From 5c0df55de9f2b627327eab20507ba071145b1e46 Mon Sep 17 00:00:00 2001 From: omenem Date: Mon, 20 Apr 2020 13:47:27 +0200 Subject: [PATCH 01/10] wip --- .../smarthut/models/BooleanTrigger.java | 23 ++++ .../sanmarinoes/smarthut/models/Trigger.java | 100 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java new file mode 100644 index 0000000..4b6a1df --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java @@ -0,0 +1,23 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Column; +import javax.persistence.Entity; + +@Entity +public class BooleanTrigger extends Trigger { + + @Column(name = "switchable_on") + private boolean on; + + public boolean isOn() { + return on; + } + + public void setOn(boolean on) { + this.on = on; + } + + public boolean check(boolean on) { + return this.on == on; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java new file mode 100644 index 0000000..b4eabc5 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -0,0 +1,100 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import io.swagger.annotations.ApiModelProperty; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PreRemove; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import javax.validation.constraints.NotNull; + +@Entity +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"device_id", "scene_id"})}) +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +public abstract class Trigger { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @ManyToOne(targetEntity = OutputDevice.class) + @JoinColumn(name = "device_id", updatable = false, insertable = false) + @GsonExclude + private D device; + + /** + * The device this trigger belongs to, as a foreign key id. To use when updating and inserting + * from a REST call. + */ + @Column(name = "device_id", nullable = false) + @NotNull + private Long deviceId; + + @ManyToOne + @JoinColumn(name = "scene_id", updatable = false, insertable = false) + @GsonExclude + private Scene scene; + + @Column(name = "scene_id", nullable = false) + @NotNull + private Long sceneId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public D getDevice() { + return device; + } + + public void setDevice(D device) { + this.device = device; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public Scene getScene() { + return scene; + } + + public void setScene(Scene scene) { + this.scene = scene; + } + + public Long getSceneId() { + return sceneId; + } + + public void setSceneId(Long sceneId) { + this.sceneId = sceneId; + } + + @PreRemove + public void removeDeviceAndScene() { + this.setScene(null); + this.setSceneId(null); + + this.setDevice(null); + this.setDeviceId(null); + } +} From 319629a681da900c0963a9e288eb92dad7c57227 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Mon, 20 Apr 2020 14:14:04 +0200 Subject: [PATCH 02/10] Pseudocode for automation implemmentation --- .../sanmarinoes/smarthut/models/Device.java | 5 +++ .../smarthut/models/InputDevice.java | 7 ++++ .../smarthut/models/Thermostat.java | 16 +++++++++ .../smarthut/service/DeviceService.java | 36 +++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 0114ac3..7fd7b80 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -4,6 +4,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import com.google.gson.annotations.SerializedName; import io.swagger.annotations.ApiModelProperty; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -91,4 +92,8 @@ public abstract class Device { this.kind = kind; this.flowType = flowType; } + + public List> triggeredTriggers() { + return List.of(); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java index 2acf0c2..0623872 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java @@ -1,9 +1,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; +import javax.persistence.OneToMany; /** * A generic abstraction for an input device, i.e. something that captures input either from the @@ -12,6 +15,10 @@ import javax.persistence.InheritanceType; @Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class InputDevice extends Device { + @OneToMany(mappedBy = "scene", orphanRemoval = true) + @GsonExclude + private Set> triggers = new HashSet<>(); + public InputDevice(String kind) { super(kind, FlowType.INPUT); } 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 7c54d54..dc8b977 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,9 +1,15 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import com.google.gson.annotations.SerializedName; import java.math.BigDecimal; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.OneToMany; import javax.persistence.Transient; import javax.validation.constraints.NotNull; @@ -24,6 +30,7 @@ public class Thermostat extends Switchable { /** * Computes the new thermostat state, for when the thermostat is on; + * * @return true if the state changed, false if not; */ public boolean computeState() { @@ -75,12 +82,21 @@ public class Thermostat extends Switchable { @Column private boolean useExternalSensors = false; + @OneToMany(mappedBy = "scene", orphanRemoval = true) + @GsonExclude + private Set> triggers = new HashSet<>(); + /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { super("thermostat"); this.mode = Mode.OFF; } + @Override + public List> triggeredTriggers() { + return triggers.stream().filter(t -> t.check(this.isOn())).collect(Collectors.toList()); + } + public void setMode(Mode state) { this.mode = state; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java new file mode 100644 index 0000000..c843c42 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -0,0 +1,36 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DeviceService { + + /* + Automation entity + - name + - id + - Set + - OrderedList // define order of application of scenes of the automation + // separate AutomationWithOrder id entity: + // - application_order_id (1 for first, 2 for second) + // - scene + // - FK automation + */ + + @Autowired DeviceRepository deviceRepository; + + public T save(T device) { + List> activated = device.triggeredTriggers(); + + // map activated -> automations + // remove duplicates + // sort automations per priority + // sort scenes inside automations per priority + // apply scenes (SceneService.apply()) + } +} From 0692f7e2ee85fe22cb2faf44bc465c8867586ee0 Mon Sep 17 00:00:00 2001 From: omenem Date: Tue, 21 Apr 2020 14:45:04 +0200 Subject: [PATCH 03/10] wip --- .../smarthut/models/Automation.java | 45 ++++++++ .../smarthut/models/BooleanTrigger.java | 3 + .../smarthut/models/RangeTrigger.java | 44 ++++++++ .../sanmarinoes/smarthut/models/Scene.java | 16 ++- .../smarthut/models/ScenePriority.java | 104 ++++++++++++++++++ .../models/ScenePriorityRepository.java | 5 + .../sanmarinoes/smarthut/models/Trigger.java | 30 ++--- 7 files changed, 228 insertions(+), 19 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java new file mode 100644 index 0000000..21b4ad3 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java @@ -0,0 +1,45 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import io.swagger.annotations.ApiModelProperty; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +public class Automation { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @OneToMany(mappedBy = "trigger", orphanRemoval = true) + @GsonExclude + private Set> triggers = new HashSet<>(); + + @OneToMany(mappedBy = "scenes", cascade = CascadeType.DETACH) + @GsonExclude + private Set scenes = new HashSet<>(); + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Set> getStates() { + return triggers; + } + + public Set getScenes() { + return scenes; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java index 4b6a1df..4e35e1d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java @@ -2,8 +2,11 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; @Entity +@Inheritance(strategy = InheritanceType.JOINED) public class BooleanTrigger extends Trigger { @Column(name = "switchable_on") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java new file mode 100644 index 0000000..c1f5ce4 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java @@ -0,0 +1,44 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.validation.constraints.NotNull; + +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +public class RangeTrigger extends Trigger { + + enum Operator { + EQUAL, + LESS, + GREATER, + LESS_EQUAL, + GREATER_EQUAL; + } + + @NotNull + @Column(nullable = false) + Operator operator; + + @NotNull + @Column(nullable = false) + private Float range; + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + public Float getRange() { + return range; + } + + public void setRange(Float range) { + this.range = range; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java index e762087..439acdb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -25,20 +25,24 @@ public class Scene { @GsonExclude private User user; - @OneToMany(mappedBy = "scene", orphanRemoval = true) - @GsonExclude - private Set> states = new HashSet<>(); - @NotNull @Column(name = "user_id", nullable = false) @GsonExclude private Long userId; + @OneToMany(mappedBy = "states", orphanRemoval = true) + @GsonExclude + private Set> states = new HashSet<>(); + /** The user given name of this room (e.g. 'Master bedroom') */ @NotNull @Column(nullable = false) private String name; + @ManyToMany(mappedBy = "automations", cascade = CascadeType.DETACH) + @GsonExclude + private Set automations = new HashSet<>(); + public String getName() { return name; } @@ -78,4 +82,8 @@ public class Scene { public void setUserId(Long userId) { this.userId = userId; } + + public Set getAutomations() { + return automations; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java new file mode 100644 index 0000000..7ceb39e --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java @@ -0,0 +1,104 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import io.swagger.annotations.ApiModelProperty; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PreRemove; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Entity +public class ScenePriority { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @ManyToOne + @JoinColumn(name = "automation_id", updatable = false, insertable = false) + @GsonExclude + private Automation automation; + + @Column(name = "automation_id", nullable = false) + @NotNull + private Long automationId; + + @NotNull + @Min(0) + @Column(nullable = false) + private Integer priority; + + @ManyToOne + @JoinColumn(name = "scene_id", updatable = false, insertable = false) + @GsonExclude + private Scene scene; + + @Column(name = "scene_id", nullable = false) + @NotNull + private Long sceneId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Integer getPriority() { + return priority; + } + + public void setPriority(Integer priority) { + this.priority = priority; + } + + public Automation getAutomation() { + return automation; + } + + public void setAutomation(Automation automation) { + this.automation = automation; + } + + public Long getAutomationId() { + return automationId; + } + + public void setAutomationId(Long automationId) { + this.automationId = automationId; + } + + public Scene getScene() { + return scene; + } + + public void setScene(Scene scene) { + this.scene = scene; + } + + public Long getSceneId() { + return sceneId; + } + + public void setSceneId(Long sceneId) { + this.sceneId = sceneId; + } + + @PreRemove + public void preRemove() { + this.setAutomation(null); + this.setAutomationId(null); + + this.setScene(null); + this.setSceneId(null); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java new file mode 100644 index 0000000..2dc81c4 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import org.springframework.data.repository.CrudRepository; + +public interface ScenePriorityRepository extends CrudRepository {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java index b4eabc5..22aac95 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -41,13 +41,13 @@ public abstract class Trigger { private Long deviceId; @ManyToOne - @JoinColumn(name = "scene_id", updatable = false, insertable = false) + @JoinColumn(name = "automation_id", updatable = false, insertable = false) @GsonExclude - private Scene scene; + private Automation automation; - @Column(name = "scene_id", nullable = false) + @Column(name = "automation_id", nullable = false) @NotNull - private Long sceneId; + private Long automationId; public long getId() { return id; @@ -73,28 +73,28 @@ public abstract class Trigger { this.deviceId = deviceId; } - public Scene getScene() { - return scene; + public Automation getAutomation() { + return automation; } - public void setScene(Scene scene) { - this.scene = scene; + public void setAutomation(Automation automation) { + this.automation = automation; } - public Long getSceneId() { - return sceneId; + public Long getAutomationId() { + return automationId; } - public void setSceneId(Long sceneId) { - this.sceneId = sceneId; + public void setAutomationId(Long automationId) { + this.automationId = automationId; } @PreRemove public void removeDeviceAndScene() { - this.setScene(null); - this.setSceneId(null); - this.setDevice(null); this.setDeviceId(null); + + this.setAutomation(null); + this.setAutomationId(null); } } From 618c1524668a52aa2d3281ab2b8180236b69f2f3 Mon Sep 17 00:00:00 2001 From: omenem Date: Tue, 21 Apr 2020 15:21:47 +0200 Subject: [PATCH 04/10] wip --- .../smarthut/models/BooleanTriggerRepository.java | 4 ++++ .../inf/sa4/sanmarinoes/smarthut/models/Device.java | 5 ----- .../smarthut/models/RangeTriggerRepository.java | 3 +++ .../inf/sa4/sanmarinoes/smarthut/models/Trigger.java | 2 ++ .../sanmarinoes/smarthut/models/TriggerRepository.java | 10 ++++++++++ .../sanmarinoes/smarthut/service/DeviceService.java | 7 ++++++- 6 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java new file mode 100644 index 0000000..932f4c8 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java @@ -0,0 +1,4 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface BooleanTriggerRepository + extends TriggerRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 7fd7b80..0114ac3 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -4,7 +4,6 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import com.google.gson.annotations.SerializedName; import io.swagger.annotations.ApiModelProperty; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -92,8 +91,4 @@ public abstract class Device { this.kind = kind; this.flowType = flowType; } - - public List> triggeredTriggers() { - return List.of(); - } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java new file mode 100644 index 0000000..084a70f --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface RangeTriggerRepository extends TriggerRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java index 22aac95..f42658d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -89,6 +89,8 @@ public abstract class Trigger { this.automationId = automationId; } + public abstract boolean check(T d); + @PreRemove public void removeDeviceAndScene() { this.setDevice(null); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java new file mode 100644 index 0000000..a506ce6 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java @@ -0,0 +1,10 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.util.List; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +public interface TriggerRepository> extends CrudRepository { + + List findAllByDeviceId(@Param("deviceId") long deviceId); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index c843c42..f248356 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -3,6 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.TriggerRepository; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -23,9 +24,13 @@ public class DeviceService { */ @Autowired DeviceRepository deviceRepository; + @Autowired TriggerRepository> triggerRepository; public T save(T device) { - List> activated = device.triggeredTriggers(); + + final Long deviceId = device.getId(); + + List> triggers = triggerRepository.findAllByDeviceId(deviceId); // map activated -> automations // remove duplicates From 43576061877c43d8a66900e6968d07ea794fd20d Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 21 Apr 2020 16:58:12 +0200 Subject: [PATCH 05/10] Code review --- .../smarthut/models/Automation.java | 2 +- .../smarthut/models/BooleanTrigger.java | 7 ++++++- .../smarthut/models/BooleanTriggerable.java | 5 +++++ .../sanmarinoes/smarthut/models/Dimmer.java | 4 +--- .../smarthut/models/KnobDimmer.java | 10 +++++++--- .../smarthut/models/MotionSensor.java | 7 ++++++- .../smarthut/models/RangeTrigger.java | 5 +++++ .../smarthut/models/RangeTriggerable.java | 5 +++++ .../smarthut/models/ScenePriority.java | 20 ++----------------- .../sanmarinoes/smarthut/models/Sensor.java | 7 ++++++- .../sanmarinoes/smarthut/models/Switch.java | 11 ++++++---- .../smarthut/models/Thermostat.java | 14 ++++++------- .../smarthut/service/DeviceService.java | 5 +++-- 13 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java index 21b4ad3..9dfefe9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Automation.java @@ -23,7 +23,7 @@ public class Automation { @GsonExclude private Set> triggers = new HashSet<>(); - @OneToMany(mappedBy = "scenes", cascade = CascadeType.DETACH) + @OneToMany(mappedBy = "scenes", cascade = CascadeType.REMOVE) @GsonExclude private Set scenes = new HashSet<>(); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java index 4e35e1d..db83c94 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java @@ -7,7 +7,7 @@ import javax.persistence.InheritanceType; @Entity @Inheritance(strategy = InheritanceType.JOINED) -public class BooleanTrigger extends Trigger { +public class BooleanTrigger extends Trigger { @Column(name = "switchable_on") private boolean on; @@ -23,4 +23,9 @@ public class BooleanTrigger extends Trigger { public boolean check(boolean on) { return this.on == on; } + + @Override + public boolean check() { + return getDevice().readTriggerState() == isOn(); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java new file mode 100644 index 0000000..6ff219f --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface BooleanTriggerable { + boolean readTriggerState(); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java index 7ef0808..9b3d627 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java @@ -1,7 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; - import java.util.HashSet; import java.util.Set; import javax.persistence.*; @@ -19,8 +18,7 @@ public abstract class Dimmer extends InputDevice { @JoinTable( name = "dimmer_dimmable", joinColumns = @JoinColumn(name = "dimmer_id"), - inverseJoinColumns = @JoinColumn(name = "dimmable_id") - ) + inverseJoinColumns = @JoinColumn(name = "dimmable_id")) private Set dimmables = new HashSet<>(); /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java index 87b527d..89273f8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java @@ -8,10 +8,9 @@ import javax.persistence.Entity; * value, like a knob) */ @Entity -public class KnobDimmer extends Dimmer { +public class KnobDimmer extends Dimmer implements RangeTriggerable { - @Column - Integer intensity = 0; + @Column private int intensity = 0; public KnobDimmer() { super("knobDimmer"); @@ -28,4 +27,9 @@ public class KnobDimmer extends Dimmer { dl.setIntensity(intensity); } } + + @Override + public double readTriggerState() { + return intensity; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java index 6c5baf7..4998922 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java @@ -5,7 +5,7 @@ import javax.persistence.Entity; /** Represents a motion sensor device */ @Entity -public class MotionSensor extends InputDevice { +public class MotionSensor extends InputDevice implements BooleanTriggerable { @Column(nullable = false) private boolean detected; @@ -21,4 +21,9 @@ public class MotionSensor extends InputDevice { public MotionSensor() { super("motionSensor"); } + + @Override + public boolean readTriggerState() { + return detected; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java index c1f5ce4..6c34f80 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java @@ -10,6 +10,11 @@ import javax.validation.constraints.NotNull; @Inheritance(strategy = InheritanceType.JOINED) public class RangeTrigger extends Trigger { + @Override + public boolean check(T d) { + return false; + } + enum Operator { EQUAL, LESS, diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java new file mode 100644 index 0000000..489a763 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface RangeTriggerable { + double readTriggerState(); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java index 7ceb39e..0652e5e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java @@ -1,11 +1,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; -import io.swagger.annotations.ApiModelProperty; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @@ -16,12 +13,6 @@ import javax.validation.constraints.NotNull; @Entity public class ScenePriority { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "id", updatable = false, nullable = false, unique = true) - @ApiModelProperty(hidden = true) - private long id; - @ManyToOne @JoinColumn(name = "automation_id", updatable = false, insertable = false) @GsonExclude @@ -41,18 +32,11 @@ public class ScenePriority { @GsonExclude private Scene scene; - @Column(name = "scene_id", nullable = false) + @Id + @Column(name = "scene_id", nullable = false, updatable = false, unique = true) @NotNull private Long sceneId; - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - public Integer getPriority() { return priority; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java index 6b5e6b9..2fb5442 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java @@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull; /** A sensor input device that measures a quantity in a continuous scale (e.g. temperature) */ @Entity -public class Sensor extends InputDevice { +public class Sensor extends InputDevice implements RangeTriggerable { public static final Map TYPICAL_VALUES = Map.of( @@ -19,6 +19,11 @@ public class Sensor extends InputDevice { SensorType.HUMIDITY, new BigDecimal(40.0), SensorType.LIGHT, new BigDecimal(1000)); + @Override + public double readTriggerState() { + return value.doubleValue(); + } + /** Type of sensor, i.e. of the thing the sensor measures. */ public enum SensorType { /** A sensor that measures temperature in degrees celsius */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java index e78bf9f..0768d6b 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java @@ -1,22 +1,20 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; - import java.util.HashSet; import java.util.Set; import javax.persistence.*; /** A switch input device */ @Entity -public class Switch extends InputDevice { +public class Switch extends InputDevice implements BooleanTriggerable { @ManyToMany(cascade = CascadeType.DETACH) @GsonExclude @JoinTable( name = "switch_switchable", joinColumns = @JoinColumn(name = "switch_id"), - inverseJoinColumns = @JoinColumn(name = "switchable_id") - ) + inverseJoinColumns = @JoinColumn(name = "switchable_id")) private Set switchables = new HashSet<>(); /** The state of this switch */ @@ -57,4 +55,9 @@ public class Switch extends InputDevice { public Set getOutputs() { return switchables; } + + @Override + public boolean readTriggerState() { + return on; + } } 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 dc8b977..2dd3772 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 @@ -4,9 +4,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import com.google.gson.annotations.SerializedName; import java.math.BigDecimal; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.OneToMany; @@ -15,7 +13,7 @@ import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ @Entity -public class Thermostat extends Switchable { +public class Thermostat extends Switchable implements BooleanTriggerable { @Override public boolean isOn() { @@ -56,6 +54,11 @@ public class Thermostat extends Switchable { return true; } + @Override + public boolean readTriggerState() { + return mode != Mode.OFF; + } + public enum Mode { @SerializedName("OFF") OFF, @@ -92,11 +95,6 @@ public class Thermostat extends Switchable { this.mode = Mode.OFF; } - @Override - public List> triggeredTriggers() { - return triggers.stream().filter(t -> t.check(this.isOn())).collect(Collectors.toList()); - } - public void setMode(Mode state) { this.mode = state; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index f248356..d8bbb0d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -28,9 +28,10 @@ public class DeviceService { public T save(T device) { - final Long deviceId = device.getId(); + final long deviceId = device.getId(); - List> triggers = triggerRepository.findAllByDeviceId(deviceId); + List> triggers = + triggerRepository.findAllByDeviceId(deviceId); // map activated -> automations // remove duplicates From db21aa0a26528ca58f7d69f962036a7a2cfcba62 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Tue, 21 Apr 2020 17:36:17 +0200 Subject: [PATCH 06/10] Code review --- .../smarthut/controller/SwitchController.java | 17 +++++----- .../smarthut/models/Automation.java | 12 +++---- .../smarthut/models/BooleanTrigger.java | 2 +- .../sanmarinoes/smarthut/models/Device.java | 5 +++ .../smarthut/models/InputDevice.java | 7 ---- .../smarthut/models/RangeTrigger.java | 33 +++++++++++++++---- .../sanmarinoes/smarthut/models/Scene.java | 10 +----- .../sanmarinoes/smarthut/models/Trigger.java | 7 ++-- .../smarthut/service/DeviceService.java | 14 ++++++-- 9 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java index 3a87b18..3bf41b8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java @@ -6,10 +6,10 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchOperationRequest; 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.DeviceService; import java.security.Principal; import java.util.*; import java.util.List; -import java.util.stream.Collectors; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.*; public class SwitchController extends InputDeviceConnectionController { private SwitchRepository switchRepository; - private SwitchableRepository switchableRepository; + private DeviceService deviceService; /** * Contstructs the controller by requiring essential object for the controller implementation @@ -31,10 +31,12 @@ public class SwitchController extends InputDeviceConnectionController outputRepository) { + SwitchRepository inputRepository, + SwitchableRepository outputRepository, + DeviceService deviceService) { super(inputRepository, outputRepository, Switchable.SWITCH_SWITCHABLE_CONNECTOR); this.switchRepository = inputRepository; - this.switchableRepository = outputRepository; + this.deviceService = deviceService; } @GetMapping @@ -57,7 +59,7 @@ public class SwitchController extends InputDeviceConnectionController operate( + public List operate( @Valid @RequestBody final SwitchOperationRequest sr, final Principal principal) throws NotFoundException { final Switch s = @@ -77,9 +79,8 @@ public class SwitchController extends InputDeviceConnectionController> triggers = new HashSet<>(); - @OneToMany(mappedBy = "scenes", cascade = CascadeType.REMOVE) + @OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE) @GsonExclude private Set scenes = new HashSet<>(); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java index db83c94..f52e5ca 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java @@ -25,7 +25,7 @@ public class BooleanTrigger extends Trigg } @Override - public boolean check() { + public boolean triggered() { return getDevice().readTriggerState() == isOn(); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 0114ac3..1787a67 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -34,6 +34,11 @@ public abstract class Device { @GsonExclude private Room room; + @OneToMany(mappedBy = "device", orphanRemoval = true) + @GsonExclude + // @SocketGsonExclude + private Set> triggers = new HashSet<>(); + /** * The room this device belongs in, as a foreign key id. To use when updating and inserting from * a REST call. diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java index 0623872..2acf0c2 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java @@ -1,12 +1,9 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; -import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; -import javax.persistence.OneToMany; /** * A generic abstraction for an input device, i.e. something that captures input either from the @@ -15,10 +12,6 @@ import javax.persistence.OneToMany; @Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class InputDevice extends Device { - @OneToMany(mappedBy = "scene", orphanRemoval = true) - @GsonExclude - private Set> triggers = new HashSet<>(); - public InputDevice(String kind) { super(kind, FlowType.INPUT); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java index 6c34f80..73c86eb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java @@ -1,5 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +import com.google.gson.annotations.SerializedName; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Inheritance; @@ -8,28 +9,46 @@ import javax.validation.constraints.NotNull; @Entity @Inheritance(strategy = InheritanceType.JOINED) -public class RangeTrigger extends Trigger { +public class RangeTrigger extends Trigger { @Override - public boolean check(T d) { - return false; + public boolean triggered() { + double value = getDevice().readTriggerState(); + switch (operator) { + case EQUAL: + return value == range; + case LESS: + return value < range; + case GREATER: + return value > range; + case GREATER_EQUAL: + return value >= range; + case LESS_EQUAL: + return value <= range; + } + throw new IllegalStateException(); } enum Operator { + @SerializedName("EQUAL") EQUAL, + @SerializedName("LESS") LESS, + @SerializedName("GREATER") GREATER, + @SerializedName("LESS_EQUAL") LESS_EQUAL, - GREATER_EQUAL; + @SerializedName("GREATER_EQUAL") + GREATER_EQUAL } @NotNull @Column(nullable = false) - Operator operator; + private Operator operator; @NotNull @Column(nullable = false) - private Float range; + private double range; public Operator getOperator() { return operator; @@ -39,7 +58,7 @@ public class RangeTrigger extends Trigger { this.operator = operator; } - public Float getRange() { + public double getRange() { return range; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java index 439acdb..c4b6213 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -30,7 +30,7 @@ public class Scene { @GsonExclude private Long userId; - @OneToMany(mappedBy = "states", orphanRemoval = true) + @OneToMany(mappedBy = "scene", orphanRemoval = true) @GsonExclude private Set> states = new HashSet<>(); @@ -39,10 +39,6 @@ public class Scene { @Column(nullable = false) private String name; - @ManyToMany(mappedBy = "automations", cascade = CascadeType.DETACH) - @GsonExclude - private Set automations = new HashSet<>(); - public String getName() { return name; } @@ -82,8 +78,4 @@ public class Scene { public void setUserId(Long userId) { this.userId = userId; } - - public Set getAutomations() { - return automations; - } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java index f42658d..1ef68f0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -12,15 +12,14 @@ import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.PreRemove; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; import javax.validation.constraints.NotNull; @Entity -@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"device_id", "scene_id"})}) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class Trigger { + public abstract boolean triggered(); + @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", updatable = false, nullable = false, unique = true) @@ -89,8 +88,6 @@ public abstract class Trigger { this.automationId = automationId; } - public abstract boolean check(T d); - @PreRemove public void removeDeviceAndScene() { this.setDevice(null); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index d8bbb0d..04512e5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -4,7 +4,9 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.TriggerRepository; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -26,17 +28,25 @@ public class DeviceService { @Autowired DeviceRepository deviceRepository; @Autowired TriggerRepository> triggerRepository; + public List saveAll(Collection devices) { + return devices.stream().map(this::save).collect(Collectors.toList()); + } + public T save(T device) { final long deviceId = device.getId(); - List> triggers = - triggerRepository.findAllByDeviceId(deviceId); + List> triggers = triggerRepository.findAllByDeviceId(deviceId); + + List> triggeredTriggers = + triggers.stream().filter(Trigger::triggered).collect(Collectors.toList()); // map activated -> automations // remove duplicates // sort automations per priority // sort scenes inside automations per priority // apply scenes (SceneService.apply()) + + return deviceRepository.save(device); } } From 5c2f828834f45d07213020cc731e40de158b3bf7 Mon Sep 17 00:00:00 2001 From: omenem Date: Wed, 22 Apr 2020 16:48:49 +0200 Subject: [PATCH 07/10] wid, added implements keyword for Boolean/RangeTriggerable in all the devices --- .../usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java | 7 ++++++- .../inf/sa4/sanmarinoes/smarthut/models/RegularLight.java | 7 ++++++- .../sa4/sanmarinoes/smarthut/models/SecurityCamera.java | 7 ++++++- .../inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java | 8 ++++++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java index a3ae206..ab49dd0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java @@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -public class Dimmable extends Switchable { +public class Dimmable extends Switchable implements RangeTriggerable { public static final Connector KNOB_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(KnobDimmer::getOutputs, Dimmable::getDimmers); @@ -85,4 +85,9 @@ public class Dimmable extends Switchable { newState.setIntensity(getIntensity()); return newState; } + + @Override + public double readTriggerState() { + return intensity; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java index 2dcff1b..2d06c59 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java @@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull; /** Represents a standard non-dimmable light */ @Entity -public class RegularLight extends Switchable { +public class RegularLight extends Switchable implements BooleanTriggerable { /** Whether the light is on or not */ @Column(name = "light_on", nullable = false) @@ -27,4 +27,9 @@ public class RegularLight extends Switchable { public void setOn(boolean on) { this.on = on; } + + @Override + public boolean readTriggerState() { + return on; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java index 7ddde5d..3d4cef9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java @@ -5,7 +5,7 @@ import javax.persistence.Entity; import javax.validation.constraints.NotNull; @Entity -public class SecurityCamera extends Switchable { +public class SecurityCamera extends Switchable implements BooleanTriggerable { public SecurityCamera() { super("securityCamera"); @@ -33,4 +33,9 @@ public class SecurityCamera extends Switchable { public void setOn(boolean on) { this.on = on; } + + @Override + public boolean readTriggerState() { + return on; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java index 546c746..77f6c3d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -import com.google.common.base.Objects; import java.math.BigDecimal; import javax.persistence.Column; @@ -9,7 +8,7 @@ import javax.validation.constraints.NotNull; /** A smart plug that can be turned either on or off */ @Entity -public class SmartPlug extends Switchable { +public class SmartPlug extends Switchable implements BooleanTriggerable { /** The average consumption of an active plug when on in Watt */ public static final Double AVERAGE_CONSUMPTION_KW = 200.0; @@ -46,4 +45,9 @@ public class SmartPlug extends Switchable { public SmartPlug() { super("smartPlug"); } + + @Override + public boolean readTriggerState() { + return on; + } } From 570b1e8b29bf9da2aa1b28ee8295f54e7e75bc07 Mon Sep 17 00:00:00 2001 From: omenem Date: Wed, 22 Apr 2020 17:30:16 +0200 Subject: [PATCH 08/10] wip, implemented very long stream in DeviceService, SceneService is missing though --- .../smarthut/models/AutomationRepository.java | 5 +++ .../smarthut/service/DeviceService.java | 33 ++++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java new file mode 100644 index 0000000..b8b2ac2 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import org.springframework.data.repository.CrudRepository; + +public interface AutomationRepository extends CrudRepository {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index 04512e5..273fe09 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -1,10 +1,14 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.AutomationRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ScenePriority; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.TriggerRepository; import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; @@ -13,19 +17,10 @@ import org.springframework.stereotype.Component; @Component public class DeviceService { - /* - Automation entity - - name - - id - - Set - - OrderedList // define order of application of scenes of the automation - // separate AutomationWithOrder id entity: - // - application_order_id (1 for first, 2 for second) - // - scene - // - FK automation - */ - @Autowired DeviceRepository deviceRepository; + @Autowired AutomationRepository automationRepository; + @Autowired SceneRepository sceneRepository; + // @Autowired SceneService sceneService; @Autowired TriggerRepository> triggerRepository; public List saveAll(Collection devices) { @@ -38,12 +33,20 @@ public class DeviceService { List> triggers = triggerRepository.findAllByDeviceId(deviceId); - List> triggeredTriggers = - triggers.stream().filter(Trigger::triggered).collect(Collectors.toList()); + triggers.stream() + .filter(Trigger::triggered) + .map(Trigger::getAutomationId) + .map(t -> automationRepository.findById(t)) + .distinct() + .map(t -> t.get().getScenes()) + .flatMap(Collection::stream) + .distinct() + .sorted(Comparator.comparing(ScenePriority::getPriority)) + .map(t -> sceneRepository.findById(t.getSceneId())) + .forEach(SceneService::apply); // map activated -> automations // remove duplicates - // sort automations per priority // sort scenes inside automations per priority // apply scenes (SceneService.apply()) From 37ea9591cfe025849b897005466243d16881a233 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Wed, 22 Apr 2020 23:04:43 +0200 Subject: [PATCH 09/10] Code review --- .../smarthut/controller/SceneController.java | 35 ++++++++----------- .../smarthut/service/DeviceService.java | 30 ++++++++-------- .../smarthut/service/SceneService.java | 28 +++++++++++++++ 3 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index 2b4c9c1..e9174af 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -5,8 +5,8 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SceneSaveRequest; 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.SceneService; import java.security.Principal; -import java.util.ArrayList; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -26,20 +26,21 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/scene") public class SceneController { - @Autowired SceneRepository sceneService; - @Autowired UserRepository userService; - @Autowired StateRepository> stateService; - @Autowired DeviceRepository deviceRepository; + @Autowired private SceneRepository sceneRepository; + @Autowired private SceneService sceneService; + @Autowired private UserRepository userService; + @Autowired private StateRepository> stateService; + @Autowired private DeviceRepository deviceRepository; @GetMapping public List findAll(Principal principal) { - return toList(sceneService.findByUsername(principal.getName())); + return toList(sceneRepository.findByUsername(principal.getName())); } @GetMapping("/{id}") public @ResponseBody Scene findById(@PathVariable("id") long id, Principal principal) throws NotFoundException { - return sceneService + return sceneRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); } @@ -56,26 +57,18 @@ public class SceneController { newScene.setUserId(userId); newScene.setName(s.getName()); - return sceneService.save(newScene); + return sceneRepository.save(newScene); } @PostMapping("/{id}/apply") public @ResponseBody List apply(@PathVariable("id") long id, final Principal principal) throws NotFoundException { final Scene newScene = - sceneService + sceneRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); - final List updated = new ArrayList<>(); - - for (final State s : newScene.getStates()) { - s.apply(); - updated.add(s.getDevice()); - } - deviceRepository.saveAll(updated); - - return updated; + return sceneService.apply(newScene); } @PutMapping("/{id}") @@ -83,7 +76,7 @@ public class SceneController { @PathVariable("id") long id, @RequestBody SceneSaveRequest s, final Principal principal) throws NotFoundException { final Scene newScene = - sceneService + sceneRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); @@ -91,13 +84,13 @@ public class SceneController { newScene.setName(s.getName()); } - return sceneService.save(newScene); + return sceneRepository.save(newScene); } @DeleteMapping("/{id}") public void deleteById(@PathVariable("id") long id) { stateService.deleteAllBySceneId(id); - sceneService.deleteById(id); + sceneRepository.deleteById(id); } /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index 273fe09..137d0e3 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -1,12 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.AutomationRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ScenePriority; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.TriggerRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -17,11 +11,11 @@ import org.springframework.stereotype.Component; @Component public class DeviceService { - @Autowired DeviceRepository deviceRepository; - @Autowired AutomationRepository automationRepository; - @Autowired SceneRepository sceneRepository; - // @Autowired SceneService sceneService; - @Autowired TriggerRepository> triggerRepository; + @Autowired private DeviceRepository deviceRepository; + @Autowired private AutomationRepository automationRepository; + @Autowired private SceneRepository sceneRepository; + @Autowired private SceneService sceneService; + @Autowired private TriggerRepository> triggerRepository; public List saveAll(Collection devices) { return devices.stream().map(this::save).collect(Collectors.toList()); @@ -36,14 +30,18 @@ public class DeviceService { triggers.stream() .filter(Trigger::triggered) .map(Trigger::getAutomationId) - .map(t -> automationRepository.findById(t)) + .map(t -> automationRepository.findById(t).orElseThrow(IllegalStateException::new)) .distinct() - .map(t -> t.get().getScenes()) + .map(Automation::getScenes) .flatMap(Collection::stream) .distinct() .sorted(Comparator.comparing(ScenePriority::getPriority)) - .map(t -> sceneRepository.findById(t.getSceneId())) - .forEach(SceneService::apply); + .map( + t -> + sceneRepository + .findById(t.getSceneId()) + .orElseThrow(IllegalStateException::new)) + .forEach(sceneService::apply); // map activated -> automations // remove duplicates diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java new file mode 100644 index 0000000..826d896 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java @@ -0,0 +1,28 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Scene; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SceneService { + + @Autowired private DeviceRepository deviceRepository; + + public List apply(Scene newScene) { + final List updated = new ArrayList<>(); + + for (final State s : newScene.getStates()) { + s.apply(); + updated.add(s.getDevice()); + } + deviceRepository.saveAll(updated); + + return updated; + } +} From 3da04ccaef19a0cb1dd0a4f60bec83d58b9a2598 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Thu, 23 Apr 2020 11:17:46 +0200 Subject: [PATCH 10/10] Fixed user story 5 and 7 --- .../controller/ButtonDimmerController.java | 9 +-- .../controller/CurtainsController.java | 4 +- .../controller/DimmableLightController.java | 1 + .../InputDeviceConnectionController.java | 65 ++++++++++--------- .../controller/KnobDimmerController.java | 8 +-- .../controller/MotionSensorController.java | 34 +++------- .../controller/RegularLightController.java | 1 + .../smarthut/controller/RoomController.java | 19 ++++-- .../smarthut/controller/SceneController.java | 1 - .../controller/SecurityCameraController.java | 9 ++- .../smarthut/controller/SensorController.java | 5 +- .../controller/SmartPlugController.java | 5 +- .../smarthut/controller/SwitchController.java | 7 +- .../controller/ThermostatController.java | 5 +- .../smarthut/models/RoomRepository.java | 7 ++ .../smarthut/models/UserRepository.java | 7 ++ .../smarthut/scheduled/UpdateTasks.java | 14 ++-- .../smarthut/service/DeviceService.java | 42 +++++++++--- .../smarthut/service/MotionSensorService.java | 33 ++++++++++ .../smarthut/service/SensorService.java | 10 +-- .../smarthut/service/ThermostatService.java | 7 +- 21 files changed, 193 insertions(+), 100 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java index ad00070..6b13ca9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java @@ -20,7 +20,6 @@ public class ButtonDimmerController private DeviceService deviceService; private ButtonDimmerRepository buttonDimmerRepository; - private DimmableRepository dimmableRepository; @Autowired protected ButtonDimmerController( @@ -30,12 +29,14 @@ public class ButtonDimmerController super(inputRepository, outputRepository, DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR); this.deviceService = deviceService; this.buttonDimmerRepository = inputRepository; - this.dimmableRepository = outputRepository; } @PostMapping public ButtonDimmer create( - @Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) { + @Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(bd.getRoomId(), principal.getName()); + ButtonDimmer newBD = new ButtonDimmer(); newBD.setName(bd.getName()); newBD.setRoomId(bd.getRoomId()); @@ -61,7 +62,7 @@ public class ButtonDimmerController break; } - dimmableRepository.saveAll(buttonDimmer.getOutputs()); + deviceService.saveAllAsOwner(buttonDimmer.getOutputs(), principal.getName(), false); return buttonDimmer.getOutputs(); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java index 517eea2..6644135 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java @@ -30,7 +30,9 @@ public class CurtainsController { @PostMapping public Curtains create( - @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) { + @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(curtain.getRoomId(), principal.getName()); return save(new Curtains(), curtain, principal); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index 277c367..60a4726 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -57,6 +57,7 @@ public class DimmableLightController extends GuestEnabledController output; + private final List outputs; - private Connection(I input, List output) { + private Connection(I input, List outputs) { this.input = input; - this.output = output; + this.outputs = outputs; } } + @Autowired private DeviceService deviceService; + private DeviceRepository inputRepository; private DeviceRepository outputReposiory; @@ -56,17 +59,17 @@ public abstract class InputDeviceConnectionController< this.connector = connector; } - private Connection checkConnectionIDs(Long inputId, List outputs) + private Connection checkConnectionIDs(Long inputId, List outputs, String username) throws NotFoundException { final I input = inputRepository - .findById(inputId) + .findByIdAndUsername(inputId, username) .orElseThrow(() -> new NotFoundException("input device")); final List outputDevices = new ArrayList<>(); for (final Long outputId : outputs) { outputDevices.add( outputReposiory - .findById(outputId) + .findByIdAndUsername(outputId, username) .orElseThrow(() -> new NotFoundException("output device"))); } return new Connection(input, outputDevices); @@ -76,19 +79,19 @@ public abstract class InputDeviceConnectionController< * Implements the output device connection creation (add) route * * @param inputId input device id - * @param outputId output device id list + * @param outputs output device id list * @return the list of output devices attached to the input device of id inputId * @throws NotFoundException if inputId or outputId are not valid */ - protected Set addOutput(Long inputId, List outputId) - throws NotFoundException { - final Connection pair = checkConnectionIDs(inputId, outputId); + protected Set addOutput( + Long inputId, List outputs, String username) throws NotFoundException { + final Connection pair = checkConnectionIDs(inputId, outputs, username); - for (final O o : pair.output) { + for (final O o : pair.outputs) { connector.connect(pair.input, o, true); } - outputReposiory.saveAll(pair.output); + deviceService.saveAllAsOwner(pair.outputs, username, false); return pair.input.getOutputs(); } @@ -96,33 +99,37 @@ public abstract class InputDeviceConnectionController< * Implements the output device connection destruction (remove) route * * @param inputId input device id - * @param outputId output device id list + * @param outputs output device id list * @return the list of output devices attached to the input device of id inputId * @throws NotFoundException if inputId or outputId are not valid */ - protected Set removeOutput(Long inputId, List outputId) - throws NotFoundException { - final Connection pair = checkConnectionIDs(inputId, outputId); + protected Set removeOutput( + Long inputId, List outputs, String username) throws NotFoundException { + final Connection pair = checkConnectionIDs(inputId, outputs, username); - for (final O o : pair.output) { + for (final O o : pair.outputs) { connector.connect(pair.input, o, false); } - outputReposiory.saveAll(pair.output); + deviceService.saveAllAsOwner(pair.outputs, username, false); return pair.input.getOutputs(); } @PostMapping("/{id}/lights") public List addLight( - @PathVariable("id") long inputId, @RequestBody List lightId) + @PathVariable("id") long inputId, + @RequestBody List lightId, + final Principal principal) throws NotFoundException { - return toList(addOutput(inputId, lightId)); + return toList(addOutput(inputId, lightId, principal.getName())); } @DeleteMapping("/{id}/lights") public List removeLight( - @PathVariable("id") long inputId, @RequestBody List lightId) + @PathVariable("id") long inputId, + @RequestBody List lightId, + final Principal principal) throws NotFoundException { - return toList(removeOutput(inputId, lightId)); + return toList(removeOutput(inputId, lightId, principal.getName())); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java index 0f5d281..9b30535 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java @@ -19,19 +19,19 @@ public class KnobDimmerController extends InputDeviceConnectionController dimmableRepository; @Autowired protected KnobDimmerController( KnobDimmerRepository inputRepository, DimmableRepository outputRepository) { super(inputRepository, outputRepository, Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR); this.knobDimmerRepository = inputRepository; - this.dimmableRepository = outputRepository; } @PostMapping public KnobDimmer create( - @Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) { + @Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(kd.getRoomId(), principal.getName()); KnobDimmer newKD = new KnobDimmer(); newKD.setName(kd.getName()); newKD.setRoomId(kd.getRoomId()); @@ -49,7 +49,7 @@ public class KnobDimmerController extends InputDeviceConnectionController public RegularLight create( @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) throws NotFoundException { + deviceService.throwIfRoomNotOwned(rl.getRoomId(), principal.getName()); return save(new RegularLight(), rl, principal.getName(), null); } 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 136446a..c4540c5 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 @@ -49,7 +49,11 @@ public class RoomController { final Principal principal) throws NotFoundException { - List rooms = toList(roomRepository.findAll()); + List rooms = + toList( + hostId != null + ? roomRepository.findByUserId(hostId) + : roomRepository.findByUsername(principal.getName())); return fetchOwnerOrGuest(rooms, hostId, principal); } @@ -60,10 +64,6 @@ public class RoomController { @RequestParam(value = "hostId", required = false) Long hostId) throws NotFoundException { Room room = roomRepository.findById(id).orElseThrow(NotFoundException::new); - /* Very ugly way of avoiding code duplication. If this method call throws no exception, - * we can return the room safely. I pass null as I do not return a list in this case. - * Refer to fetchOwnerOrGuest for further information. - */ fetchOwnerOrGuest(null, hostId, principal); return room; } @@ -115,11 +115,16 @@ public class RoomController { } @DeleteMapping("/{id}") - public void deleteById(@PathVariable("id") long id) { + public void deleteById(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { switchRepository.deleteAllByRoomId(id); knobDimmerRepository.deleteAllByRoomId(id); buttonDimmerRepository.deleteAllByRoomId(id); - roomRepository.deleteById(id); + final Room r = + roomRepository + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + roomRepository.delete(r); } /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index fc2268d..0cddba2 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -30,7 +30,6 @@ public class SceneController { @Autowired private SceneService sceneService; @Autowired private UserRepository userService; @Autowired private StateRepository> stateService; - @Autowired private DeviceRepository deviceRepository; @GetMapping public List findAll(Principal principal) { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java index c2d955c..c063ebf 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java @@ -23,10 +23,11 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/securityCamera") public class SecurityCameraController { - @Autowired DeviceService deviceService; - @Autowired SecurityCameraRepository securityCameraService; + @Autowired private DeviceService deviceService; + @Autowired private SecurityCameraRepository securityCameraService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; + @Autowired private RoomRepository roomRepository; private SecurityCamera save( SecurityCamera newSC, SwitchableSaveRequest sc, final Principal principal) { @@ -39,7 +40,9 @@ public class SecurityCameraController { @PostMapping public SecurityCamera create( - @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) { + @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(sc.getRoomId(), principal.getName()); return save(new SecurityCamera(), sc, principal); } 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 ea01909..41b9af0 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 @@ -28,7 +28,10 @@ public class SensorController { @Autowired private SensorService sensorService; @PostMapping - public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) { + public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(s.getRoomId(), principal.getName()); + Sensor newSensor = new Sensor(); newSensor.setSensor(s.getSensor()); newSensor.setName(s.getName()); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java index 308836c..468cd5d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java @@ -31,8 +31,9 @@ public class SmartPlugController { } @PostMapping - public SmartPlug create( - @Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) { + public SmartPlug create(@Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(sp.getRoomId(), principal.getName()); return save(new SmartPlug(), sp, principal); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java index 9b95451..0847c87 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java @@ -38,8 +38,9 @@ public class SwitchController extends InputDeviceConnectionController { */ @Query("SELECT r FROM Room r JOIN r.user u WHERE r.id = ?1 AND u.username = ?2") Optional findByIdAndUsername(Long id, String username); + + @Query("SELECT r FROM Room r JOIN r.user u WHERE u.username = ?1") + List findByUsername(String username); + + @Query("SELECT r FROM Room r JOIN r.user u WHERE u.id = ?1") + List findByUserId(Long hostId); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java index 01fd897..d1569d6 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java @@ -1,10 +1,17 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.util.*; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository { User findByUsername(String username); + @Query("SELECT u FROM #{#entityName} u JOIN FETCH u.guests WHERE u.username = ?1") + User findByUsernameFetchGuests(String username); + + @Query("SELECT u FROM #{#entityName} u JOIN FETCH u.guests WHERE u.id = ?1") + User findByIdFetchGuests(Long id); + User findByEmailIgnoreCase(String email); } 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 4fe293c..e701166 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,7 +1,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.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.MotionSensorService; 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; @@ -30,7 +30,7 @@ public class UpdateTasks { @Autowired private ThermostatService thermostatService; - @Autowired private MotionSensorController motionSensorController; + @Autowired private MotionSensorService motionSensorService; @Autowired private SensorSocketEndpoint sensorSocketEndpoint; @@ -55,14 +55,18 @@ public class UpdateTasks { StreamSupport.stream(motionSensorRepository.findAll().spliterator(), true) .forEach( sensor -> { - motionSensorController.updateDetectionFromMotionSensor(sensor, true); + final User owner = motionSensorRepository.findUser(sensor.getId()); + motionSensorService.updateDetectionFromMotionSensor( + sensor, true, owner.getUsername()); CompletableFuture.delayedExecutor( (long) (Math.random() * 2000), TimeUnit.MILLISECONDS) .execute( () -> - motionSensorController + motionSensorService .updateDetectionFromMotionSensor( - sensor, false)); + sensor, + false, + owner.getUsername())); }); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index 923c21e..f043b05 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -25,6 +25,10 @@ public class DeviceService { @Autowired private SensorSocketEndpoint endpoint; @Autowired private ThermostatService thermostatService; + public void throwIfRoomNotOwned(Long roomId, String username) throws NotFoundException { + roomRepository.findByIdAndUsername(roomId, username).orElseThrow(NotFoundException::new); + } + public void triggerTriggers(Device device) { final long deviceId = device.getId(); @@ -100,10 +104,9 @@ public class DeviceService { public T saveAsGuest(T device, String guestUsername, Long hostId) throws NotFoundException { - device = deviceRepository.save(device); - final User currentUser = userRepository.findByUsername(guestUsername); - final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); + final User host = userRepository.findByIdFetchGuests(hostId); + if (host == null) throw new NotFoundException(); final Set guests = Set.copyOf(host.getGuests()); // We're telling the host that a guest has modified a device. Therefore, fromGuest becomes @@ -128,10 +131,8 @@ public class DeviceService { return device; } - public T saveAsOwner(T device, String username) { - device = deviceRepository.save(device); - - final User user = userRepository.findByUsername(username); + private void propagateUpdateAsOwner(Device device, String username) { + final User user = userRepository.findByUsernameFetchGuests(username); final Set guests = user.getGuests(); // make sure we're broadcasting from host device.setFromHost(true); @@ -140,10 +141,35 @@ public class DeviceService { // broadcast to endpoint the object device, with receiving user set to guest endpoint.queueDeviceUpdate(device, guest); } + } + + public List saveAllAsOwner( + Iterable devices, String username, boolean fromScene) { + devices = deviceRepository.saveAll(devices); + devices.forEach((d) -> propagateUpdateAsOwner(d, username)); + + if (!fromScene) { + devices.forEach(this::triggerTriggers); + } + + return toList(devices); + } + + public T saveAsOwner(T device, String username, boolean fromScene) { + device = deviceRepository.save(device); + propagateUpdateAsOwner(device, username); + + if (!fromScene) { + triggerTriggers(device); + } return device; } + public T saveAsOwner(T device, String username) { + return saveAsOwner(device, username, false); + } + public void delete(Long id, String username) throws NotFoundException { Device device = deviceRepository @@ -151,7 +177,7 @@ public class DeviceService { .orElseThrow(NotFoundException::new); deviceRepository.delete(device); - final User user = userRepository.findByUsername(username); + final User user = userRepository.findByUsernameFetchGuests(username); final Set guests = user.getGuests(); device.setFromHost(true); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java new file mode 100644 index 0000000..01a7401 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java @@ -0,0 +1,33 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensor; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class MotionSensorService { + + @Autowired private SensorSocketEndpoint sensorSocketEndpoint; + @Autowired private DeviceService deviceService; + @Autowired private MotionSensorRepository motionSensorRepository; + + /** + * Updates detection status of given motion sensor and propagates update throgh socket + * + * @param sensor the motion sensor to update + * @param detected the new detection status + * @return the updated motion sensor + */ + public MotionSensor updateDetectionFromMotionSensor( + MotionSensor sensor, boolean detected, String username) { + sensor.setDetected(detected); + final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username); + + sensorSocketEndpoint.queueDeviceUpdate( + sensor, motionSensorRepository.findUser(sensor.getId())); + + return toReturn; + } +} 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 f3072cd..0e4fbbd 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 @@ -12,6 +12,8 @@ public class SensorService { @Autowired private SensorRepository sensorRepository; + @Autowired private DeviceService deviceService; + @Autowired private ThermostatService thermostatService; @Autowired private SensorSocketEndpoint endpoint; @@ -38,10 +40,10 @@ public class SensorService { */ public Sensor updateValueFromSensor(Sensor sensor, BigDecimal value) { sensor.setValue(value); - final Sensor toReturn = sensorRepository.save(sensor); - + sensor = + deviceService.saveAsOwner( + sensor, sensorRepository.findUser(sensor.getId()).getUsername()); endpoint.queueDeviceUpdate(sensor, sensorRepository.findUser(sensor.getId())); - - return toReturn; + return sensor; } } 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 2352cf9..e214e39 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 @@ -16,6 +16,8 @@ public class ThermostatService { @Autowired private SensorSocketEndpoint endpoint; + @Autowired private DeviceService deviceService; + @Autowired private ThermostatRepository thermostatRepository; private void randomJitter(Thermostat thermostat) { @@ -28,7 +30,8 @@ public class ThermostatService { private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) { thermostat.setInternalSensorTemperature(value); - thermostatRepository.save(thermostat); + deviceService.saveAsOwner( + thermostat, thermostatRepository.findUser(thermostat.getId()).getUsername()); } public void fakeUpdateAll() { @@ -51,7 +54,7 @@ public class ThermostatService { boolean shouldUpdate = this.computeState(t); if (shouldUpdate) { - thermostatRepository.save(t); + deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername()); endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId())); } }