Password reset functionality, ZWave switch schedule improvement, support zwave controller on pi, support relay switches and security sensors.

This commit is contained in:
MarkBryanMilligan
2021-07-02 12:06:37 -05:00
parent 6c2b567536
commit de50645a2c
65 changed files with 27104 additions and 438 deletions

View File

@@ -1,21 +1,26 @@
package com.lanternsoftware.datamodel.zwave;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.List;
import java.util.Objects;
@DBSerializable
public class Switch {
private SwitchType type;
private String room;
private String name;
private int nodeId;
private int level;
private int gpioPin;
private boolean primary;
private boolean multilevel;
private boolean hold;
private String thermostatSource;
private boolean hidden;
private String thermometerUrl;
private String controllerUrl;
private ThermostatMode thermostatMode;
private int lowLevel;
private List<SwitchSchedule> schedule;
@@ -23,23 +28,30 @@ public class Switch {
public Switch() {
}
public Switch(String _room, String _name, int _nodeId, boolean _primary, boolean _multilevel, String _thermostatSource, int _lowLevel) {
this(_room, _name, _nodeId, 0, _primary, _multilevel, false, _thermostatSource, _lowLevel, null);
public Switch(String _room, String _name, int _nodeId, boolean _primary, boolean _multilevel, String _thermometerUrl, int _lowLevel) {
this(_room, _name, _nodeId, 0, _primary, false, _thermometerUrl, _lowLevel, null);
}
public Switch(String _room, String _name, int _nodeId, int _level, boolean _primary, boolean _multilevel, boolean _hold, String _thermostatSource, int _lowLevel, List<SwitchSchedule> _schedule) {
public Switch(String _room, String _name, int _nodeId, int _level, boolean _primary, boolean _hold, String _thermometerUrl, int _lowLevel, List<SwitchSchedule> _schedule) {
room = _room;
name = _name;
nodeId = _nodeId;
level = _level;
primary = _primary;
multilevel = _multilevel;
hold = _hold;
thermostatSource = _thermostatSource;
thermometerUrl = _thermometerUrl;
lowLevel = _lowLevel;
schedule = _schedule;
}
public SwitchType getType() {
return type;
}
public void setType(SwitchType _type) {
type = _type;
}
public String getRoom() {
return room;
}
@@ -56,6 +68,12 @@ public class Switch {
name = _name;
}
public String getFullDisplay() {
if (NullUtils.isNotEmpty(room))
return room + " - " + name;
return name;
}
public int getNodeId() {
return nodeId;
}
@@ -72,6 +90,14 @@ public class Switch {
level = _level;
}
public int getGpioPin() {
return gpioPin;
}
public void setGpioPin(int _gpioPin) {
gpioPin = _gpioPin;
}
public boolean isPrimary() {
return primary;
}
@@ -81,11 +107,7 @@ public class Switch {
}
public boolean isMultilevel() {
return multilevel;
}
public void setMultilevel(boolean _multilevel) {
multilevel = _multilevel;
return type == SwitchType.DIMMER;
}
public boolean isHold() {
@@ -96,28 +118,44 @@ public class Switch {
hold = _hold;
}
public String getThermostatSource() {
return thermostatSource;
public String getThermometerUrl() {
return thermometerUrl;
}
public void setThermostatSource(String _thermostatSource) {
thermostatSource = _thermostatSource;
public void setThermometerUrl(String _thermometerUrl) {
thermometerUrl = _thermometerUrl;
}
public String getControllerUrl() {
return controllerUrl;
}
public void setControllerUrl(String _controllerUrl) {
controllerUrl = _controllerUrl;
}
public boolean isThermostat() {
return NullUtils.isNotEmpty(thermostatSource) && (nodeId < 100);
return isSpaceHeaterThermostat() || isZWaveThermostat();
}
public boolean isThermometer() {
return isUrlThermostat() && (nodeId > 99);
public boolean isSpaceHeaterThermostat() {
return type == SwitchType.SPACE_HEATER_THERMOSTAT;
}
public boolean isUrlThermostat() {
return NullUtils.makeNotNull(thermostatSource).startsWith("http");
public boolean isThermometerUrlValid() {
return NullUtils.makeNotNull(thermometerUrl).startsWith("http");
}
public boolean isZWaveThermostat() {
return NullUtils.isEqual(thermostatSource, "ZWAVE");
return type == SwitchType.THERMOSTAT;
}
public boolean isRelay() {
return type == SwitchType.RELAY;
}
public boolean isControlledBy(String _controllerUrl) {
return NullUtils.isEqual(_controllerUrl, controllerUrl);
}
public ThermostatMode getThermostatMode() {
@@ -136,6 +174,14 @@ public class Switch {
lowLevel = _lowLevel;
}
public boolean isHidden() {
return hidden;
}
public void setHidden(boolean _hidden) {
hidden = _hidden;
}
public List<SwitchSchedule> getSchedule() {
return schedule;
}
@@ -143,4 +189,40 @@ public class Switch {
public void setSchedule(List<SwitchSchedule> _schedule) {
schedule = _schedule;
}
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
Switch aSwitch = (Switch) _o;
return nodeId == aSwitch.nodeId;
}
@Override
public int hashCode() {
return Objects.hash(nodeId);
}
public boolean isModified(Switch _switch) {
return (_switch == null) || (level != _switch.getLevel()) || (hold != _switch.isHold()) || (thermostatMode != _switch.getThermostatMode());
}
public Switch duplicate() {
Switch s = new Switch();
s.setType(getType());
s.setRoom(getRoom());
s.setName(getName());
s.setNodeId(getNodeId());
s.setLevel(getLevel());
s.setGpioPin(getGpioPin());
s.setPrimary(isPrimary());
s.setHold(isHold());
s.setHidden(isHidden());
s.setThermometerUrl(getThermometerUrl());
s.setControllerUrl(getControllerUrl());
s.setThermostatMode(getThermostatMode());
s.setLowLevel(getLowLevel());
s.setSchedule(CollectionUtils.transform(getSchedule(), SwitchSchedule::duplicate));
return s;
}
}

View File

@@ -7,20 +7,24 @@ import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Objects;
import java.util.TimeZone;
@DBSerializable
public class SwitchSchedule {
private int dayOfWeek;
private int timeOfDay;
private int minutesPerHour;
private int timeOfDayEnd;
private int onDuration;
private int offDuration;
private int level;
public SwitchSchedule() {
}
public SwitchSchedule(int _minutesPerHour) {
minutesPerHour = _minutesPerHour;
public SwitchSchedule(int _onDuration, int _offDuration) {
onDuration = _onDuration;
offDuration = _offDuration;
}
public SwitchSchedule(int _dayOfWeek, int _timeOfDay, int _level) {
@@ -64,12 +68,34 @@ public class SwitchSchedule {
timeOfDay = (_hour * 3600) + (_minute * 60) + _second;
}
public int getMinutesPerHour() {
return minutesPerHour;
public int getTimeOfDayEnd() {
return timeOfDayEnd;
}
public void setMinutesPerHour(int _minutesPerHour) {
minutesPerHour = _minutesPerHour;
public void setTimeOfDayEnd(int _timeOfDayEnd) {
timeOfDayEnd = _timeOfDayEnd;
}
public void setTimeOfDayEnd(int _hour, int _minute) {
timeOfDayEnd = (_hour * 3600) + (_minute * 60);
}
public void setTimeOfDayEnd(int _hour, int _minute, int _second) {
timeOfDayEnd = (_hour * 3600) + (_minute * 60) + _second;
}
public int getOnDuration() {
return onDuration;
}
public void setOnDuration(int _onDuration) {
onDuration = _onDuration;
}
public int getOffDuration() {
return offDuration;
}
public void setOffDuration(int _offDuration) {
offDuration = _offDuration;
}
public int getLevel() {
@@ -81,38 +107,88 @@ public class SwitchSchedule {
}
public int hour() {
return timeOfDay/3600;
return hour(timeOfDay);
}
public int minute() {
return (timeOfDay/60)%60;
return minute(timeOfDay);
}
public int second() {
return timeOfDay%60;
return second(timeOfDay);
}
private boolean isOn() {
return GregorianCalendar.getInstance().get(Calendar.MINUTE) < minutesPerHour;
public int hour(int _timeOfDay) {
return _timeOfDay/3600;
}
public int minute(int _timeOfDay) {
return (_timeOfDay/60)%60;
}
public int second(int _timeOfDay) {
return _timeOfDay%60;
}
public Date startToday(TimeZone _tz) {
return today(timeOfDay, _tz);
}
public Date endToday(TimeZone _tz) {
return today(timeOfDayEnd, _tz);
}
public Date today(int _timeOfDay, TimeZone _tz) {
Date now = new Date();
Calendar cal = DateUtils.toCalendar(now, _tz);
if (dayOfWeek > 0)
cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
cal.set(Calendar.HOUR_OF_DAY, hour(_timeOfDay));
cal.set(Calendar.MINUTE, minute(_timeOfDay));
cal.set(Calendar.SECOND, second(_timeOfDay));
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
public SwitchTransition getNextTransition(Switch _switch, TimeZone _tz) {
if (minutesPerHour > 0) {
Date dt = DateUtils.getStartOfHour(_tz);
Date transition = DateUtils.addMinutes(dt, minutesPerHour);
if (new Date().before(transition))
return new SwitchTransition(_switch, transition, 0);
return new SwitchTransition(_switch, DateUtils.getEndOfHour(_tz), level == 0?255:level);
}
Date startToday = startToday(_tz);
Date now = new Date();
Calendar cal = DateUtils.toCalendar(now, _tz);
cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
cal.set(Calendar.HOUR_OF_DAY, hour());
cal.set(Calendar.MINUTE, minute());
cal.set(Calendar.SECOND, second());
cal.set(Calendar.MILLISECOND, 0);
if (cal.getTimeInMillis() <= now.getTime())
cal.add(Calendar.DAY_OF_MONTH, 7);
return new SwitchTransition(_switch, cal.getTime(), level);
if (onDuration > 0) {
if ((timeOfDay > 0) && now.before(startToday))
now = startToday;
if (timeOfDayEnd > 0) {
if (now.after(endToday(_tz)))
now = DateUtils.addDays(startToday, (dayOfWeek > 0)?7:1, _tz);
}
long progress = now.getTime()%((onDuration+offDuration)*1000L);
if (progress < onDuration*1000L)
return new SwitchTransition(_switch, new Date(now.getTime() + (onDuration*1000L)-progress), 0);
return new SwitchTransition(_switch, new Date(now.getTime()+((onDuration+offDuration)*1000L)-progress), level == 0 ? 255 : level);
}
return new SwitchTransition(_switch, startToday.after(now)?startToday:DateUtils.addDays(startToday, (dayOfWeek > 0)?7:1, _tz), level);
}
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
SwitchSchedule that = (SwitchSchedule) _o;
return dayOfWeek == that.dayOfWeek && timeOfDay == that.timeOfDay && timeOfDayEnd == that.timeOfDayEnd && onDuration == that.onDuration && offDuration == that.offDuration && level == that.level;
}
@Override
public int hashCode() {
return Objects.hash(dayOfWeek, timeOfDay, timeOfDayEnd, onDuration, offDuration, level);
}
public SwitchSchedule duplicate() {
SwitchSchedule s = new SwitchSchedule();
s.setDayOfWeek(getDayOfWeek());
s.setTimeOfDay(getTimeOfDay());
s.setTimeOfDayEnd(getTimeOfDayEnd());
s.setOnDuration(getOnDuration());
s.setOffDuration(getOffDuration());
s.setLevel(getLevel());
return s;
}
}

View File

@@ -0,0 +1,11 @@
package com.lanternsoftware.datamodel.zwave;
public enum SwitchType {
BINARY,
DIMMER,
THERMOSTAT,
SPACE_HEATER_THERMOSTAT,
THERMOMETER,
RELAY,
SECURITY
}

View File

@@ -1,5 +1,7 @@
package com.lanternsoftware.datamodel.zwave;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
@@ -7,8 +9,10 @@ import java.util.List;
@DBSerializable(autogen = false)
public class ZWaveConfig {
@PrimaryKey
private int accountId;
@PrimaryKey private int accountId;
private String commPort;
private String url;
private String masterUrl;
private List<Switch> switches;
public int getAccountId() {
@@ -19,6 +23,30 @@ public class ZWaveConfig {
accountId = _accountId;
}
public String getCommPort() {
return commPort;
}
public void setCommPort(String _commPort) {
commPort = _commPort;
}
public String getUrl() {
return url;
}
public void setUrl(String _url) {
url = _url;
}
public String getMasterUrl() {
return masterUrl;
}
public void setMasterUrl(String _masterUrl) {
masterUrl = _masterUrl;
}
public List<Switch> getSwitches() {
return switches;
}
@@ -26,4 +54,16 @@ public class ZWaveConfig {
public void setSwitches(List<Switch> _switches) {
switches = _switches;
}
public boolean isMaster() {
return NullUtils.isEqual(url, masterUrl);
}
public List<Switch> getSwitchesForThisController() {
return CollectionUtils.filter(switches, this::isMySwitch);
}
public boolean isMySwitch(Switch _sw) {
return (isMaster() && NullUtils.isEmpty(_sw.getControllerUrl())) || _sw.isControlledBy(getUrl());
}
}

View File

@@ -5,7 +5,6 @@ import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
@@ -28,7 +27,9 @@ public class SwitchScheduleSerializer extends AbstractDaoSerializer<SwitchSchedu
DaoEntity d = new DaoEntity();
d.put("day_of_week", _o.getDayOfWeek());
d.put("time_of_day", _o.getTimeOfDay());
d.put("minutes_per_hour", _o.getMinutesPerHour());
d.put("time_of_day_end", _o.getTimeOfDayEnd());
d.put("on_duration", _o.getOnDuration());
d.put("off_duration", _o.getOffDuration());
d.put("level", _o.getLevel());
return d;
}
@@ -39,7 +40,9 @@ public class SwitchScheduleSerializer extends AbstractDaoSerializer<SwitchSchedu
SwitchSchedule o = new SwitchSchedule();
o.setDayOfWeek(DaoSerializer.getInteger(_d, "day_of_week"));
o.setTimeOfDay(DaoSerializer.getInteger(_d, "time_of_day"));
o.setMinutesPerHour(DaoSerializer.getInteger(_d, "minutes_per_hour"));
o.setTimeOfDayEnd(DaoSerializer.getInteger(_d, "time_of_day_end"));
o.setOnDuration(DaoSerializer.getInteger(_d, "on_duration"));
o.setOffDuration(DaoSerializer.getInteger(_d, "off_duration"));
o.setLevel(DaoSerializer.getInteger(_d, "level"));
return o;
}

View File

@@ -2,12 +2,12 @@ package com.lanternsoftware.datamodel.zwave.dao;
import com.lanternsoftware.datamodel.zwave.Switch;
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
import com.lanternsoftware.datamodel.zwave.SwitchType;
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
@@ -28,16 +28,19 @@ public class SwitchSerializer extends AbstractDaoSerializer<Switch>
public DaoEntity toDaoEntity(Switch _o)
{
DaoEntity d = new DaoEntity();
d.put("type", DaoSerializer.toEnumName(_o.getType()));
d.put("room", _o.getRoom());
d.put("name", _o.getName());
d.put("node_id", _o.getNodeId());
d.put("level", _o.getLevel());
d.put("gpio_pin", _o.getGpioPin());
d.put("primary", _o.isPrimary());
d.put("multilevel", _o.isMultilevel());
d.put("hold", _o.isHold());
d.put("thermostat_source", _o.getThermostatSource());
d.put("thermometer_url", _o.getThermometerUrl());
d.put("controller_url", _o.getControllerUrl());
d.put("thermostat_mode", DaoSerializer.toEnumName(_o.getThermostatMode()));
d.put("low_level", _o.getLowLevel());
d.put("hidden", _o.isHidden());
d.put("schedule", DaoSerializer.toDaoEntities(_o.getSchedule(), DaoProxyType.MONGO));
return d;
}
@@ -46,16 +49,19 @@ public class SwitchSerializer extends AbstractDaoSerializer<Switch>
public Switch fromDaoEntity(DaoEntity _d)
{
Switch o = new Switch();
o.setType(DaoSerializer.getEnum(_d, "type", SwitchType.class));
o.setRoom(DaoSerializer.getString(_d, "room"));
o.setName(DaoSerializer.getString(_d, "name"));
o.setNodeId(DaoSerializer.getInteger(_d, "node_id"));
o.setLevel(DaoSerializer.getInteger(_d, "level"));
o.setGpioPin(DaoSerializer.getInteger(_d, "gpio_pin"));
o.setPrimary(DaoSerializer.getBoolean(_d, "primary"));
o.setMultilevel(DaoSerializer.getBoolean(_d, "multilevel"));
o.setHold(DaoSerializer.getBoolean(_d, "hold"));
o.setThermostatSource(DaoSerializer.getString(_d, "thermostat_source"));
o.setThermometerUrl(DaoSerializer.getString(_d, "thermometer_url"));
o.setControllerUrl(DaoSerializer.getString(_d, "controller_url"));
o.setThermostatMode(DaoSerializer.getEnum(_d, "thermostat_mode", ThermostatMode.class));
o.setLowLevel(DaoSerializer.getInteger(_d, "low_level"));
o.setHidden(DaoSerializer.getBoolean(_d, "hidden"));
o.setSchedule(DaoSerializer.getList(_d, "schedule", SwitchSchedule.class));
return o;
}

View File

@@ -28,6 +28,9 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer<ZWaveConfig>
{
DaoEntity d = new DaoEntity();
d.put("_id", String.valueOf(_o.getAccountId()));
d.put("comm_port", _o.getCommPort());
d.put("url", _o.getUrl());
d.put("master_url", _o.getMasterUrl());
d.put("switches", DaoSerializer.toDaoEntities(_o.getSwitches(), DaoProxyType.MONGO));
return d;
}
@@ -37,6 +40,9 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer<ZWaveConfig>
{
ZWaveConfig o = new ZWaveConfig();
o.setAccountId(DaoSerializer.getInteger(_d, "_id"));
o.setCommPort(DaoSerializer.getString(_d, "comm_port"));
o.setUrl(DaoSerializer.getString(_d, "url"));
o.setMasterUrl(DaoSerializer.getString(_d, "master_url"));
o.setSwitches(DaoSerializer.getList(_d, "switches", Switch.class));
return o;
}