Merge branch '30-add-wattage-data-to-smart-plugs' into 'dev'

Resolve "Add wattage data to smart plugs"

Closes #30

See merge request sa4-2020/the-sanmarinoes/backend!42
This commit is contained in:
Claudio Maggioni 2020-03-17 17:01:26 +01:00
commit 7095de71a6
8 changed files with 83 additions and 10 deletions

View file

@ -5,6 +5,7 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SmartPlugSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SmartPlugSaveRequest;
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 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;
@ -14,7 +15,7 @@ import org.springframework.web.bind.annotation.*;
@RestController @RestController
@EnableAutoConfiguration @EnableAutoConfiguration
@RequestMapping("/smartplug") @RequestMapping("/smartPlug")
public class SmartPlugController { public class SmartPlugController {
@Autowired private SmartPlugRepository smartPlugRepository; @Autowired private SmartPlugRepository smartPlugRepository;
@ -49,6 +50,18 @@ public class SmartPlugController {
smartPlugRepository.findById(sp.getId()).orElseThrow(NotFoundException::new), sp); smartPlugRepository.findById(sp.getId()).orElseThrow(NotFoundException::new), sp);
} }
@DeleteMapping("/{id}/meter")
public SmartPlug resetMeter(@PathVariable("id") long id, final Principal principal)
throws NotFoundException {
final SmartPlug s =
smartPlugRepository
.findByIdAndUsername(id, principal.getName())
.orElseThrow(NotFoundException::new);
s.resetTotalConsumption();
return smartPlugRepository.save(s);
}
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) { public void deleteById(@PathVariable("id") long id) {
smartPlugRepository.deleteById(id); smartPlugRepository.deleteById(id);

View file

@ -36,7 +36,7 @@ public abstract class Device {
* The room this device belongs in, as a foreign key id. To use when updating and inserting from * The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call. * a REST call.
*/ */
@Column(name = "room_id", nullable = false, unique = true) @Column(name = "room_id", nullable = false)
@NotNull @NotNull
private Long roomId; private Long roomId;

View file

@ -35,7 +35,7 @@ public class Sensor extends InputDevice {
} }
/** The value of this sensor according to its sensor type */ /** The value of this sensor according to its sensor type */
@Column(nullable = false, length = 10, precision = 1) @Column(nullable = false, precision = 11, scale = 1)
private BigDecimal value; private BigDecimal value;
/** The type of this sensor */ /** The type of this sensor */

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.math.BigDecimal;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -8,11 +9,28 @@ import javax.validation.constraints.NotNull;
@Entity @Entity
public class SmartPlug extends Switchable { public class SmartPlug extends Switchable {
/** The average consumption of an active plug when on in Watt */
public static final Double AVERAGE_CONSUMPTION_KW = 200.0;
/** The total amount of power that the smart plug has consumed represented in W/h */
@Column(precision = 13, scale = 3)
@NotNull
private BigDecimal totalConsumption = BigDecimal.ZERO;
/** Whether the smart plug is on */ /** Whether the smart plug is on */
@Column(name = "smart_plug_on", nullable = false) @Column(name = "smart_plug_on", nullable = false)
@NotNull @NotNull
private boolean on; private boolean on;
public BigDecimal getTotalConsumption() {
return totalConsumption;
}
/** Resets the consuption meter */
public void resetTotalConsumption() {
totalConsumption = BigDecimal.ZERO;
}
@Override @Override
public boolean isOn() { public boolean isOn() {
return on; return on;

View file

@ -1,3 +1,24 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
public interface SmartPlugRepository extends SwitchableRepository<SmartPlug> {} import java.util.Collection;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
public interface SmartPlugRepository extends SwitchableRepository<SmartPlug> {
@Transactional
Collection<SmartPlug> findByOn(boolean on);
/**
* Updates total consumption of all activated smart plugs by considering a load of
* fakeConsumption W. This query must be executed every second
*
* @see ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled.UpdateTasks
* @param fakeConsumption the fake consumption in watts
*/
@Modifying(clearAutomatically = true)
@Transactional
@Query(
"UPDATE SmartPlug s SET totalConsumption = s.totalConsumption + ?1 / 3600.0 WHERE s.on = true")
void updateTotalConsumption(Double fakeConsumption);
}

View file

@ -2,10 +2,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.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.MotionSensorRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
@ -13,18 +13,25 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** Generates fake sensor (and motion sensor) updates as required by milestone one */ /**
* Generates fake sensor (and motion sensor) and smart plug consumption updates as required by
* milestone one
*/
@Component @Component
public class SensorUpdateTasks { public class UpdateTasks {
@Autowired private SensorRepository sensorRepository; @Autowired private SensorRepository sensorRepository;
@Autowired private MotionSensorRepository motionSensorRepository; @Autowired private MotionSensorRepository motionSensorRepository;
@Autowired private SmartPlugRepository smartPlugRepository;
@Autowired private SensorController sensorController; @Autowired private SensorController sensorController;
@Autowired private MotionSensorController motionSensorController; @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 +/- 1.25% error */
@Scheduled(fixedRate = 2000) @Scheduled(fixedRate = 2000)
public void sensorFakeUpdate() { public void sensorFakeUpdate() {
@ -59,4 +66,12 @@ public class SensorUpdateTasks {
sensor, false)); sensor, false));
}); });
} }
/** Updates power consumption of all activated smart plugs every second */
@Scheduled(fixedDelay = 1000)
public void smartPlugConsumptionFakeUpdate() {
smartPlugRepository.updateTotalConsumption(SmartPlug.AVERAGE_CONSUMPTION_KW);
final Collection<SmartPlug> c = smartPlugRepository.findByOn(true);
c.forEach(s -> sensorSocketEndpoint.broadcast(s, sensorRepository.findUser(s.getId())));
}
} }

View file

@ -61,6 +61,12 @@ public class SensorSocketEndpoint extends Endpoint {
final Collection<Session> sessions = authorizedClients.get(u); final Collection<Session> sessions = authorizedClients.get(u);
return sessions.stream() return sessions.stream()
.parallel() .parallel()
.filter(
s -> {
if (s.isOpen()) return true;
sessions.remove(s);
return false;
})
.filter(didThrow(s -> s.getBasicRemote().sendText(gson.toJson(message)))) .filter(didThrow(s -> s.getBasicRemote().sendText(gson.toJson(message))))
.count(); .count();
} }

View file

@ -5,7 +5,7 @@ spring.datasource.password=
# Hibernate properties # Hibernate properties
spring.jpa.database=POSTGRESQL spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=true spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.format_sql=true