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/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/SpringFoxConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java
index 1a5fd4f..193c18b 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/config/WebSecurityConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java
index 2b2f118..4d30bff 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/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/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
index 5c415dd..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.queueDeviceUpdate(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
new file mode 100644
index 0000000..57e1ca9
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java
@@ -0,0 +1,75 @@
+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.*;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
+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;
+
+ @Autowired private ThermostatService thermostatService;
+
+ @GetMapping
+ public List findAll(Principal user) {
+ return thermostatService.findAll(user.getName());
+ }
+
+ @GetMapping("/{id}")
+ 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.setId(t.getId());
+ newT.setName(t.getName());
+ newT.setRoomId(t.getRoomId());
+ newT.setUseExternalSensors(t.isUseExternalSensors());
+
+ if (t.isTurnOn()) {
+ newT.setState(Thermostat.ThermostatState.IDLE);
+ thermostatService.computeState(newT);
+ } else {
+ newT.setState(Thermostat.ThermostatState.OFF);
+ }
+
+ newT = thermostatRepository.save(newT);
+ thermostatService.populateMeasuredTemperature(newT);
+ return 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..5ac3402
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatSaveRequest.java
@@ -0,0 +1,75 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+
+import java.math.BigDecimal;
+import javax.validation.constraints.NotNull;
+
+public class ThermostatSaveRequest {
+
+ /** 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;
+
+ @NotNull private boolean useExternalSensors;
+
+ /** State of this thermostat */
+ @NotNull private boolean turnOn;
+
+ public boolean isTurnOn() {
+ return turnOn;
+ }
+
+ public void setTurnOn(boolean turnOn) {
+ this.turnOn = turnOn;
+ }
+
+ public boolean isUseExternalSensors() {
+ return useExternalSensors;
+ }
+
+ public void setUseExternalSensors(boolean useExternalSensors) {
+ this.useExternalSensors = useExternalSensors;
+ }
+
+ 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/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/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java
new file mode 100644
index 0000000..8524b8f
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java
@@ -0,0 +1,85 @@
+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.Transient;
+import javax.validation.constraints.NotNull;
+
+/** A thermostat capable of controlling cooling and heating. */
+@Entity
+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;
+
+ /** The temperature detected by the embedded sensor */
+ @Column(nullable = false, precision = 4, scale = 1)
+ private BigDecimal internalSensorTemperature =
+ Sensor.TYPICAL_VALUES.get(Sensor.SensorType.TEMPERATURE);
+
+ /** State of this thermostat */
+ @Column @NotNull private ThermostatState state;
+
+ @Transient private BigDecimal measuredTemperature;
+
+ @Column private boolean useExternalSensors = false;
+
+ /** Creates a thermostat with a temperature sensor and its initial OFF state */
+ public Thermostat() {
+ super("thermostat");
+ this.state = ThermostatState.OFF;
+ }
+
+ public void setState(ThermostatState state) {
+ this.state = state;
+ }
+
+ public ThermostatState getState() {
+ return this.state;
+ }
+
+ public BigDecimal getTargetTemperature() {
+ return this.targetTemperature;
+ }
+
+ public BigDecimal getInternalSensorTemperature() {
+ return internalSensorTemperature;
+ }
+
+ public boolean isUseExternalSensors() {
+ return useExternalSensors;
+ }
+
+ public BigDecimal getMeasuredTemperature() {
+ return measuredTemperature;
+ }
+
+ public void setMeasuredTemperature(BigDecimal measuredTemperature) {
+ this.measuredTemperature = measuredTemperature;
+ }
+
+ public void setTargetTemperature(BigDecimal targetTemperature) {
+ this.targetTemperature = targetTemperature;
+ }
+
+ public void setInternalSensorTemperature(BigDecimal internalSensorTemperature) {
+ this.internalSensorTemperature = internalSensorTemperature;
+ }
+
+ 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
new file mode 100644
index 0000000..896e0ad
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatRepository.java
@@ -0,0 +1,30 @@
+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
+ *
+ * @param thermostatRoomId room ID of the thermostat
+ * @return an optional big decimal, empty if none found
+ */
+ @Query(
+ "SELECT AVG(s.value) FROM Sensor s JOIN s.room r WHERE s.sensor = 'TEMPERATURE' AND r.id = ?1")
+ Optional getAverageTemperature(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 9cdb838..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,10 +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;
@@ -26,24 +26,24 @@ public class UpdateTasks {
@Autowired private SmartPlugRepository smartPlugRepository;
- @Autowired private SensorController sensorController;
+ @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() {
- StreamSupport.stream(sensorRepository.findAll().spliterator(), true)
- .forEach(
- sensor ->
- sensorController.updateValueFromSensor(
- sensor,
- Sensor.TYPICAL_VALUES
- .get(sensor.getSensor())
- .multiply(
- BigDecimal.valueOf(0.9875 + Math.random() / 40))));
+ sensorService.sensorFakeUpdate();
+ }
+
+ /** Generates fake sensor updates every two seconds with a +/- 2.5% error */
+ @Scheduled(fixedRate = 2000)
+ public void thermostatInteralSensorFakeUpdate() {
+ thermostatService.fakeUpdateAll();
}
/**
@@ -71,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/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..f3072cd
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java
@@ -0,0 +1,47 @@
+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 java.math.BigDecimal;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SensorService {
+
+ @Autowired private SensorRepository sensorRepository;
+
+ @Autowired private ThermostatService thermostatService;
+
+ @Autowired private SensorSocketEndpoint endpoint;
+
+ private void randomJitter(Sensor sensor) {
+ updateValueFromSensor(
+ sensor,
+ Sensor.TYPICAL_VALUES
+ .get(sensor.getSensor())
+ .multiply(BigDecimal.valueOf(0.975 + Math.random() / 20)));
+ }
+
+ public void sensorFakeUpdate() {
+ sensorRepository.findAll().forEach(this::randomJitter);
+ thermostatService.updateStates();
+ }
+
+ /**
+ * 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.queueDeviceUpdate(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..fca88ee
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java
@@ -0,0 +1,110 @@
+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;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils;
+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 SensorSocketEndpoint endpoint;
+
+ @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);
+ 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);
+
+ 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));
+ }
+}