WIP on average temperature computation

This commit is contained in:
Claudio Maggioni (maggicl) 2020-04-14 13:24:36 +02:00
parent 4c4297dfdf
commit 8d53bee294
13 changed files with 165 additions and 70 deletions

View file

@ -1,6 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config; 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 io.jsonwebtoken.ExpiredJwtException;
import java.io.IOException; import java.io.IOException;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;

View file

@ -1,6 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config; 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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View file

@ -8,6 +8,8 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UserNotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.security.Principal; import java.security.Principal;
import javax.validation.Valid; import javax.validation.Valid;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.JWTUserDetailsService;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.DisabledException;

View file

@ -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.dto.SensorSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; 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 ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.security.Principal; import java.security.Principal;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.*; import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -20,9 +23,14 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/sensor") @RequestMapping("/sensor")
public class SensorController { public class SensorController {
@Autowired private SensorRepository sensorRepository; @Autowired
private SensorRepository sensorRepository;
@Autowired private SensorSocketEndpoint sensorSocketEndpoint; @Autowired
private SensorSocketEndpoint sensorSocketEndpoint;
@Autowired
private SensorService sensorService;
@GetMapping @GetMapping
public List<Sensor> findAll() { public List<Sensor> findAll() {
@ -45,29 +53,13 @@ public class SensorController {
return sensorRepository.save(newSensor); 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") @PutMapping("/{id}/value")
public Sensor updateValue( public Sensor updateValue(
@PathVariable("id") Long sensorId, @PathVariable("id") Long sensorId,
@RequestParam("value") BigDecimal value, @RequestParam("value") BigDecimal value,
final Principal principal) final Principal principal)
throws NotFoundException { throws NotFoundException {
return updateValueFromSensor( return sensorService.updateValueFromSensor(
sensorRepository sensorRepository
.findByIdAndUsername(sensorId, principal.getName()) .findByIdAndUsername(sensorId, principal.getName())
.orElseThrow(NotFoundException::new), .orElseThrow(NotFoundException::new),

View file

@ -10,6 +10,8 @@ import java.util.*;
import java.util.List; import java.util.List;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import javax.validation.Valid; import javax.validation.Valid;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.*; import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -21,22 +23,16 @@ public class ThermostatController {
@Autowired private ThermostatRepository thermostatRepository; @Autowired private ThermostatRepository thermostatRepository;
@Autowired private ThermostatService thermostatService;
@GetMapping @GetMapping
public List<Thermostat> findAll() { public List<Thermostat> findAll(Principal user) {
Iterable<Thermostat> thermostats = thermostatRepository.findAll(); return thermostatService.findAll(user.getName());
StreamSupport.stream(thermostats.spliterator(), false)
.forEach(
s ->
s.setExternalSensorsAvailable(
thermostatRepository.getTemperatureSensorCount(
s.getRoomId())
> 0));
return toList(thermostats);
} }
@GetMapping("/{id}") @GetMapping("/{id}")
public Thermostat findById(@PathVariable("id") long id) throws NotFoundException { public Thermostat findById(@PathVariable("id") long id, Principal principal) throws NotFoundException {
return thermostatRepository.findById(id).orElseThrow(NotFoundException::new); return thermostatService.findById(id, principal.getName()).orElseThrow(NotFoundException::new);
} }
private Thermostat save(Thermostat newT, ThermostatSaveRequest t) { private Thermostat save(Thermostat newT, ThermostatSaveRequest t) {
@ -47,7 +43,9 @@ public class ThermostatController {
newT.setName(t.getName()); newT.setName(t.getName());
newT.setRoomId(t.getRoomId()); newT.setRoomId(t.getRoomId());
return thermostatRepository.save(newT); newT = thermostatRepository.save(newT);
thermostatService.populateMeasuredTemperature(newT);
return newT;
} }
@PostMapping @PostMapping

View file

@ -29,8 +29,7 @@ public class ThermostatSaveRequest {
/** Temperature to be reached */ /** Temperature to be reached */
@NotNull private BigDecimal targetTemperature; @NotNull private BigDecimal targetTemperature;
/** Embedded temperature sensor */ @NotNull private boolean useExternalSensors;
@NotNull private Sensor temperatureSensor;
/** State of this thermostat */ /** State of this thermostat */
@NotNull private Thermostat.ThermostatState state; @NotNull private Thermostat.ThermostatState state;
@ -43,12 +42,12 @@ public class ThermostatSaveRequest {
return this.state; return this.state;
} }
public Sensor getTemperatureSensor() { public boolean isUseExternalSensors() {
return this.temperatureSensor; return useExternalSensors;
} }
public void setTemperatureSensor(Sensor temperatureSensor) { public void setUseExternalSensors(boolean useExternalSensors) {
this.temperatureSensor = temperatureSensor; this.useExternalSensors = useExternalSensors;
} }
public BigDecimal getTargetTemperature() { public BigDecimal getTargetTemperature() {

View file

@ -1,6 +1,7 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import java.math.BigDecimal; import java.math.BigDecimal;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
@ -27,15 +28,15 @@ public class Thermostat extends OutputDevice {
/** The temperature detected by the embedded sensor */ /** The temperature detected by the embedded sensor */
@Column(nullable = false, precision = 4, scale = 1) @Column(nullable = false, precision = 4, scale = 1)
private BigDecimal sensorTemperature; private BigDecimal internalSensorTemperature;
/** State of this thermostat */ /** State of this thermostat */
@Column @NotNull private ThermostatState state; @Column @NotNull private ThermostatState state;
@Column boolean useInternalSensor = true; @Transient
private BigDecimal measuredTemperature;
/** True if there are any other sensors in the room */ @Column boolean useExternalSensors = false;
@Transient boolean externalSensorsAvaliable;
/** Creates a thermostat with a temperature sensor and its initial OFF state */ /** Creates a thermostat with a temperature sensor and its initial OFF state */
public Thermostat() { public Thermostat() {
@ -55,11 +56,23 @@ public class Thermostat extends OutputDevice {
return this.targetTemperature; return this.targetTemperature;
} }
public void setExternalSensorsAvailable(boolean externalSensorsAvaliable) { public BigDecimal getInternalSensorTemperature() {
this.externalSensorsAvaliable = externalSensorsAvaliable; 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 * 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. * until such temperature is reached by the embedded sensor to become idle again.
* *

View file

@ -12,16 +12,6 @@ public interface ThermostatRepository extends DeviceRepository<Thermostat> {
* @return an optional big decimal, empty if none found * @return an optional big decimal, empty if none found
*/ */
@Query( @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<BigDecimal> getAverageTemperature(Long thermostatRoomId); Optional<BigDecimal> 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);
} }

View file

@ -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.MotionSensorController;
import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.SensorController; import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.SensorController;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; 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 ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
@ -26,7 +27,7 @@ public class UpdateTasks {
@Autowired private SmartPlugRepository smartPlugRepository; @Autowired private SmartPlugRepository smartPlugRepository;
@Autowired private SensorController sensorController; @Autowired private SensorService sensorService;
@Autowired private MotionSensorController motionSensorController; @Autowired private MotionSensorController motionSensorController;
@ -35,16 +36,7 @@ public class UpdateTasks {
/** Generates fake sensor updates every two seconds with a +/- 1.25% error */ /** Generates fake sensor updates every two seconds with a +/- 1.25% error */
@Scheduled(fixedRate = 2000) @Scheduled(fixedRate = 2000)
public void sensorFakeUpdate() { public void sensorFakeUpdate() {
StreamSupport.stream(sensorRepository.findAll().spliterator(), true) sensorService.sensorFakeUpdate();
.forEach(
sensor ->
sensorController.updateValueFromSensor(
sensor,
Sensor.TYPICAL_VALUES
.get(sensor.getSensor())
.multiply(
new BigDecimal(
0.9875 + Math.random() / 40))));
} }
/** /**

View file

@ -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 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.beans.factory.annotation.Autowired;
import org.springframework.security.core.*; import org.springframework.security.core.*;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;

View file

@ -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;
}
}

View file

@ -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<Thermostat> findAll(String username) {
Iterable<Thermostat> all = thermostatRepository.findAllByUsername(username);
all.forEach(this::populateMeasuredTemperature);
return Utils.toList(all);
}
public Optional<Thermostat> findById(Long thermostat, String username) {
Optional<Thermostat> 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<BigDecimal> 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));
}
}