Added apply() method on State to change underlying device accordingly

This commit is contained in:
Claudio Maggioni (maggicl) 2020-04-15 23:08:57 +02:00
parent 6be999ffcc
commit 495c317eb8
18 changed files with 150 additions and 52 deletions

View file

@ -5,7 +5,6 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
import java.security.Principal; import java.security.Principal;
import java.util.*;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -42,10 +41,10 @@ public class ThermostatController {
newT.setUseExternalSensors(t.isUseExternalSensors()); newT.setUseExternalSensors(t.isUseExternalSensors());
if (t.isTurnOn()) { if (t.isTurnOn()) {
newT.setState(Thermostat.ThermostatState.IDLE); newT.setMode(Thermostat.Mode.IDLE);
thermostatService.computeState(newT); thermostatService.computeState(newT);
} else { } else {
newT.setState(Thermostat.ThermostatState.OFF); newT.setMode(Thermostat.Mode.OFF);
} }
newT = thermostatRepository.save(newT); newT = thermostatRepository.save(newT);

View file

@ -0,0 +1,13 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
/**
* An IDimmable Device whose state can be set by a DimmableState of the corresponding type
* @param <T> the type of the class that extends this interface (just for type bounds, does not mean actually anything)
*/
public interface AlterableFromDimmableState<T extends OutputDevice & AlterableFromDimmableState<T>>
extends IDimmable, AlterableFromState<State<T>> {
default void readStateAndSet(State<T> state) {
final DimmableState<T> hack = (DimmableState<T>) state;
setDimAmount(hack.getDimAmount());
}
}

View file

@ -0,0 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
/** An OutputDevice whose state can be set by a State of corresponding device type */
public interface AlterableFromState<T extends State<? extends OutputDevice>> {
void readStateAndSet(T state);
}

View file

@ -0,0 +1,13 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
/**
* An ISwitchable Device whose state can be set by a SwitchableState of the corresponding type
* @param <T> the type of the class that extends this interface (just for type bounds, does not mean actually anything)
*/
public interface AlterableFromSwitchableState<T extends OutputDevice & AlterableFromSwitchableState<T>>
extends ISwtichable, AlterableFromState<State<T>> {
default void readStateAndSet(State<T> state) {
final SwitchableState<T> hack = (SwitchableState<T>) state;
setOn(hack.isOn());
}
}

View file

@ -7,7 +7,7 @@ import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Entity @Entity
public class Curtains extends OutputDevice { public class Curtains extends OutputDevice implements IDimmable, AlterableFromDimmableState<Curtains> {
/** /**
* it represents how much the curtains are opened, 0 is completely closed 100 is completely open * it represents how much the curtains are opened, 0 is completely closed 100 is completely open
@ -38,4 +38,14 @@ public class Curtains extends OutputDevice {
this.openedAmount = newOpening; this.openedAmount = newOpening;
} }
} }
@Override
public Integer getDimAmount() {
return getOpenedAmount();
}
@Override
public void setDimAmount(Integer intensity) {
setOpenedAmount(intensity);
}
} }

View file

@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull;
/** Represent a dimmable light */ /** Represent a dimmable light */
@Entity @Entity
public class DimmableLight extends Switchable { public class DimmableLight extends Switchable implements IDimmable, AlterableFromDimmableState<DimmableLight> {
public static final Connector<ButtonDimmer, DimmableLight> public static final Connector<ButtonDimmer, DimmableLight>
BUTTON_DIMMER_DIMMABLE_LIGHT_CONNECTOR = BUTTON_DIMMER_DIMMABLE_LIGHT_CONNECTOR =
@ -86,4 +86,14 @@ public class DimmableLight extends Switchable {
super.setSwitchId(switchId); super.setSwitchId(switchId);
this.dimmerId = null; this.dimmerId = null;
} }
@Override
public Integer getDimAmount() {
return getIntensity();
}
@Override
public void setDimAmount(Integer intensity) {
setIntensity(intensity);
}
} }

View file

@ -6,22 +6,22 @@ import javax.validation.constraints.Max;
import javax.validation.constraints.Min; import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
/** Represent a dimmable light state */ /** Represent a state for an IDimmable device */
@Entity @Entity
public class DimmableLightState extends State { public class DimmableState<T extends OutputDevice & AlterableFromState<State<T>>> extends State<T> {
/** The light intensity value. Goes from 0 (off) to 100 (on) */ /** The light intensity value. Goes from 0 (off) to 100 (on) */
@NotNull @NotNull
@Column(nullable = false) @Column(nullable = false)
@Min(0) @Min(0)
@Max(100) @Max(100)
private Integer intensity = 0; private Integer dimAmount = 0;
public Integer getIntensity() { public Integer getDimAmount() {
return intensity; return dimAmount;
} }
public void setIntensity(Integer intensity) { public void setDimAmount(Integer dimAmount) {
this.intensity = intensity; this.dimAmount = dimAmount;
} }
} }

View file

@ -0,0 +1,10 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
/**
* Although not totally enforced in code, it represents an OutputDevice that can be set a state (here "dimAmount")
* that ranges from 0 to 100
*/
public interface IDimmable {
Integer getDimAmount();
void setDimAmount(Integer intensity);
}

View file

@ -0,0 +1,20 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
/** Interface equivalent of Switchable. Altough not totally enforced in code, it represents an OutputDevice that can be
* turned on or off
*/
public interface ISwtichable {
/**
* Returns whether the device is on (true) or not (false)
*
* @return whether the device is on (true) or not (false)
*/
boolean isOn();
/**
* Sets the on status of the device
*
* @param on the new on status: true for on, false for off
*/
void setOn(boolean on);
}

View file

@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull;
/** Represents a standard non-dimmable light */ /** Represents a standard non-dimmable light */
@Entity @Entity
public class RegularLight extends Switchable { public class RegularLight extends Switchable implements AlterableFromSwitchableState<RegularLight> {
/** Whether the light is on or not */ /** Whether the light is on or not */
@Column(name = "light_on", nullable = false) @Column(name = "light_on", nullable = false)

View file

@ -5,7 +5,7 @@ import javax.persistence.Entity;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Entity @Entity
public class SecurityCamera extends Switchable { public class SecurityCamera extends Switchable implements AlterableFromSwitchableState<SecurityCamera> {
public SecurityCamera() { public SecurityCamera() {
super("securityCamera"); super("securityCamera");

View file

@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull;
/** A smart plug that can be turned either on or off */ /** A smart plug that can be turned either on or off */
@Entity @Entity
public class SmartPlug extends Switchable { public class SmartPlug extends Switchable implements AlterableFromSwitchableState<SmartPlug> {
/** The average consumption of an active plug when on in Watt */ /** The average consumption of an active plug when on in Watt */
public static final Double AVERAGE_CONSUMPTION_KW = 200.0; public static final Double AVERAGE_CONSUMPTION_KW = 200.0;

View file

@ -2,6 +2,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import org.hibernate.annotations.Type;
import javax.persistence.*; import javax.persistence.*;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -11,7 +13,7 @@ import javax.validation.constraints.NotNull;
*/ */
@Entity @Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class State { public abstract class State<D extends OutputDevice & AlterableFromState<State<D>>> {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
@ -19,10 +21,10 @@ public abstract class State {
@ApiModelProperty(hidden = true) @ApiModelProperty(hidden = true)
private long id; private long id;
@ManyToOne @ManyToOne(targetEntity = OutputDevice.class)
@JoinColumn(name = "device_id", updatable = false, insertable = false) @JoinColumn(name = "device_id", updatable = false, insertable = false)
@GsonExclude @GsonExclude
private Device device; private D device;
/** /**
* The device this state belongs in, as a foreign key id. To use when updating and inserting * The device this state belongs in, as a foreign key id. To use when updating and inserting
@ -41,6 +43,13 @@ public abstract class State {
@NotNull @NotNull
private Long sceneId; private Long sceneId;
/**
* Sets the state of the connected device to the state represented by this object.
*/
public void apply() {
device.readStateAndSet(this);
}
public long getId() { public long getId() {
return id; return id;
} }
@ -49,11 +58,11 @@ public abstract class State {
this.id = id; this.id = id;
} }
public Device getDevice() { public D getDevice() {
return device; return device;
} }
public void setDevice(Device device) { public void setDevice(D device) {
this.device = device; this.device = device;
} }

View file

@ -6,7 +6,7 @@ import javax.persistence.*;
/** A device that can be turned either on or off */ /** A device that can be turned either on or off */
@Entity @Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Switchable extends OutputDevice { public abstract class Switchable extends OutputDevice implements ISwtichable {
public static final Connector<Switch, Switchable> SWITCH_SWITCHABLE_CONNECTOR = public static final Connector<Switch, Switchable> SWITCH_SWITCHABLE_CONNECTOR =
Connector.basic(Switch::getOutputs, Switchable::setSwitchId); Connector.basic(Switch::getOutputs, Switchable::setSwitchId);
@ -23,20 +23,6 @@ public abstract class Switchable extends OutputDevice {
super(kind); super(kind);
} }
/**
* Returns whether the device is on (true) or not (false)
*
* @return whether the device is on (true) or not (false)
*/
public abstract boolean isOn();
/**
* Sets the on status of the device
*
* @param on the new on status: true for on, false for off
*/
public abstract void setOn(boolean on);
public Long getSwitchId() { public Long getSwitchId() {
return switchId; return switchId;
} }

View file

@ -4,9 +4,9 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
/** A state for RegularLight and SmartPlug */ /** Represents a state for a Switchable device */
@Entity @Entity
public class SwitchableState extends State { public class SwitchableState<T extends OutputDevice & AlterableFromState<State<T>>> extends State<T> {
@Column(name = "switchable_on", nullable = false) @Column(name = "switchable_on", nullable = false)
@NotNull @NotNull

View file

@ -9,9 +9,15 @@ import javax.validation.constraints.NotNull;
/** A thermostat capable of controlling cooling and heating. */ /** A thermostat capable of controlling cooling and heating. */
@Entity @Entity
public class Thermostat extends OutputDevice { public class Thermostat extends OutputDevice implements AlterableFromState<State<Thermostat>> {
public enum ThermostatState { @Override
public void readStateAndSet(State<Thermostat> state) {
final ThermostatState hack = (ThermostatState) state;
setMode(hack.getMode());
}
public enum Mode {
@SerializedName("OFF") @SerializedName("OFF")
OFF, OFF,
@SerializedName("IDLE") @SerializedName("IDLE")
@ -31,7 +37,7 @@ public class Thermostat extends OutputDevice {
Sensor.TYPICAL_VALUES.get(Sensor.SensorType.TEMPERATURE); Sensor.TYPICAL_VALUES.get(Sensor.SensorType.TEMPERATURE);
/** State of this thermostat */ /** State of this thermostat */
@Column @NotNull private ThermostatState state; @Column @NotNull private Thermostat.Mode mode;
@Transient private BigDecimal measuredTemperature; @Transient private BigDecimal measuredTemperature;
@ -40,15 +46,15 @@ public class Thermostat extends OutputDevice {
/** Creates a thermostat with a temperature sensor and its initial OFF state */ /** Creates a thermostat with a temperature sensor and its initial OFF state */
public Thermostat() { public Thermostat() {
super("thermostat"); super("thermostat");
this.state = ThermostatState.OFF; this.mode = Mode.OFF;
} }
public void setState(ThermostatState state) { public void setMode(Mode state) {
this.state = state; this.mode = state;
} }
public ThermostatState getState() { public Mode getMode() {
return this.state; return this.mode;
} }
public BigDecimal getTargetTemperature() { public BigDecimal getTargetTemperature() {

View file

@ -0,0 +1,16 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
@Entity
public class ThermostatState extends State<Thermostat> {
private Thermostat.Mode mode;
public Thermostat.Mode getMode() {
return mode;
}
public void setMode(Thermostat.Mode mode) {
this.mode = mode;
}
}

View file

@ -43,7 +43,7 @@ public class ThermostatService {
} }
public boolean computeState(Thermostat t) { public boolean computeState(Thermostat t) {
if (t.getState() == Thermostat.ThermostatState.OFF) { if (t.getMode() == Thermostat.Mode.OFF) {
return false; return false;
} }
@ -53,14 +53,14 @@ public class ThermostatService {
BigDecimal delta = target.subtract(measured); BigDecimal delta = target.subtract(measured);
if (delta.abs().doubleValue() < 0.25) { if (delta.abs().doubleValue() < 0.25) {
if (t.getState() == Thermostat.ThermostatState.IDLE) return false; if (t.getMode() == Thermostat.Mode.IDLE) return false;
t.setState(Thermostat.ThermostatState.IDLE); t.setMode(Thermostat.Mode.IDLE);
} else if (delta.signum() > 0) { } else if (delta.signum() > 0) {
if (t.getState() == Thermostat.ThermostatState.HEATING) return false; if (t.getMode() == Thermostat.Mode.HEATING) return false;
t.setState(Thermostat.ThermostatState.HEATING); t.setMode(Thermostat.Mode.HEATING);
} else { } else {
if (t.getState() == Thermostat.ThermostatState.COOLING) return false; if (t.getMode() == Thermostat.Mode.COOLING) return false;
t.setState(Thermostat.ThermostatState.COOLING); t.setMode(Thermostat.Mode.COOLING);
} }
return true; return true;