From 7cfb2ffc7322f0ece96a48301d3eb8e0e375c175 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Thu, 9 Apr 2020 11:30:05 +0200 Subject: [PATCH 1/8] Added thermostat, not complete --- .../smarthut/models/Thermostat.java | 64 +++++++++++++++++++ .../smarthut/models/ThermostatRepository.java | 3 + 2 files changed, 67 insertions(+) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java new file mode 100644 index 0000000..338fb29 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -0,0 +1,64 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.math.BigDecimal; +import javax.persistence.Column; +import javax.validation.constraints.NotNull; + +/** A thermostat capable of controlling cooling and heating. */ +public class Thermostat extends InputDevice { + + enum ThermostatState { + OFF, + IDLE, + COOLING, + HEATING + } + + @Column @NotNull private BigDecimal targetTemperature; + + @Column @NotNull BigDecimal averageTemperature; + + @Column @NotNull private final Sensor temperatureSensor; + + @Column @NotNull private ThermostatState state; + + /** Creates a thermostat with a temperature sensor and its initial OFF state */ + public Thermostat() { + super("thermostat"); + this.temperatureSensor = new Sensor(); + this.temperatureSensor.setSensor(Sensor.SensorType.TEMPERATURE); + this.state = ThermostatState.OFF; + } + + /** Setter method for the thermostat state */ + public void setState(ThermostatState state) { + this.state = state; + } + + /** + * Sets the target temperature to be reached. Changes the thermostat state accordingly and waits + * until such temperature is reached by the embedded sensor to become idle again. + * + * @param targetTemperature - the temperature to be reached by the thermostat + */ + public void setTargetTemperature(BigDecimal targetTemperature) { + if (this.state == ThermostatState.OFF) { + this.state = ThermostatState.IDLE; + } + + this.targetTemperature = targetTemperature; + BigDecimal actualTemperature = this.temperatureSensor.getValue(); + + if (actualTemperature.compareTo(targetTemperature) == -1) { + this.setState(ThermostatState.HEATING); + } else { + this.setState(ThermostatState.COOLING); + } + + while (!(this.temperatureSensor.getValue().equals(this.targetTemperature))) { + /** Do nothing, wait for the target temperature to be reached */ + } + + this.setState(ThermostatState.IDLE); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java new file mode 100644 index 0000000..a9c45f1 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface ThermostatRepository extends DeviceRepository {} From 7bda571a2740333749ef5b7649dfc700f9447819 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Thu, 9 Apr 2020 15:25:34 +0200 Subject: [PATCH 2/8] thermostat in an entity now --- .../usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index 338fb29..04606aa 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -2,9 +2,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.math.BigDecimal; import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.OneToOne; import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ +@Entity public class Thermostat extends InputDevice { enum ThermostatState { @@ -18,7 +21,7 @@ public class Thermostat extends InputDevice { @Column @NotNull BigDecimal averageTemperature; - @Column @NotNull private final Sensor temperatureSensor; + @Column @NotNull @OneToOne private final Sensor temperatureSensor; @Column @NotNull private ThermostatState state; From 0b1170404d1ea5d43c2810c4acbf6154eed0accd Mon Sep 17 00:00:00 2001 From: tommi27 Date: Mon, 13 Apr 2020 15:36:29 +0200 Subject: [PATCH 3/8] almost finished thermostat --- .../controller/ThermostatController.java | 64 +++++++++++++ .../smarthut/dto/ThermostatSaveRequest.java | 96 +++++++++++++++++++ .../smarthut/models/Thermostat.java | 38 +++++++- 3 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java new file mode 100644 index 0000000..c29e92f --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -0,0 +1,64 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; + +import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ThermostatSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import java.security.Principal; +import java.util.*; +import java.util.List; +import javax.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.*; +import org.springframework.web.bind.annotation.*; + +@RestController +@EnableAutoConfiguration +@RequestMapping("/thermostat") +public class ThermostatController { + + @Autowired private ThermostatRepository thermostatRepository; + + @GetMapping + public List findAll() { + return toList(thermostatRepository.findAll()); + } + + @GetMapping("/{id}") + public Thermostat findById(@PathVariable("id") long id) throws NotFoundException { + return thermostatRepository.findById(id).orElseThrow(NotFoundException::new); + } + + private Thermostat save(Thermostat newT, ThermostatSaveRequest t) { + newT.setTargetTemperature(t.getTargetTemperature()); + newT.setState(t.getState()); + newT.setAverageTemperature(t.getAverageTemperature()); + newT.setTargetTemperature(t.getTargetTemperature()); + newT.setId(t.getId()); + newT.setName(t.getName()); + newT.setRoomId(t.getRoomId()); + + return thermostatRepository.save(newT); + } + + @PostMapping + public Thermostat create(@Valid @RequestBody ThermostatSaveRequest t) { + return save(new Thermostat(), t); + } + + @PutMapping + public Thermostat update(@Valid @RequestBody ThermostatSaveRequest t, final Principal principal) + throws NotFoundException { + return save( + thermostatRepository + .findByIdAndUsername(t.getId(), principal.getName()) + .orElseThrow(NotFoundException::new), + t); + } + + @DeleteMapping("/{id}") + public void deleteById(@PathVariable("id") long id) { + thermostatRepository.deleteById(id); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java new file mode 100644 index 0000000..0fac272 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java @@ -0,0 +1,96 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; +import java.math.BigDecimal; +import javax.validation.constraints.NotNull; + +public class ThermostatSaveRequest { + + public enum ThermostatState { + OFF, + IDLE, + COOLING, + HEATING + } + + /** Device identifier */ + private long id; + + /** + * The room this device belongs in, as a foreign key id. To use when updating and inserting from + * a REST call. + */ + @NotNull private Long roomId; + + /** The name of the device as assigned by the user (e.g. 'Master bedroom light') */ + @NotNull private String name; + + /** Temperature to be reached */ + @NotNull private BigDecimal targetTemperature; + + /** Average room temperature given by all the temperature sensors in the room */ + @NotNull BigDecimal averageTemperature; + + /** Embedded temperature sensor */ + @NotNull private Sensor temperatureSensor; + + /** State of this thermostat */ + @NotNull private Thermostat.ThermostatState state; + + public void setState(Thermostat.ThermostatState state) { + this.state = state; + } + + public Thermostat.ThermostatState getState() { + return this.state; + } + + public void setAverageTemperature(BigDecimal averageTemperature) { + this.averageTemperature = averageTemperature; + } + + public BigDecimal getAverageTemperature() { + return this.averageTemperature; + } + + public Sensor getTemperatureSensor() { + return this.temperatureSensor; + } + + public void setTemperatureSensor(Sensor temperatureSensor) { + this.temperatureSensor = temperatureSensor; + } + + public BigDecimal getTargetTemperature() { + return this.targetTemperature; + } + + public void setTargetTemperature(BigDecimal targetTemperature) { + this.targetTemperature = targetTemperature; + } + + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + + public void setName(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public Long getRoomId() { + return roomId; + } + + public String getName() { + return name; + } + + public void setId(long id) { + this.id = id; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index 04606aa..6835646 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -10,19 +10,23 @@ import javax.validation.constraints.NotNull; @Entity public class Thermostat extends InputDevice { - enum ThermostatState { + public enum ThermostatState { OFF, IDLE, COOLING, HEATING } + /** Temperature to be reached */ @Column @NotNull private BigDecimal targetTemperature; + /** Average room temperature given by all the temperature sensors in the room */ @Column @NotNull BigDecimal averageTemperature; + /** Embedded temperature sensor */ @Column @NotNull @OneToOne private final Sensor temperatureSensor; + /** State of this thermostat */ @Column @NotNull private ThermostatState state; /** Creates a thermostat with a temperature sensor and its initial OFF state */ @@ -33,11 +37,39 @@ public class Thermostat extends InputDevice { this.state = ThermostatState.OFF; } - /** Setter method for the thermostat state */ public void setState(ThermostatState state) { this.state = state; } + public ThermostatState getState() { + return this.state; + } + + public void setAverageTemperature(BigDecimal averageTemperature) { + this.averageTemperature = averageTemperature; + } + + public BigDecimal getAverageTemperature() { + return this.averageTemperature; + } + + public Sensor getTemperatureSensor() { + return this.temperatureSensor; + } + + public BigDecimal getTargetTemperature() { + return this.targetTemperature; + } + + /** + * Takes all of the temperature sensors in the room inculding its own embedded sensor and set + * this average temperature to the average of all the temperatures registered. + */ + public void calcAverageTemperature() { + // TODO: write actual method body + BigDecimal average = new BigDecimal(0); + } + /** * Sets the target temperature to be reached. Changes the thermostat state accordingly and waits * until such temperature is reached by the embedded sensor to become idle again. @@ -46,7 +78,7 @@ public class Thermostat extends InputDevice { */ public void setTargetTemperature(BigDecimal targetTemperature) { if (this.state == ThermostatState.OFF) { - this.state = ThermostatState.IDLE; + this.setState(ThermostatState.IDLE); } this.targetTemperature = targetTemperature; From 4c4297dfdf99da94418bf9723e4f83e4729e96e2 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Mon, 13 Apr 2020 16:42:48 +0200 Subject: [PATCH 4/8] wip, to fix --- .../controller/ThermostatController.java | 12 ++++- .../smarthut/dto/ThermostatSaveRequest.java | 11 ---- .../smarthut/models/Thermostat.java | 51 ++++++++----------- .../smarthut/models/ThermostatRepository.java | 26 +++++++++- 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index c29e92f..0ab66ff 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -8,6 +8,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.*; import java.util.List; +import java.util.stream.StreamSupport; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; @@ -22,7 +23,15 @@ public class ThermostatController { @GetMapping public List findAll() { - return toList(thermostatRepository.findAll()); + Iterable thermostats = thermostatRepository.findAll(); + StreamSupport.stream(thermostats.spliterator(), false) + .forEach( + s -> + s.setExternalSensorsAvailable( + thermostatRepository.getTemperatureSensorCount( + s.getRoomId()) + > 0)); + return toList(thermostats); } @GetMapping("/{id}") @@ -33,7 +42,6 @@ public class ThermostatController { private Thermostat save(Thermostat newT, ThermostatSaveRequest t) { newT.setTargetTemperature(t.getTargetTemperature()); newT.setState(t.getState()); - newT.setAverageTemperature(t.getAverageTemperature()); newT.setTargetTemperature(t.getTargetTemperature()); newT.setId(t.getId()); newT.setName(t.getName()); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java index 0fac272..b897a92 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java @@ -29,9 +29,6 @@ public class ThermostatSaveRequest { /** Temperature to be reached */ @NotNull private BigDecimal targetTemperature; - /** Average room temperature given by all the temperature sensors in the room */ - @NotNull BigDecimal averageTemperature; - /** Embedded temperature sensor */ @NotNull private Sensor temperatureSensor; @@ -46,14 +43,6 @@ public class ThermostatSaveRequest { return this.state; } - public void setAverageTemperature(BigDecimal averageTemperature) { - this.averageTemperature = averageTemperature; - } - - public BigDecimal getAverageTemperature() { - return this.averageTemperature; - } - public Sensor getTemperatureSensor() { return this.temperatureSensor; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index 6835646..e9d4375 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -1,39 +1,45 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +import com.google.gson.annotations.SerializedName; import java.math.BigDecimal; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.OneToOne; +import javax.persistence.Transient; import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ @Entity -public class Thermostat extends InputDevice { +public class Thermostat extends OutputDevice { public enum ThermostatState { + @SerializedName("OFF") OFF, + @SerializedName("IDLE") IDLE, + @SerializedName("COOLING") COOLING, + @SerializedName("HEATING") HEATING } /** Temperature to be reached */ @Column @NotNull private BigDecimal targetTemperature; - /** Average room temperature given by all the temperature sensors in the room */ - @Column @NotNull BigDecimal averageTemperature; - - /** Embedded temperature sensor */ - @Column @NotNull @OneToOne private final Sensor temperatureSensor; + /** The temperature detected by the embedded sensor */ + @Column(nullable = false, precision = 4, scale = 1) + private BigDecimal sensorTemperature; /** State of this thermostat */ @Column @NotNull private ThermostatState state; + @Column boolean useInternalSensor = true; + + /** True if there are any other sensors in the room */ + @Transient boolean externalSensorsAvaliable; + /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { super("thermostat"); - this.temperatureSensor = new Sensor(); - this.temperatureSensor.setSensor(Sensor.SensorType.TEMPERATURE); this.state = ThermostatState.OFF; } @@ -45,29 +51,12 @@ public class Thermostat extends InputDevice { return this.state; } - public void setAverageTemperature(BigDecimal averageTemperature) { - this.averageTemperature = averageTemperature; - } - - public BigDecimal getAverageTemperature() { - return this.averageTemperature; - } - - public Sensor getTemperatureSensor() { - return this.temperatureSensor; - } - public BigDecimal getTargetTemperature() { return this.targetTemperature; } - /** - * Takes all of the temperature sensors in the room inculding its own embedded sensor and set - * this average temperature to the average of all the temperatures registered. - */ - public void calcAverageTemperature() { - // TODO: write actual method body - BigDecimal average = new BigDecimal(0); + public void setExternalSensorsAvailable(boolean externalSensorsAvaliable) { + this.externalSensorsAvaliable = externalSensorsAvaliable; } /** @@ -76,7 +65,7 @@ public class Thermostat extends InputDevice { * * @param targetTemperature - the temperature to be reached by the thermostat */ - public void setTargetTemperature(BigDecimal targetTemperature) { + /*public void setTargetTemperature(BigDecimal targetTemperature) { if (this.state == ThermostatState.OFF) { this.setState(ThermostatState.IDLE); } @@ -91,9 +80,9 @@ public class Thermostat extends InputDevice { } while (!(this.temperatureSensor.getValue().equals(this.targetTemperature))) { - /** Do nothing, wait for the target temperature to be reached */ + // Do nothing, wait for the target temperature to be reached } this.setState(ThermostatState.IDLE); - } + }*/ } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java index a9c45f1..186276c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java @@ -1,3 +1,27 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -public interface ThermostatRepository extends DeviceRepository {} +import java.math.BigDecimal; +import java.util.Optional; +import org.springframework.data.jpa.repository.Query; + +public interface ThermostatRepository extends DeviceRepository { + /** + * Computes the average temperature of all temperature sensors in the room + * + * @param thermostatRoomId room ID of the thermostat + * @return an optional big decimal, empty if none found + */ + @Query( + "SELECT AVG(s.temperature) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1") + Optional getAverageTemperature(Long thermostatRoomId); + + /** + * Computes the average temperature of all temperature sensors in the room + * + * @param thermostatRoomId room ID of the thermostat + * @return an optional big decimal, empty if none found + */ + @Query( + "SELECT COUNT(*) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1") + Integer getTemperatureSensorCount(Long thermostatRoomId); +} From 8d53bee294798f585cade74fac048ba875980c06 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 14 Apr 2020 13:24:36 +0200 Subject: [PATCH 5/8] WIP on average temperature computation --- .../smarthut/config/JWTRequestFilter.java | 2 +- .../smarthut/config/WebSecurityConfig.java | 2 +- .../controller/AuthenticationController.java | 2 + .../smarthut/controller/SensorController.java | 30 ++++------- .../controller/ThermostatController.java | 24 ++++----- .../smarthut/dto/ThermostatSaveRequest.java | 11 ++-- .../smarthut/models/Thermostat.java | 27 +++++++--- .../smarthut/models/ThermostatRepository.java | 12 +---- .../smarthut/scheduled/UpdateTasks.java | 14 ++--- .../EmailSenderService.java | 0 .../JWTUserDetailsService.java | 5 +- .../smarthut/service/SensorService.java | 52 ++++++++++++++++++ .../smarthut/service/ThermostatService.java | 54 +++++++++++++++++++ 13 files changed, 165 insertions(+), 70 deletions(-) rename src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/{Service => service}/EmailSenderService.java (100%) rename src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/{models => service}/JWTUserDetailsService.java (85%) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java index e0cbb6a..503f7cd 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java @@ -1,6 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.config; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.JWTUserDetailsService; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.JWTUserDetailsService; import io.jsonwebtoken.ExpiredJwtException; import java.io.IOException; import javax.servlet.FilterChain; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java index ec116c3..3789414 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java @@ -1,6 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.config; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.JWTUserDetailsService; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.JWTUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java index ad48da2..f806f01 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java @@ -8,6 +8,8 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UserNotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import javax.validation.Valid; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.JWTUserDetailsService; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java index ee1be81..b56fd60 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java @@ -5,12 +5,15 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; + import java.math.BigDecimal; import java.security.Principal; import java.util.*; import java.util.List; import javax.validation.Valid; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; import org.springframework.web.bind.annotation.*; @@ -20,9 +23,14 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/sensor") public class SensorController { - @Autowired private SensorRepository sensorRepository; + @Autowired + private SensorRepository sensorRepository; - @Autowired private SensorSocketEndpoint sensorSocketEndpoint; + @Autowired + private SensorSocketEndpoint sensorSocketEndpoint; + + @Autowired + private SensorService sensorService; @GetMapping public List findAll() { @@ -45,29 +53,13 @@ public class SensorController { return sensorRepository.save(newSensor); } - /** - * Updates the sensor with new measurement and propagates update through websocket - * - * @param sensor the sensor to update - * @param value the new measurement - * @return the updated sensor - */ - public Sensor updateValueFromSensor(Sensor sensor, BigDecimal value) { - sensor.setValue(value); - final Sensor toReturn = sensorRepository.save(sensor); - - sensorSocketEndpoint.broadcast(sensor, sensorRepository.findUser(sensor.getId())); - - return toReturn; - } - @PutMapping("/{id}/value") public Sensor updateValue( @PathVariable("id") Long sensorId, @RequestParam("value") BigDecimal value, final Principal principal) throws NotFoundException { - return updateValueFromSensor( + return sensorService.updateValueFromSensor( sensorRepository .findByIdAndUsername(sensorId, principal.getName()) .orElseThrow(NotFoundException::new), diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 0ab66ff..4fc472a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -10,6 +10,8 @@ import java.util.*; import java.util.List; import java.util.stream.StreamSupport; import javax.validation.Valid; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; import org.springframework.web.bind.annotation.*; @@ -21,22 +23,16 @@ public class ThermostatController { @Autowired private ThermostatRepository thermostatRepository; + @Autowired private ThermostatService thermostatService; + @GetMapping - public List findAll() { - Iterable thermostats = thermostatRepository.findAll(); - StreamSupport.stream(thermostats.spliterator(), false) - .forEach( - s -> - s.setExternalSensorsAvailable( - thermostatRepository.getTemperatureSensorCount( - s.getRoomId()) - > 0)); - return toList(thermostats); + public List findAll(Principal user) { + return thermostatService.findAll(user.getName()); } @GetMapping("/{id}") - public Thermostat findById(@PathVariable("id") long id) throws NotFoundException { - return thermostatRepository.findById(id).orElseThrow(NotFoundException::new); + public Thermostat findById(@PathVariable("id") long id, Principal principal) throws NotFoundException { + return thermostatService.findById(id, principal.getName()).orElseThrow(NotFoundException::new); } private Thermostat save(Thermostat newT, ThermostatSaveRequest t) { @@ -47,7 +43,9 @@ public class ThermostatController { newT.setName(t.getName()); newT.setRoomId(t.getRoomId()); - return thermostatRepository.save(newT); + newT = thermostatRepository.save(newT); + thermostatService.populateMeasuredTemperature(newT); + return newT; } @PostMapping diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java index b897a92..6a541ba 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java @@ -29,8 +29,7 @@ public class ThermostatSaveRequest { /** Temperature to be reached */ @NotNull private BigDecimal targetTemperature; - /** Embedded temperature sensor */ - @NotNull private Sensor temperatureSensor; + @NotNull private boolean useExternalSensors; /** State of this thermostat */ @NotNull private Thermostat.ThermostatState state; @@ -43,12 +42,12 @@ public class ThermostatSaveRequest { return this.state; } - public Sensor getTemperatureSensor() { - return this.temperatureSensor; + public boolean isUseExternalSensors() { + return useExternalSensors; } - public void setTemperatureSensor(Sensor temperatureSensor) { - this.temperatureSensor = temperatureSensor; + public void setUseExternalSensors(boolean useExternalSensors) { + this.useExternalSensors = useExternalSensors; } public BigDecimal getTargetTemperature() { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index e9d4375..f5d45ac 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -1,6 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import com.google.gson.annotations.SerializedName; + import java.math.BigDecimal; import javax.persistence.Column; import javax.persistence.Entity; @@ -27,15 +28,15 @@ public class Thermostat extends OutputDevice { /** The temperature detected by the embedded sensor */ @Column(nullable = false, precision = 4, scale = 1) - private BigDecimal sensorTemperature; + private BigDecimal internalSensorTemperature; /** State of this thermostat */ @Column @NotNull private ThermostatState state; - @Column boolean useInternalSensor = true; + @Transient + private BigDecimal measuredTemperature; - /** True if there are any other sensors in the room */ - @Transient boolean externalSensorsAvaliable; + @Column boolean useExternalSensors = false; /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { @@ -55,11 +56,23 @@ public class Thermostat extends OutputDevice { return this.targetTemperature; } - public void setExternalSensorsAvailable(boolean externalSensorsAvaliable) { - this.externalSensorsAvaliable = externalSensorsAvaliable; + public BigDecimal getInternalSensorTemperature() { + return internalSensorTemperature; } - /** + public boolean isUseExternalSensors() { + return useExternalSensors; + } + + public void setMeasuredTemperature(BigDecimal measuredTemperature) { + this.measuredTemperature = measuredTemperature; + } + + public void setTargetTemperature(BigDecimal targetTemperature) { + this.targetTemperature = targetTemperature; + } + + /* * Sets the target temperature to be reached. Changes the thermostat state accordingly and waits * until such temperature is reached by the embedded sensor to become idle again. * diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java index 186276c..5f673c0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java @@ -12,16 +12,6 @@ public interface ThermostatRepository extends DeviceRepository { * @return an optional big decimal, empty if none found */ @Query( - "SELECT AVG(s.temperature) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1") + "SELECT AVG(s.value) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1") Optional getAverageTemperature(Long thermostatRoomId); - - /** - * Computes the average temperature of all temperature sensors in the room - * - * @param thermostatRoomId room ID of the thermostat - * @return an optional big decimal, empty if none found - */ - @Query( - "SELECT COUNT(*) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1") - Integer getTemperatureSensorCount(Long thermostatRoomId); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java index 932db5c..0f4bea5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java @@ -3,6 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled; import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.MotionSensorController; import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.SensorController; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import java.math.BigDecimal; import java.util.Collection; @@ -26,7 +27,7 @@ public class UpdateTasks { @Autowired private SmartPlugRepository smartPlugRepository; - @Autowired private SensorController sensorController; + @Autowired private SensorService sensorService; @Autowired private MotionSensorController motionSensorController; @@ -35,16 +36,7 @@ public class UpdateTasks { /** Generates fake sensor updates every two seconds with a +/- 1.25% error */ @Scheduled(fixedRate = 2000) public void sensorFakeUpdate() { - StreamSupport.stream(sensorRepository.findAll().spliterator(), true) - .forEach( - sensor -> - sensorController.updateValueFromSensor( - sensor, - Sensor.TYPICAL_VALUES - .get(sensor.getSensor()) - .multiply( - new BigDecimal( - 0.9875 + Math.random() / 40)))); + sensorService.sensorFakeUpdate(); } /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/Service/EmailSenderService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/EmailSenderService.java similarity index 100% rename from src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/Service/EmailSenderService.java rename to src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/EmailSenderService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/JWTUserDetailsService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/JWTUserDetailsService.java similarity index 85% rename from src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/JWTUserDetailsService.java rename to src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/JWTUserDetailsService.java index 06ee415..7dff142 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/JWTUserDetailsService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/JWTUserDetailsService.java @@ -1,6 +1,9 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; import java.util.Set; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.*; import org.springframework.security.core.userdetails.UserDetails; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java new file mode 100644 index 0000000..b9c8fae --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java @@ -0,0 +1,52 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.stream.StreamSupport; + +@Component +public class SensorService { + + @Autowired + private SensorRepository sensorRepository; + + @Autowired + private SensorSocketEndpoint endpoint; + + public void sensorFakeUpdate() { + StreamSupport.stream(sensorRepository.findAll().spliterator(), true) + .forEach( + sensor -> + updateValueFromSensor( + sensor, + Sensor.TYPICAL_VALUES + .get(sensor.getSensor()) + .multiply( + BigDecimal.valueOf(0.9875 + Math.random() / 40)))); + } + + public void temperatureSensorFakeUpdate() { + + } + + /** + * Updates the sensor with new measurement and propagates update through websocket + * + * @param sensor the sensor to update + * @param value the new measurement + * @return the updated sensor + */ + public Sensor updateValueFromSensor(Sensor sensor, BigDecimal value) { + sensor.setValue(value); + final Sensor toReturn = sensorRepository.save(sensor); + + endpoint.broadcast(sensor, sensorRepository.findUser(sensor.getId())); + + return toReturn; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java new file mode 100644 index 0000000..ab9be80 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -0,0 +1,54 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; + +@Component +public class ThermostatService { + + @Autowired private SensorRepository sensorRepository; + + @Autowired private ThermostatRepository thermostatRepository; + + public List findAll(String username) { + Iterable all = thermostatRepository.findAllByUsername(username); + all.forEach(this::populateMeasuredTemperature); + return Utils.toList(all); + } + + public Optional findById(Long thermostat, String username) { + Optional t = thermostatRepository.findByIdAndUsername(thermostat, username); + + if (t.isPresent()) { + Thermostat u = t.get(); + populateMeasuredTemperature(u); + t = Optional.of(u); + } + + return t; + } + + private BigDecimal measureTemperature(final Thermostat thermostat) { + Optional average; + + if (thermostat.isUseExternalSensors()) { + average = thermostatRepository.getAverageTemperature(thermostat.getRoomId()); + } else { + return thermostat.getInternalSensorTemperature(); + } + + return average.orElse(null); + } + + public void populateMeasuredTemperature(Thermostat thermostat) { + thermostat.setMeasuredTemperature(measureTemperature(thermostat)); + } +} From 44321fe153c5b99b13134616ce2ff2e6c2fd951d Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Wed, 15 Apr 2020 14:10:40 +0200 Subject: [PATCH 6/8] wip --- .../smarthut/models/SensorRepository.java | 6 +++- .../smarthut/service/SensorService.java | 33 ++++++++++++------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SensorRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SensorRepository.java index b796277..dd040e8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SensorRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SensorRepository.java @@ -1,3 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -public interface SensorRepository extends DeviceRepository {} +import java.util.List; + +public interface SensorRepository extends DeviceRepository { + List findAllBySensor(Sensor.SensorType sensor); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java index cc1224a..b68af12 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java @@ -2,11 +2,14 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; +import java.util.List; import java.util.stream.StreamSupport; @Component @@ -15,23 +18,31 @@ public class SensorService { @Autowired private SensorRepository sensorRepository; + @Autowired + private ThermostatRepository thermostatRepository; + @Autowired private SensorSocketEndpoint endpoint; - public void sensorFakeUpdate() { - StreamSupport.stream(sensorRepository.findAll().spliterator(), true) - .forEach( - sensor -> - updateValueFromSensor( - sensor, - Sensor.TYPICAL_VALUES - .get(sensor.getSensor()) - .multiply( - BigDecimal.valueOf(0.9875 + Math.random() / 40)))); + private void randomJitter(Sensor sensor) { + updateValueFromSensor( + sensor, + Sensor.TYPICAL_VALUES + .get(sensor.getSensor()) + .multiply( + BigDecimal.valueOf(0.9875 + Math.random() / 40))); } - public void temperatureSensorFakeUpdate() { + public void sensorFakeUpdate() { + sensorRepository.findAllBySensor(Sensor.SensorType.HUMIDITY).forEach(this::randomJitter); + sensorRepository.findAllBySensor(Sensor.SensorType.LIGHT).forEach(this::randomJitter); + temperatureSensorFakeUpdate(sensorRepository.findAllBySensor(Sensor.SensorType.HUMIDITY)); + } + public void temperatureSensorFakeUpdate(List temperatureSensors) { + for (Sensor temperature : temperatureSensors) { + //Thermostat t = thermostatRepository.findByRoomId() + } } /** From 0e924c088bba193e235dc873146983954da99214 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Wed, 15 Apr 2020 15:10:02 +0200 Subject: [PATCH 7/8] thermostat should be finished --- .../smarthut/controller/RoomController.java | 11 ++++- .../controller/ThermostatController.java | 21 +++++---- .../smarthut/models/Thermostat.java | 8 ++-- .../smarthut/service/SensorService.java | 36 ++++---------- .../smarthut/service/ThermostatService.java | 47 +++++++++++++++++-- 5 files changed, 80 insertions(+), 43 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 2bfa440..9474fd4 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -5,6 +5,7 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.RoomSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import java.security.Principal; import java.util.*; import javax.validation.Valid; @@ -29,6 +30,8 @@ public class RoomController { @Autowired private KnobDimmerRepository knobDimmerRepository; + @Autowired private ThermostatService thermostatService; + @GetMapping public List findAll() { return toList(roomRepository.findAll()); @@ -99,6 +102,12 @@ public class RoomController { */ @GetMapping(path = "/{roomId}/devices") public List getDevices(@PathVariable("roomId") long roomid) { - return deviceRepository.findByRoomId(roomid); + Iterable devices = deviceRepository.findByRoomId(roomid); + for (Device d : devices) { + if (d instanceof Thermostat) { + thermostatService.populateMeasuredTemperature((Thermostat) d); + } + } + return toList(devices); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 4fc472a..063801e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -1,17 +1,14 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; -import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ThermostatSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import java.security.Principal; import java.util.*; import java.util.List; -import java.util.stream.StreamSupport; import javax.validation.Valid; - -import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; import org.springframework.web.bind.annotation.*; @@ -31,18 +28,26 @@ public class ThermostatController { } @GetMapping("/{id}") - public Thermostat findById(@PathVariable("id") long id, Principal principal) throws NotFoundException { - return thermostatService.findById(id, principal.getName()).orElseThrow(NotFoundException::new); + public Thermostat findById(@PathVariable("id") long id, Principal principal) + throws NotFoundException { + return thermostatService + .findById(id, principal.getName()) + .orElseThrow(NotFoundException::new); } private Thermostat save(Thermostat newT, ThermostatSaveRequest t) { - newT.setTargetTemperature(t.getTargetTemperature()); - newT.setState(t.getState()); newT.setTargetTemperature(t.getTargetTemperature()); newT.setId(t.getId()); newT.setName(t.getName()); newT.setRoomId(t.getRoomId()); + if (newT.getState() == Thermostat.ThermostatState.OFF + && t.getState() != Thermostat.ThermostatState.OFF) { + thermostatService.computeState(newT); + } else { + newT.setState(t.getState()); + } + newT = thermostatRepository.save(newT); thermostatService.populateMeasuredTemperature(newT); return newT; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index f5d45ac..bc762fd 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -1,7 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import com.google.gson.annotations.SerializedName; - import java.math.BigDecimal; import javax.persistence.Column; import javax.persistence.Entity; @@ -33,8 +32,7 @@ public class Thermostat extends OutputDevice { /** State of this thermostat */ @Column @NotNull private ThermostatState state; - @Transient - private BigDecimal measuredTemperature; + @Transient private BigDecimal measuredTemperature; @Column boolean useExternalSensors = false; @@ -64,6 +62,10 @@ public class Thermostat extends OutputDevice { return useExternalSensors; } + public BigDecimal getMeasuredTemperature() { + return measuredTemperature; + } + public void setMeasuredTemperature(BigDecimal measuredTemperature) { this.measuredTemperature = measuredTemperature; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java index b68af12..f3072cd 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java @@ -2,47 +2,31 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import java.math.BigDecimal; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.math.BigDecimal; -import java.util.List; -import java.util.stream.StreamSupport; - @Component public class SensorService { - @Autowired - private SensorRepository sensorRepository; + @Autowired private SensorRepository sensorRepository; - @Autowired - private ThermostatRepository thermostatRepository; + @Autowired private ThermostatService thermostatService; - @Autowired - private SensorSocketEndpoint endpoint; + @Autowired private SensorSocketEndpoint endpoint; private void randomJitter(Sensor sensor) { updateValueFromSensor( - sensor, - Sensor.TYPICAL_VALUES - .get(sensor.getSensor()) - .multiply( - BigDecimal.valueOf(0.9875 + Math.random() / 40))); + sensor, + Sensor.TYPICAL_VALUES + .get(sensor.getSensor()) + .multiply(BigDecimal.valueOf(0.975 + Math.random() / 20))); } public void sensorFakeUpdate() { - sensorRepository.findAllBySensor(Sensor.SensorType.HUMIDITY).forEach(this::randomJitter); - sensorRepository.findAllBySensor(Sensor.SensorType.LIGHT).forEach(this::randomJitter); - temperatureSensorFakeUpdate(sensorRepository.findAllBySensor(Sensor.SensorType.HUMIDITY)); - } - - public void temperatureSensorFakeUpdate(List temperatureSensors) { - for (Sensor temperature : temperatureSensors) { - //Thermostat t = thermostatRepository.findByRoomId() - } + sensorRepository.findAll().forEach(this::randomJitter); + thermostatService.updateStates(); } /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java index ab9be80..9bd41de 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -1,20 +1,19 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.math.BigDecimal; import java.util.List; import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class ThermostatService { - @Autowired private SensorRepository sensorRepository; + @Autowired private SensorSocketEndpoint endpoint; @Autowired private ThermostatRepository thermostatRepository; @@ -24,6 +23,44 @@ public class ThermostatService { return Utils.toList(all); } + public boolean computeState(Thermostat t) { + if (t.getState() == Thermostat.ThermostatState.OFF) { + return false; + } + + populateMeasuredTemperature(t); + BigDecimal measured = t.getMeasuredTemperature(); + BigDecimal target = t.getTargetTemperature(); + BigDecimal delta = target.subtract(measured); + + if (delta.abs().doubleValue() < 0.25) { + if (t.getState() == Thermostat.ThermostatState.IDLE) return false; + t.setState(Thermostat.ThermostatState.IDLE); + } else if (delta.signum() > 0) { + if (t.getState() == Thermostat.ThermostatState.HEATING) return false; + t.setState(Thermostat.ThermostatState.HEATING); + } else { + if (t.getState() == Thermostat.ThermostatState.COOLING) return false; + t.setState(Thermostat.ThermostatState.COOLING); + } + + return true; + } + + private void updateState(Thermostat t) { + boolean shouldUpdate = this.computeState(t); + + if (shouldUpdate) { + thermostatRepository.save(t); + endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId())); + } + } + + public void updateStates() { + Iterable ts = thermostatRepository.findAll(); + ts.forEach(this::updateState); + } + public Optional findById(Long thermostat, String username) { Optional t = thermostatRepository.findByIdAndUsername(thermostat, username); From 646672e3db85a0fbb2258bcfe6e803741be695ab Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Wed, 15 Apr 2020 17:55:04 +0200 Subject: [PATCH 8/8] Code review for Thermostat --- socket_test.html | 4 ++- .../smarthut/config/SpringFoxConfig.java | 1 + .../controller/ThermostatController.java | 8 ++--- .../smarthut/dto/ThermostatSaveRequest.java | 19 +++------- .../smarthut/models/Thermostat.java | 36 +++++-------------- .../smarthut/models/ThermostatRepository.java | 13 +++++++ .../smarthut/scheduled/UpdateTasks.java | 18 +++++++--- .../smarthut/service/ThermostatService.java | 19 ++++++++++ 8 files changed, 68 insertions(+), 50 deletions(-) diff --git a/socket_test.html b/socket_test.html index 91399e5..776248d 100644 --- a/socket_test.html +++ b/socket_test.html @@ -29,8 +29,10 @@ connection.onopen = function(evt) { connection.onmessage = function(evt) { console.log("***ONMESSAGE", evt); let data = JSON.parse(evt.data); + let a = document.getElementById("giovanni"); + if (a) a.remove(); - malusa.innerHTML += "

" + JSON.stringify(JSON.parse(evt.data), null, 2) + "

"; + malusa.innerHTML += "
" + JSON.stringify(JSON.parse(evt.data), null, 2) + "
"; }; connection.onerror = function(evt) { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java index 971a7fb..09c7bdd 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java @@ -68,6 +68,7 @@ public class SpringFoxConfig { .or(PathSelectors.regex("/room.*")::apply) .or(PathSelectors.regex("/device.*")::apply) .or(PathSelectors.regex("/buttonDimmer.*")::apply) + .or(PathSelectors.regex("/thermostat.*")::apply) .or(PathSelectors.regex("/dimmableLight.*")::apply) .or(PathSelectors.regex("/knobDimmer.*")::apply) .or(PathSelectors.regex("/regularLight.*")::apply) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 063801e..57e1ca9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ThermostatSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; @@ -40,12 +39,13 @@ public class ThermostatController { newT.setId(t.getId()); newT.setName(t.getName()); newT.setRoomId(t.getRoomId()); + newT.setUseExternalSensors(t.isUseExternalSensors()); - if (newT.getState() == Thermostat.ThermostatState.OFF - && t.getState() != Thermostat.ThermostatState.OFF) { + if (t.isTurnOn()) { + newT.setState(Thermostat.ThermostatState.IDLE); thermostatService.computeState(newT); } else { - newT.setState(t.getState()); + newT.setState(Thermostat.ThermostatState.OFF); } newT = thermostatRepository.save(newT); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java index 6a541ba..5ac3402 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java @@ -1,19 +1,10 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; import java.math.BigDecimal; import javax.validation.constraints.NotNull; public class ThermostatSaveRequest { - public enum ThermostatState { - OFF, - IDLE, - COOLING, - HEATING - } - /** Device identifier */ private long id; @@ -32,14 +23,14 @@ public class ThermostatSaveRequest { @NotNull private boolean useExternalSensors; /** State of this thermostat */ - @NotNull private Thermostat.ThermostatState state; + @NotNull private boolean turnOn; - public void setState(Thermostat.ThermostatState state) { - this.state = state; + public boolean isTurnOn() { + return turnOn; } - public Thermostat.ThermostatState getState() { - return this.state; + public void setTurnOn(boolean turnOn) { + this.turnOn = turnOn; } public boolean isUseExternalSensors() { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index bc762fd..8524b8f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -27,14 +27,15 @@ public class Thermostat extends OutputDevice { /** The temperature detected by the embedded sensor */ @Column(nullable = false, precision = 4, scale = 1) - private BigDecimal internalSensorTemperature; + private BigDecimal internalSensorTemperature = + Sensor.TYPICAL_VALUES.get(Sensor.SensorType.TEMPERATURE); /** State of this thermostat */ @Column @NotNull private ThermostatState state; @Transient private BigDecimal measuredTemperature; - @Column boolean useExternalSensors = false; + @Column private boolean useExternalSensors = false; /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { @@ -74,30 +75,11 @@ public class Thermostat extends OutputDevice { this.targetTemperature = targetTemperature; } - /* - * Sets the target temperature to be reached. Changes the thermostat state accordingly and waits - * until such temperature is reached by the embedded sensor to become idle again. - * - * @param targetTemperature - the temperature to be reached by the thermostat - */ - /*public void setTargetTemperature(BigDecimal targetTemperature) { - if (this.state == ThermostatState.OFF) { - this.setState(ThermostatState.IDLE); - } + public void setInternalSensorTemperature(BigDecimal internalSensorTemperature) { + this.internalSensorTemperature = internalSensorTemperature; + } - this.targetTemperature = targetTemperature; - BigDecimal actualTemperature = this.temperatureSensor.getValue(); - - if (actualTemperature.compareTo(targetTemperature) == -1) { - this.setState(ThermostatState.HEATING); - } else { - this.setState(ThermostatState.COOLING); - } - - while (!(this.temperatureSensor.getValue().equals(this.targetTemperature))) { - // Do nothing, wait for the target temperature to be reached - } - - this.setState(ThermostatState.IDLE); - }*/ + public void setUseExternalSensors(boolean useExternalSensors) { + this.useExternalSensors = useExternalSensors; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java index 5f673c0..896e0ad 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java @@ -1,10 +1,23 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.math.BigDecimal; +import java.util.List; import java.util.Optional; +import javax.transaction.Transactional; import org.springframework.data.jpa.repository.Query; public interface ThermostatRepository extends DeviceRepository { + + /** + * Finds all devices belonging to a user + * + * @param username the User's username + * @return all devices of that user + */ + @Transactional + @Query("SELECT t FROM Thermostat t JOIN t.room r JOIN r.user u WHERE u.username = ?1") + List findAllByUsername(String username); + /** * Computes the average temperature of all temperature sensors in the room * diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java index e902662..4fe293c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java @@ -1,11 +1,10 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled; import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.MotionSensorController; -import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.SensorController; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; -import java.math.BigDecimal; import java.util.Collection; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -29,16 +28,24 @@ public class UpdateTasks { @Autowired private SensorService sensorService; + @Autowired private ThermostatService thermostatService; + @Autowired private MotionSensorController motionSensorController; @Autowired private SensorSocketEndpoint sensorSocketEndpoint; - /** Generates fake sensor updates every two seconds with a +/- 1.25% error */ + /** Generates fake sensor updates every two seconds with a +/- 2.5% error */ @Scheduled(fixedRate = 2000) public void sensorFakeUpdate() { sensorService.sensorFakeUpdate(); } + /** Generates fake sensor updates every two seconds with a +/- 2.5% error */ + @Scheduled(fixedRate = 2000) + public void thermostatInteralSensorFakeUpdate() { + thermostatService.fakeUpdateAll(); + } + /** * Generate fake motion detections in all motion detectors every 20 seconds for 2 seconds at * most @@ -64,7 +71,10 @@ public class UpdateTasks { public void smartPlugConsumptionFakeUpdate() { smartPlugRepository.updateTotalConsumption(SmartPlug.AVERAGE_CONSUMPTION_KW); final Collection c = smartPlugRepository.findByOn(true); - c.forEach(s -> sensorSocketEndpoint.queueDeviceUpdate(s, sensorRepository.findUser(s.getId()))); + c.forEach( + s -> + sensorSocketEndpoint.queueDeviceUpdate( + s, sensorRepository.findUser(s.getId()))); } /** Sends device updates through sensor socket in batch every one second */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java index 9bd41de..fca88ee 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -1,5 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; @@ -17,6 +18,24 @@ public class ThermostatService { @Autowired private ThermostatRepository thermostatRepository; + private void randomJitter(Thermostat thermostat) { + updateValueForThermostat( + thermostat, + Sensor.TYPICAL_VALUES + .get(Sensor.SensorType.TEMPERATURE) + .multiply(BigDecimal.valueOf(0.975 + Math.random() / 20))); + } + + private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) { + thermostat.setInternalSensorTemperature(value); + thermostatRepository.save(thermostat); + } + + public void fakeUpdateAll() { + thermostatRepository.findAll().forEach(this::randomJitter); + updateStates(); + } + public List findAll(String username) { Iterable all = thermostatRepository.findAllByUsername(username); all.forEach(this::populateMeasuredTemperature);