mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Initial Commit
This commit is contained in:
73
zwave/lantern-datamodel-zwave/pom.xml
Normal file
73
zwave/lantern-datamodel-zwave/pom.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.services</groupId>
|
||||
<artifactId>lantern-datamodel-zwave</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-datamodel-zwave</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-dao</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<index>true</index>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.lanternsoftware.datamodel.zwave;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@DBSerializable
|
||||
public class Switch {
|
||||
private String room;
|
||||
private String name;
|
||||
private int nodeId;
|
||||
private int level;
|
||||
private boolean primary;
|
||||
private boolean multilevel;
|
||||
private boolean hold;
|
||||
private String thermostatSource;
|
||||
private ThermostatMode thermostatMode;
|
||||
private int lowLevel;
|
||||
private List<SwitchSchedule> schedule;
|
||||
|
||||
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, int _level, boolean _primary, boolean _multilevel, boolean _hold, String _thermostatSource, int _lowLevel, List<SwitchSchedule> _schedule) {
|
||||
room = _room;
|
||||
name = _name;
|
||||
nodeId = _nodeId;
|
||||
level = _level;
|
||||
primary = _primary;
|
||||
multilevel = _multilevel;
|
||||
hold = _hold;
|
||||
thermostatSource = _thermostatSource;
|
||||
lowLevel = _lowLevel;
|
||||
schedule = _schedule;
|
||||
}
|
||||
|
||||
public String getRoom() {
|
||||
return room;
|
||||
}
|
||||
|
||||
public void setRoom(String _room) {
|
||||
room = _room;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String _name) {
|
||||
name = _name;
|
||||
}
|
||||
|
||||
public int getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(int _nodeId) {
|
||||
nodeId = _nodeId;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int _level) {
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public boolean isPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(boolean _primary) {
|
||||
primary = _primary;
|
||||
}
|
||||
|
||||
public boolean isMultilevel() {
|
||||
return multilevel;
|
||||
}
|
||||
|
||||
public void setMultilevel(boolean _multilevel) {
|
||||
multilevel = _multilevel;
|
||||
}
|
||||
|
||||
public boolean isHold() {
|
||||
return hold;
|
||||
}
|
||||
|
||||
public void setHold(boolean _hold) {
|
||||
hold = _hold;
|
||||
}
|
||||
|
||||
public String getThermostatSource() {
|
||||
return thermostatSource;
|
||||
}
|
||||
|
||||
public void setThermostatSource(String _thermostatSource) {
|
||||
thermostatSource = _thermostatSource;
|
||||
}
|
||||
|
||||
public boolean isThermostat() {
|
||||
return NullUtils.isNotEmpty(thermostatSource) && (nodeId < 100);
|
||||
}
|
||||
|
||||
public boolean isThermometer() {
|
||||
return isUrlThermostat() && (nodeId > 99);
|
||||
}
|
||||
|
||||
public boolean isUrlThermostat() {
|
||||
return NullUtils.makeNotNull(thermostatSource).startsWith("http");
|
||||
}
|
||||
|
||||
public boolean isZWaveThermostat() {
|
||||
return NullUtils.isEqual(thermostatSource, "ZWAVE");
|
||||
}
|
||||
|
||||
public ThermostatMode getThermostatMode() {
|
||||
return thermostatMode;
|
||||
}
|
||||
|
||||
public void setThermostatMode(ThermostatMode _thermostatMode) {
|
||||
thermostatMode = _thermostatMode;
|
||||
}
|
||||
|
||||
public int getLowLevel() {
|
||||
return lowLevel;
|
||||
}
|
||||
|
||||
public void setLowLevel(int _lowLevel) {
|
||||
lowLevel = _lowLevel;
|
||||
}
|
||||
|
||||
public List<SwitchSchedule> getSchedule() {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
public void setSchedule(List<SwitchSchedule> _schedule) {
|
||||
schedule = _schedule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.lanternsoftware.datamodel.zwave;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@DBSerializable
|
||||
public class SwitchSchedule {
|
||||
private int dayOfWeek;
|
||||
private int timeOfDay;
|
||||
private int minutesPerHour;
|
||||
private int level;
|
||||
|
||||
public SwitchSchedule() {
|
||||
}
|
||||
|
||||
public SwitchSchedule(int _minutesPerHour) {
|
||||
minutesPerHour = _minutesPerHour;
|
||||
}
|
||||
|
||||
public SwitchSchedule(int _dayOfWeek, int _timeOfDay, int _level) {
|
||||
dayOfWeek = _dayOfWeek;
|
||||
timeOfDay = _timeOfDay;
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public SwitchSchedule(int _dayOfWeek, int _hour, int _minute, int _level) {
|
||||
dayOfWeek = _dayOfWeek;
|
||||
setTimeOfDay(_hour, _minute);
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public SwitchSchedule(int _dayOfWeek, int _hour, int _minute, int _second, int _level) {
|
||||
dayOfWeek = _dayOfWeek;
|
||||
setTimeOfDay(_hour, _minute, _second);
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public int getDayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
public void setDayOfWeek(int _dayOfWeek) {
|
||||
dayOfWeek = _dayOfWeek;
|
||||
}
|
||||
|
||||
public int getTimeOfDay() {
|
||||
return timeOfDay;
|
||||
}
|
||||
|
||||
public void setTimeOfDay(int _timeOfDayInSeconds) {
|
||||
timeOfDay = _timeOfDayInSeconds;
|
||||
}
|
||||
|
||||
public void setTimeOfDay(int _hour, int _minute) {
|
||||
timeOfDay = (_hour * 3600) + (_minute * 60);
|
||||
}
|
||||
public void setTimeOfDay(int _hour, int _minute, int _second) {
|
||||
timeOfDay = (_hour * 3600) + (_minute * 60) + _second;
|
||||
}
|
||||
|
||||
public int getMinutesPerHour() {
|
||||
return minutesPerHour;
|
||||
}
|
||||
|
||||
public void setMinutesPerHour(int _minutesPerHour) {
|
||||
minutesPerHour = _minutesPerHour;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int _level) {
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public int hour() {
|
||||
return timeOfDay/3600;
|
||||
}
|
||||
|
||||
public int minute() {
|
||||
return (timeOfDay/60)%60;
|
||||
}
|
||||
|
||||
public int second() {
|
||||
return timeOfDay%60;
|
||||
}
|
||||
|
||||
private boolean isOn() {
|
||||
return GregorianCalendar.getInstance().get(Calendar.MINUTE) < minutesPerHour;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.lanternsoftware.datamodel.zwave;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class SwitchTransition {
|
||||
private final Switch sw;
|
||||
private final Date transitionTime;
|
||||
private final int level;
|
||||
|
||||
SwitchTransition(Switch _sw, Date _transitionTime, int _level) {
|
||||
sw = _sw;
|
||||
transitionTime = _transitionTime;
|
||||
level = _level;
|
||||
}
|
||||
|
||||
public Switch getSwitch() {
|
||||
return sw;
|
||||
}
|
||||
|
||||
public Date getTransitionTime() {
|
||||
return transitionTime;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.lanternsoftware.datamodel.zwave;
|
||||
|
||||
public enum ThermostatMode {
|
||||
OFF((byte)0, "Off"),
|
||||
HEAT((byte)1, "Heat"),
|
||||
COOL((byte)2, "Cool"),
|
||||
AUXILIARY((byte)4, "E-Heat");
|
||||
|
||||
public final byte data;
|
||||
public final String display;
|
||||
|
||||
ThermostatMode(byte _data, String _display) {
|
||||
data = _data;
|
||||
display = _display;
|
||||
}
|
||||
|
||||
public static ThermostatMode fromByte(byte _bt) {
|
||||
for (ThermostatMode mode : values()) {
|
||||
if (mode.data == _bt)
|
||||
return mode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.lanternsoftware.datamodel.zwave;
|
||||
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@DBSerializable(autogen = false)
|
||||
public class ZWaveConfig {
|
||||
@PrimaryKey
|
||||
private int accountId;
|
||||
private List<Switch> switches;
|
||||
|
||||
public int getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(int _accountId) {
|
||||
accountId = _accountId;
|
||||
}
|
||||
|
||||
public List<Switch> getSwitches() {
|
||||
return switches;
|
||||
}
|
||||
|
||||
public void setSwitches(List<Switch> _switches) {
|
||||
switches = _switches;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.lanternsoftware.datamodel.zwave.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||
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;
|
||||
|
||||
public class SwitchScheduleSerializer extends AbstractDaoSerializer<SwitchSchedule>
|
||||
{
|
||||
@Override
|
||||
public Class<SwitchSchedule> getSupportedClass()
|
||||
{
|
||||
return SwitchSchedule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(SwitchSchedule _o)
|
||||
{
|
||||
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("level", _o.getLevel());
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwitchSchedule fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
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.setLevel(DaoSerializer.getInteger(_d, "level"));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.lanternsoftware.datamodel.zwave.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||
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;
|
||||
|
||||
public class SwitchSerializer extends AbstractDaoSerializer<Switch>
|
||||
{
|
||||
@Override
|
||||
public Class<Switch> getSupportedClass()
|
||||
{
|
||||
return Switch.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(Switch _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("room", _o.getRoom());
|
||||
d.put("name", _o.getName());
|
||||
d.put("node_id", _o.getNodeId());
|
||||
d.put("level", _o.getLevel());
|
||||
d.put("primary", _o.isPrimary());
|
||||
d.put("multilevel", _o.isMultilevel());
|
||||
d.put("hold", _o.isHold());
|
||||
d.put("thermostat_source", _o.getThermostatSource());
|
||||
d.put("thermostat_mode", DaoSerializer.toEnumName(_o.getThermostatMode()));
|
||||
d.put("low_level", _o.getLowLevel());
|
||||
d.put("schedule", DaoSerializer.toDaoEntities(_o.getSchedule(), DaoProxyType.MONGO));
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Switch fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
Switch o = new Switch();
|
||||
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.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.setThermostatMode(DaoSerializer.getEnum(_d, "thermostat_mode", ThermostatMode.class));
|
||||
o.setLowLevel(DaoSerializer.getInteger(_d, "low_level"));
|
||||
o.setSchedule(DaoSerializer.getList(_d, "schedule", SwitchSchedule.class));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.lanternsoftware.datamodel.zwave.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
||||
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;
|
||||
|
||||
public class ZWaveConfigSerializer extends AbstractDaoSerializer<ZWaveConfig>
|
||||
{
|
||||
@Override
|
||||
public Class<ZWaveConfig> getSupportedClass()
|
||||
{
|
||||
return ZWaveConfig.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(ZWaveConfig _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("_id", String.valueOf(_o.getAccountId()));
|
||||
d.put("switches", DaoSerializer.toDaoEntities(_o.getSwitches(), DaoProxyType.MONGO));
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZWaveConfig fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
ZWaveConfig o = new ZWaveConfig();
|
||||
o.setAccountId(DaoSerializer.getInteger(_d, "_id"));
|
||||
o.setSwitches(DaoSerializer.getList(_d, "switches", Switch.class));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
com.lanternsoftware.datamodel.zwave.dao.SwitchScheduleSerializer
|
||||
com.lanternsoftware.datamodel.zwave.dao.SwitchSerializer
|
||||
com.lanternsoftware.datamodel.zwave.dao.ZWaveConfigSerializer
|
||||
79
zwave/lantern-service-thermometer/pom.xml
Normal file
79
zwave/lantern-service-thermometer/pom.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.thermometer</groupId>
|
||||
<artifactId>lantern-service-thermometer</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-service-thermometer</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-api</artifactId>
|
||||
<version>8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hid4java</groupId>
|
||||
<artifactId>hid4java</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.lanternsoftware.thermometer;
|
||||
|
||||
import com.lanternsoftware.thermometer.context.ThermometerApp;
|
||||
|
||||
public class TestThermo {
|
||||
public static void main(String[] args) {
|
||||
ThermometerApp app = new ThermometerApp();
|
||||
app.start();
|
||||
try {
|
||||
Thread.sleep(20000);
|
||||
} catch (InterruptedException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
app.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.lanternsoftware.thermometer.context;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
public class Globals implements ServletContextListener {
|
||||
public static ThermometerApp app;
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
app = new ThermometerApp();
|
||||
app.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
if (app != null) {
|
||||
app.stop();
|
||||
app = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.lanternsoftware.thermometer.context;
|
||||
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||
import org.hid4java.HidDevice;
|
||||
import org.hid4java.HidManager;
|
||||
import org.hid4java.HidServices;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class ThermometerApp {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ThermometerApp.class);
|
||||
|
||||
private HidDevice device;
|
||||
private final Timer timer = new Timer();
|
||||
private double lastTemp;
|
||||
|
||||
public void start() {
|
||||
HidServices hs = HidManager.getHidServices();
|
||||
for (HidDevice d : hs.getAttachedHidDevices()) {
|
||||
if (NullUtils.isEqual(d.getVendorId(), (short) 0x413d) && NullUtils.isEqual(d.getProductId(), (short) 0x2107)) {
|
||||
if (d.getInterfaceNumber() == 1)
|
||||
device = d;
|
||||
}
|
||||
}
|
||||
if ((device != null) && device.open()) {
|
||||
synchronized (device) {
|
||||
read(hexToByte("0182770100000000"));
|
||||
read(hexToByte("0186ff0100000000"));
|
||||
read(hexToByte("0182770100000000"));
|
||||
read(hexToByte("0182770100000000"));
|
||||
}
|
||||
} else {
|
||||
LOG.error("Failed to open HID Device");
|
||||
return;
|
||||
}
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
lastTemp = readTemperature();
|
||||
}
|
||||
}, 0L, 10000L);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
timer.cancel();
|
||||
ConcurrencyUtils.sleep(10000);
|
||||
if (device != null) {
|
||||
device.close();
|
||||
device = null;
|
||||
}
|
||||
HidServices hs = HidManager.getHidServices();
|
||||
hs.stop();
|
||||
hs.shutdown();
|
||||
}
|
||||
|
||||
private byte[] read(byte[] _request) {
|
||||
int RETRIES = 8;
|
||||
int stat = -1;
|
||||
int attempts = 0;
|
||||
while ((stat <= 0) && (attempts < RETRIES)) {
|
||||
attempts++;
|
||||
try {
|
||||
stat = device.write(_request, _request.length*8, (byte) 0);
|
||||
}
|
||||
catch (Exception _e) {
|
||||
LOG.error("Exception while writing", _e);
|
||||
}
|
||||
if (stat <= 0) {
|
||||
if (attempts == RETRIES) {
|
||||
LOG.error("Failed max number of retires, returning null");
|
||||
return null;
|
||||
}
|
||||
LOG.error("Write attempt " + attempts + " failed, waiting 250ms to retry");
|
||||
ConcurrencyUtils.sleep(250);
|
||||
}
|
||||
}
|
||||
byte[] response = new byte[32];
|
||||
stat = -1;
|
||||
attempts = 0;
|
||||
while ((stat <= 0) && (attempts < RETRIES)) {
|
||||
attempts++;
|
||||
try {
|
||||
stat = device.read(response, 500);
|
||||
}
|
||||
catch (Exception _e) {
|
||||
LOG.error("Exception while reading", _e);
|
||||
}
|
||||
if (stat <= 0) {
|
||||
if (attempts == RETRIES) {
|
||||
LOG.error("Failed max number of retires, returning null");
|
||||
return null;
|
||||
}
|
||||
LOG.error("Read attempt " + attempts + " failed, waiting 250ms to retry");
|
||||
ConcurrencyUtils.sleep(250);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
public double getTemperature() {
|
||||
return lastTemp;
|
||||
}
|
||||
|
||||
public double readTemperature() {
|
||||
if (device != null) {
|
||||
synchronized (device) {
|
||||
byte[] response = read(hexToByte("0180330100000000"));
|
||||
if (response == null)
|
||||
return 5.0;
|
||||
int rawReading = ((response[3] & 0xFF) + (response[2] << 8));
|
||||
if (rawReading == 0)
|
||||
return 5.0;
|
||||
return rawReading / 100.0;
|
||||
}
|
||||
|
||||
}
|
||||
return 5.0;
|
||||
}
|
||||
|
||||
private static byte[] hexToByte(String s) {
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.lanternsoftware.thermometer.servlet;
|
||||
|
||||
import com.lanternsoftware.thermometer.context.Globals;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@WebServlet("/temp")
|
||||
public class TempServlet extends ThermoServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
setResponseEntity(resp, "application/json", "{\"temp\": "+ Globals.app.getTemperature() + "}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.lanternsoftware.thermometer.servlet;
|
||||
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public abstract class ThermoServlet extends HttpServlet {
|
||||
public static void setResponseHtml(HttpServletResponse _response, String _sHtml) {
|
||||
setResponseEntity(_response, "text/html", _sHtml);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) {
|
||||
setResponseEntity(_response, 200, _sContentType, _sEntity);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) {
|
||||
setResponseEntity(_response, 200, _sContentType, _btData);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) {
|
||||
setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity));
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) {
|
||||
OutputStream os = null;
|
||||
try {
|
||||
_response.setStatus(_iStatus);
|
||||
_response.setCharacterEncoding("UTF-8");
|
||||
_response.setContentType(_sContentType);
|
||||
if ((_btData != null) && (_btData.length > 0)) {
|
||||
_response.setContentLength(_btData.length);
|
||||
os = _response.getOutputStream();
|
||||
os.write(_btData);
|
||||
} else
|
||||
_response.setContentLength(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>/opt/currentmonitor/log/log.txt</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>/opt/currentmonitor/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
||||
<maxFileSize>20MB</maxFileSize>
|
||||
<maxHistory>20</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lanternsoftware" level="INFO"/>
|
||||
|
||||
<root level="OFF">
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE web-app PUBLIC
|
||||
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
||||
|
||||
<web-app>
|
||||
<listener>
|
||||
<listener-class>com.lanternsoftware.thermometer.context.Globals</listener-class>
|
||||
</listener>
|
||||
</web-app>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.lanternsoftware.thermometer;
|
||||
|
||||
import com.lanternsoftware.thermometer.context.ThermometerApp;
|
||||
|
||||
public class TestStartup {
|
||||
public static void main(String[] args) {
|
||||
ThermometerApp app = new ThermometerApp();
|
||||
app.start();
|
||||
try {
|
||||
Thread.sleep(20000);
|
||||
} catch (InterruptedException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
app.stop();
|
||||
}
|
||||
}
|
||||
94
zwave/lantern-service-zwave/pom.xml
Normal file
94
zwave/lantern-service-zwave/pom.xml
Normal file
@@ -0,0 +1,94 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.zwave</groupId>
|
||||
<artifactId>lantern-service-zwave</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-service-zwave</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.services</groupId>
|
||||
<artifactId>lantern-datamodel-zwave</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||
<artifactId>lantern-dataaccess-currentmonitor</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.zwave</groupId>
|
||||
<artifactId>lantern-zwave</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-dao-mongo</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-http</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-api</artifactId>
|
||||
<version>8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.lanternsoftware.zwave.context;
|
||||
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
public class Globals implements ServletContextListener {
|
||||
public static ZWaveApp app;
|
||||
public static MongoCurrentMonitorDao cmDao;
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
cmDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
app = new ZWaveApp();
|
||||
app.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
if (app != null) {
|
||||
app.stop();
|
||||
app = null;
|
||||
}
|
||||
if (cmDao != null)
|
||||
cmDao.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
package com.lanternsoftware.zwave.context;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchTransition;
|
||||
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
||||
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import com.lanternsoftware.util.http.HttpPool;
|
||||
import com.lanternsoftware.zwave.controller.Controller;
|
||||
import com.lanternsoftware.zwave.dao.MongoZWaveDao;
|
||||
import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
||||
import com.lanternsoftware.zwave.message.MessageEngine;
|
||||
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.MultilevelSensorGetRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.MultilevelSensorReportRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.MultilevelSwitchReportRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.MultilevelSwitchSetRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.ThermostatModeSetRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointReportRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointSetRequest;
|
||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class ZWaveApp {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZWaveApp.class);
|
||||
|
||||
private MongoZWaveDao dao;
|
||||
private ZWaveConfig config;
|
||||
private Controller controller;
|
||||
private final Map<Integer, Switch> switches = new HashMap<>();
|
||||
private final Map<Integer, List<Integer>> peers = new HashMap<>();
|
||||
private Timer timer;
|
||||
private HttpPool pool;
|
||||
private SwitchScheduleTask nextScheduleTask;
|
||||
private final Map<Integer, Double> temperatures = new HashMap<>();
|
||||
private final Object ZWAVE_MUTEX = new Object();
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
dao = new MongoZWaveDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
controller = new Controller();
|
||||
controller.start("COM4");
|
||||
timer = new Timer("ZWaveApp Timer");
|
||||
pool = new HttpPool(10, 10, 30000, 10000, 10000);
|
||||
|
||||
//// for (int node = 3; node < 7; node++) {
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 7, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 8, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 9, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 10, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 11, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 12, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// }
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
config = dao.getConfig(1);
|
||||
Map<String, List<Integer>> groups = new HashMap<>();
|
||||
for (Switch sw : CollectionUtils.makeNotNull(config.getSwitches())) {
|
||||
switches.put(sw.getNodeId(), sw);
|
||||
CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw.getNodeId(), groups);
|
||||
}
|
||||
if (CollectionUtils.filterOne(config.getSwitches(), Switch::isUrlThermostat) != null) {
|
||||
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
|
||||
}
|
||||
for (List<Integer> group : groups.values()) {
|
||||
for (Integer node : group) {
|
||||
peers.put(node, CollectionUtils.filter(group, _i -> !_i.equals(node)));
|
||||
}
|
||||
}
|
||||
scheduleNextTransition();
|
||||
|
||||
MessageEngine.subscribe(new IMessageSubscriber<MultilevelSensorReportRequest>() {
|
||||
@Override
|
||||
public Class<MultilevelSensorReportRequest> getHandledMessageClass() {
|
||||
return MultilevelSensorReportRequest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(MultilevelSensorReportRequest _message) {
|
||||
synchronized (temperatures) {
|
||||
temperatures.put((int) _message.getNodeId(), _message.getTemperatureCelsius());
|
||||
temperatures.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MessageEngine.subscribe(new IMessageSubscriber<ThermostatSetPointReportRequest>() {
|
||||
@Override
|
||||
public Class<ThermostatSetPointReportRequest> getHandledMessageClass() {
|
||||
return ThermostatSetPointReportRequest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ThermostatSetPointReportRequest _message) {
|
||||
synchronized (switches) {
|
||||
Switch sw = switches.get((int) _message.getNodeId());
|
||||
if (sw != null) {
|
||||
if (NullUtils.isOneOf(_message.getIndex(), ThermostatSetPointIndex.HEATING, ThermostatSetPointIndex.COOLING)) {
|
||||
sw.setLevel((int) Math.round(_message.getTemperatureCelsius() * 1.8) + 32);
|
||||
persistConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MessageEngine.subscribe(new IMessageSubscriber<MultilevelSwitchReportRequest>() {
|
||||
@Override
|
||||
public Class<MultilevelSwitchReportRequest> getHandledMessageClass() {
|
||||
return MultilevelSwitchReportRequest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(MultilevelSwitchReportRequest _message) {
|
||||
synchronized (switches) {
|
||||
Switch sw = switches.get((int) _message.getNodeId());
|
||||
if (sw != null) {
|
||||
sw.setLevel(_message.getLevel());
|
||||
for (Integer node : CollectionUtils.makeNotNull(peers.get((int) _message.getNodeId()))) {
|
||||
sw = switches.get(node);
|
||||
sw.setLevel(_message.getLevel());
|
||||
logger.info("Mirror Event from node {} to node {}", _message.getNodeId(), node);
|
||||
controller.send(new MultilevelSwitchSetRequest(node.byteValue(), _message.getLevel()));
|
||||
}
|
||||
persistConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// controller.send(new MultilevelSensorGetRequest((byte)11));
|
||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING));
|
||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING));
|
||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING_ECON));
|
||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING_ECON));
|
||||
// controller.send(new ThermostatSetPointSupportedGetRequest((byte)11));
|
||||
// controller.send(new ThermostatSetPointCapabilitiesGetRequest((byte)11));
|
||||
// controller.send(new ThermostatSetPointSetRequest((byte)11, ThermostatSetPointIndex.HEATING_ECON, 72));
|
||||
// controller.send(new ThermostatModeSetRequest((byte)11, ThermostatMode.HEAT));
|
||||
// controller.send(new ThermostatModeGetRequest((byte)11));
|
||||
}
|
||||
|
||||
private void scheduleNextTransition() {
|
||||
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
||||
if (nextScheduleTask != null)
|
||||
nextScheduleTask.cancel();
|
||||
List<SwitchTransition> nextTransitions = CollectionUtils.getAllSmallest(CollectionUtils.aggregate(switches.values(), _s->CollectionUtils.transform(_s.getSchedule(), _t->_t.getNextTransition(_s, tz))), Comparator.comparing(SwitchTransition::getTransitionTime));
|
||||
if (!CollectionUtils.isEmpty(nextTransitions)) {
|
||||
for (SwitchTransition tr : nextTransitions) {
|
||||
logger.info("Next transition scheduled for node {} to level {} at {}", tr.getSwitch().getNodeId(), tr.getLevel(), DateUtils.format("hh:mm:ssa", tz, tr.getTransitionTime()));
|
||||
}
|
||||
nextScheduleTask = new SwitchScheduleTask(nextTransitions);
|
||||
timer.schedule(nextScheduleTask, CollectionUtils.getFirst(nextTransitions).getTransitionTime());
|
||||
} else
|
||||
nextScheduleTask = null;
|
||||
}
|
||||
|
||||
public void setSwitchLevel(int _nodeId, int _level) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setLevel(_level);
|
||||
if (!sw.isThermostat()) {
|
||||
setGroupSwitchLevel(_nodeId, _level, sw.isMultilevel());
|
||||
} else if (sw.isZWaveThermostat()) {
|
||||
controller.send(new ThermostatSetPointSetRequest((byte) sw.getNodeId(), sw.getThermostatMode() == ThermostatMode.COOL ? ThermostatSetPointIndex.COOLING : ThermostatSetPointIndex.HEATING, _level));
|
||||
} else {
|
||||
if (timer != null)
|
||||
timer.schedule(new ThermostatTask(), 0);
|
||||
persistConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public void setThermostatMode(int _nodeId, ThermostatMode _mode) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary() || !sw.isZWaveThermostat())
|
||||
return;
|
||||
controller.send(new ThermostatModeSetRequest((byte) sw.getNodeId(), com.lanternsoftware.zwave.message.thermostat.ThermostatMode.fromByte(_mode.data)));
|
||||
sw.setThermostatMode(_mode);
|
||||
persistConfig();
|
||||
}
|
||||
|
||||
public void setSwitchSchedule(int _nodeId, List<SwitchSchedule> _transitions) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setSchedule(_transitions);
|
||||
persistConfig();
|
||||
scheduleNextTransition();
|
||||
}
|
||||
|
||||
public void setSwitchHold(int _nodeId, boolean _hold) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setHold(_hold);
|
||||
persistConfig();
|
||||
}
|
||||
|
||||
private void persistConfig() {
|
||||
synchronized (this) {
|
||||
dao.putConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSwitchLevel(int _nodeId) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
return (sw != null) ? sw.getLevel() : 0;
|
||||
}
|
||||
|
||||
public ZWaveConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
controller.stop();
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
if (pool != null) {
|
||||
pool.shutdown();
|
||||
pool = null;
|
||||
}
|
||||
if (dao != null) {
|
||||
dao.shutdown();
|
||||
dao = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setGroupSwitchLevel(int _primary, int _level, boolean _multilevel) {
|
||||
List<Integer> nodes = CollectionUtils.asArrayList(_primary);
|
||||
nodes.addAll(CollectionUtils.makeNotNull(peers.get(_primary)));
|
||||
for (int node : nodes) {
|
||||
controller.send(_multilevel ? new MultilevelSwitchSetRequest((byte) node, _level) : new BinarySwitchSetRequest((byte) node, _level > 0));
|
||||
}
|
||||
}
|
||||
|
||||
private class ThermostatTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Switch sw : switches.values()) {
|
||||
try {
|
||||
if (sw.isUrlThermostat() && !sw.isThermometer()) {
|
||||
double tempF = getTemperatureCelsius(sw) * 1.8 + 32;
|
||||
if (tempF > sw.getLevel() + 0.4) {
|
||||
setGroupSwitchLevel(sw.getNodeId(), 0, false);
|
||||
logger.info("Turning {} {} off, temp is: {} set to: {}", sw.getRoom(), sw.getName(), tempF + " set to: ", sw.getLevel());
|
||||
} else if (tempF < sw.getLevel() - 0.4) {
|
||||
setGroupSwitchLevel(sw.getNodeId(), (byte) 0xf, false);
|
||||
logger.info("Turning {} {} on, temp is: {} set to: {}", sw.getRoom(), sw.getName(), tempF + " set to: ", sw.getLevel());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
logger.error("Failed to check temperature for thermostat {}", sw.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SwitchScheduleTask extends TimerTask {
|
||||
private final List<SwitchTransition> transitions;
|
||||
|
||||
SwitchScheduleTask(List<SwitchTransition> _transitions) {
|
||||
transitions = _transitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (SwitchTransition tr : transitions) {
|
||||
if (!tr.getSwitch().isHold()) {
|
||||
logger.info("Executing scheduled transition of node {} to level {}", tr.getSwitch().getNodeId(), tr.getLevel());
|
||||
Globals.app.setSwitchLevel(tr.getSwitch().getNodeId(), tr.getLevel());
|
||||
}
|
||||
else
|
||||
logger.info("Skipping scheduled transition of node {} to level {}, switch is on hold", tr.getSwitch().getNodeId(), tr.getLevel());
|
||||
ConcurrencyUtils.sleep(100);
|
||||
}
|
||||
nextScheduleTask = null;
|
||||
Globals.app.scheduleNextTransition();
|
||||
}
|
||||
}
|
||||
|
||||
public double getTemperatureCelsius(int _nodeId) {
|
||||
return getTemperatureCelsius(switches.get(_nodeId));
|
||||
}
|
||||
|
||||
private double getTemperatureCelsius(Switch _sw) {
|
||||
if ((pool == null) || (_sw == null) || !(_sw.isThermometer() || _sw.isThermostat()))
|
||||
return 0.0;
|
||||
if (_sw.isUrlThermostat())
|
||||
return DaoSerializer.getDouble(DaoSerializer.parse(pool.executeToString(new HttpGet(_sw.getThermostatSource()))), "temp");
|
||||
else if (_sw.isZWaveThermostat()) {
|
||||
synchronized (ZWAVE_MUTEX) {
|
||||
synchronized (temperatures) {
|
||||
controller.send(new MultilevelSensorGetRequest((byte) _sw.getNodeId()));
|
||||
try {
|
||||
temperatures.wait(5000);
|
||||
} catch (InterruptedException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
Double temp = temperatures.get(_sw.getNodeId());
|
||||
return (temp == null) ? 0.0 : temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.lanternsoftware.zwave.context;
|
||||
|
||||
public class ZWaveSpring {
|
||||
/* private ZWaveConfig config;
|
||||
private static ZWaveSession session;
|
||||
private static Map<Integer, Switch> switches = new HashMap<>();
|
||||
private static Map<Integer, List<Integer>> peers = new HashMap<>();
|
||||
private static Timer timer;
|
||||
private static HttpPool pool;
|
||||
private static SwitchScheduleTask nextScheduleTask;
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
// controller = new Controller();
|
||||
// controller.start("COM4");
|
||||
timer = new Timer("ZWaveApp Timer");
|
||||
pool = new HttpPool(10, 10, 30000, 10000, 10000);
|
||||
session = new LocalZwaveSession();
|
||||
session.connect();
|
||||
while (!session.isNetworkReady()) {
|
||||
System.out.println("Network not ready yet, sleeping");
|
||||
ConcurrencyUtils.sleep(1000);
|
||||
}
|
||||
// session.subscribe(new ZWaveEventListener());
|
||||
|
||||
// for (ZWaveNode node : session.getDeviceManager().getNodes()) {
|
||||
// for (CommandClass cc : node.getCommandClasses()) {
|
||||
// System.out.println(node.getNodeId() + " " + cc.getClassCode() + " " + cc.getLabel());
|
||||
// }
|
||||
// }
|
||||
|
||||
//// for (int node = 3; node < 7; node++) {
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 7, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 8, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 9, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 10, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 11, new byte[]{99}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// session.doAction(new ConfigurationSetAction(node, (byte) 12, new byte[]{0, (byte) 1}));
|
||||
// ConcurrencyUtils.sleep(100);
|
||||
// }
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
config = SerializationEngine.deserialize(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "config.dat"), ZWaveConfig.class, SerializationEngine.SerializationType.JSON);
|
||||
Map<String, List<Integer>> groups = new HashMap<>();
|
||||
for (Switch sw : CollectionUtils.makeNotNull(config.getSwitches())) {
|
||||
switches.put(sw.getNodeId(), sw);
|
||||
CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw.getNodeId(), groups);
|
||||
}
|
||||
if (CollectionUtils.filterOne(config.getSwitches(), _sw -> NullUtils.isNotEmpty(_sw.getThermostatSource())) != null) {
|
||||
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
|
||||
}
|
||||
for (List<Integer> group : groups.values()) {
|
||||
for (Integer node : group) {
|
||||
peers.put(node, CollectionUtils.filter(group, _i -> !_i.equals(node)));
|
||||
}
|
||||
}
|
||||
scheduleNextTransition();
|
||||
}
|
||||
|
||||
public void scheduleNextTransition() {
|
||||
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
||||
if (nextScheduleTask != null)
|
||||
nextScheduleTask.cancel();
|
||||
Switch next = null;
|
||||
SwitchTransition transition = null;
|
||||
Date transitionDate = null;
|
||||
for (Switch sw : switches.values()) {
|
||||
for (SwitchTransition t : CollectionUtils.makeNotNull(sw.getSchedule())) {
|
||||
Date nextTransition = t.getNextTransition(tz);
|
||||
if ((transitionDate == null) || nextTransition.before(transitionDate)) {
|
||||
transitionDate = nextTransition;
|
||||
transition = t;
|
||||
next = sw;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transitionDate != null) {
|
||||
System.out.println("Next transition scheduled for node " + next.getNodeId() + " to level " + transition.getLevel() + " at " + DateUtils.format(tz, transitionDate, "hh:mm:ssa"));
|
||||
nextScheduleTask = new SwitchScheduleTask(next, transition);
|
||||
timer.schedule(nextScheduleTask, transitionDate);
|
||||
} else
|
||||
nextScheduleTask = null;
|
||||
}
|
||||
|
||||
public void setSwitchLevel(int _nodeId, int _level) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setLevel(_level);
|
||||
if (NullUtils.isEmpty(sw.getThermostatSource())) {
|
||||
doGroupSwitchAction(_nodeId, _level, sw.isMultilevel());
|
||||
} else {
|
||||
if (timer != null)
|
||||
timer.schedule(new ThermostatTask(), 0);
|
||||
persistConfig();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setSwitchSchedule(int _nodeId, List<SwitchTransition> _transitions) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setSchedule(_transitions);
|
||||
persistConfig();
|
||||
scheduleNextTransition();
|
||||
}
|
||||
|
||||
public void setSwitchHold(int _nodeId, boolean _hold) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
if ((sw == null) || !sw.isPrimary())
|
||||
return;
|
||||
sw.setHold(_hold);
|
||||
persistConfig();
|
||||
}
|
||||
|
||||
private void persistConfig() {
|
||||
synchronized (this) {
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "config.dat", SerializationEngine.serialize(config, SerializationEngine.SerializationType.JSON));
|
||||
}
|
||||
}
|
||||
|
||||
public int getSwitchLevel(int _nodeId) {
|
||||
Switch sw = switches.get(_nodeId);
|
||||
return (sw != null) ? sw.getLevel() : 0;
|
||||
}
|
||||
|
||||
public ZWaveConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
session.shutdown();
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
if (pool != null) {
|
||||
pool.shutdown();
|
||||
pool = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static class ZWaveEventListener implements EventHandler {
|
||||
@EventSubscribe
|
||||
public void receive(ZWaveEvent event) throws Exception {
|
||||
if (event instanceof ApplicationCommandEvent) {
|
||||
ApplicationCommandEvent ace = (ApplicationCommandEvent) event;
|
||||
if (ace.getCommandClass() == CommandClass.SWITCH_MULTILEVEL) {
|
||||
for (Integer node : CollectionUtils.makeNotNull(peers.get(ace.getNodeId()))) {
|
||||
Switch sw = switches.get(node);
|
||||
System.out.println("Mirror Event from node " + ((ApplicationCommandEvent) event).getNodeId() + " to node " + node);
|
||||
// session.doAction(new SwitchAction(node, ace.getPayload()[1], sw == null || sw.isMultilevel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventSubscribe
|
||||
public void handleSensorEvent(DeviceSensorEvent sensorEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
private void doGroupSwitchAction(int _primary, int _level, boolean _multilevel) {
|
||||
List<Integer> nodes = CollectionUtils.asArrayList(_primary);
|
||||
nodes.addAll(CollectionUtils.makeNotNull(peers.get(_primary)));
|
||||
for (int node : nodes) {
|
||||
try {
|
||||
session.doAction(new SwitchAction(node, _level, _multilevel));
|
||||
} catch (HomeAutomationException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ThermostatTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Switch sw : switches.values()) {
|
||||
if (NullUtils.isNotEmpty(sw.getThermostatSource())) {
|
||||
double tempF = getTemperatureCelsius(sw) * 1.8 + 32;
|
||||
if (tempF > sw.getLevel() + 0.4) {
|
||||
doGroupSwitchAction(sw.getNodeId(), 0, false);
|
||||
System.out.println("Turning " + sw.getRoom() + " " + sw.getName() + " off, temp is: " + tempF + " set to: " + sw.getLevel());
|
||||
} else if (tempF < sw.getLevel() - 0.4) {
|
||||
doGroupSwitchAction(sw.getNodeId(), (byte) 0xf, false);
|
||||
System.out.println("Turning " + sw.getRoom() + " " + sw.getName() + " on, temp is: " + tempF + " set to: " + sw.getLevel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SwitchScheduleTask extends TimerTask {
|
||||
private final Switch sw;
|
||||
private final SwitchTransition transition;
|
||||
|
||||
public SwitchScheduleTask(Switch _sw, SwitchTransition _transition) {
|
||||
sw = _sw;
|
||||
transition = _transition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Executing scheduled transition of node " + sw.getNodeId() + " to level " + transition.getLevel());
|
||||
if (!sw.isHold()) {
|
||||
Globals.app.setSwitchLevel(sw.getNodeId(), transition.getLevel());
|
||||
}
|
||||
nextScheduleTask = null;
|
||||
Globals.app.scheduleNextTransition();
|
||||
}
|
||||
}
|
||||
|
||||
public double getTemperatureCelsius(int _nodeId) {
|
||||
return getTemperatureCelsius(switches.get(_nodeId));
|
||||
}
|
||||
|
||||
private static double getTemperatureCelsius(Switch _sw) {
|
||||
if ((pool == null) || (_sw == null) || NullUtils.isEmpty(_sw.getThermostatSource()))
|
||||
return 0.0;
|
||||
return BsonUtils.getDouble(BsonUtils.parse(pool.executeToString(new HttpGet(_sw.getThermostatSource()))), "temp");
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.lanternsoftware.zwave.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
||||
import com.lanternsoftware.util.dao.DaoQuery;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoProxy;
|
||||
|
||||
public class MongoZWaveDao implements ZWaveDao {
|
||||
private MongoProxy proxy;
|
||||
|
||||
public MongoZWaveDao(MongoConfig _config) {
|
||||
proxy = new MongoProxy(_config);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
proxy.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void putConfig(ZWaveConfig _config) {
|
||||
proxy.save(_config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZWaveConfig getConfig(int _accountId) {
|
||||
return proxy.queryOne(ZWaveConfig.class, new DaoQuery("_id", String.valueOf(_accountId)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.lanternsoftware.zwave.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
||||
|
||||
public interface ZWaveDao {
|
||||
void putConfig(ZWaveConfig _config);
|
||||
ZWaveConfig getConfig(int _accountId);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.lanternsoftware.zwave.servlet;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||
import com.lanternsoftware.zwave.context.Globals;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@WebServlet("/config")
|
||||
public class ConfigServlet extends SecureServlet {
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
jsonResponse(_rep, Globals.app.getConfig());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.lanternsoftware.zwave.servlet;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||
import com.lanternsoftware.zwave.context.Globals;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public abstract class SecureServlet extends ZWaveServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
AuthCode authCode = Globals.cmDao.decryptAuthCode(_req.getHeader("auth_code"));
|
||||
if ((authCode == null) || (authCode.getAccountId() != 1)) {
|
||||
_rep.setStatus(401);
|
||||
return;
|
||||
}
|
||||
get(authCode, _req, _rep);
|
||||
}
|
||||
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
AuthCode authCode = Globals.cmDao.decryptAuthCode(_req.getHeader("auth_code"));
|
||||
if ((authCode == null) || (authCode.getAccountId() != 1)) {
|
||||
_rep.setStatus(401);
|
||||
return;
|
||||
}
|
||||
post(authCode, _req, _rep);
|
||||
}
|
||||
|
||||
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.lanternsoftware.zwave.servlet;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.zwave.context.Globals;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
@WebServlet("/switch/*")
|
||||
public class SwitchServlet extends SecureServlet {
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
String[] path = path(_req);
|
||||
int nodeId = NullUtils.toInteger(CollectionUtils.get(path, 0));
|
||||
if (path.length == 1) {
|
||||
setResponseEntity(_rep, "application/json", "{level:" + Globals.app.getSwitchLevel(nodeId) + "}");
|
||||
} else {
|
||||
if (nodeId > 0) {
|
||||
String command = CollectionUtils.get(path, 1);
|
||||
if ("hold".equals(command))
|
||||
Globals.app.setSwitchHold(nodeId, true);
|
||||
else if ("run".equals(command))
|
||||
Globals.app.setSwitchHold(nodeId, false);
|
||||
else if ("mode".equals(command))
|
||||
Globals.app.setThermostatMode(nodeId, ThermostatMode.fromByte(Byte.parseByte(CollectionUtils.get(path, 2))));
|
||||
else {
|
||||
Globals.app.setSwitchLevel(nodeId, NullUtils.toInteger(command));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
String[] path = path(_req);
|
||||
int nodeId = NullUtils.toInteger(CollectionUtils.get(path, 0));
|
||||
if (path.length > 1) {
|
||||
String command = CollectionUtils.get(path, 1);
|
||||
if ("schedule".equals(command)) {
|
||||
String json = getRequestPayloadAsString(_req);
|
||||
List<SwitchSchedule> transitions = DaoSerializer.parseList(json, SwitchSchedule.class);
|
||||
Globals.app.setSwitchSchedule(nodeId, transitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.lanternsoftware.zwave.servlet;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.zwave.context.Globals;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet("/temperature/*")
|
||||
public class TemperatureServlet extends SecureServlet {
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
String[] path = path(_req);
|
||||
DaoEntity json = new DaoEntity("temp", Globals.app.getTemperatureCelsius(NullUtils.toInteger(CollectionUtils.get(path, 0))));
|
||||
jsonResponse(_rep, DaoSerializer.toJson(json));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.lanternsoftware.zwave.servlet;
|
||||
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public abstract class ZWaveServlet extends HttpServlet {
|
||||
public static void setResponseHtml(HttpServletResponse _response, String _sHtml) {
|
||||
setResponseEntity(_response, "text/html", _sHtml);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) {
|
||||
setResponseEntity(_response, 200, _sContentType, _sEntity);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) {
|
||||
setResponseEntity(_response, 200, _sContentType, _btData);
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) {
|
||||
setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity));
|
||||
}
|
||||
|
||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) {
|
||||
OutputStream os = null;
|
||||
try {
|
||||
_response.setStatus(_iStatus);
|
||||
_response.setCharacterEncoding("UTF-8");
|
||||
_response.setContentType(_sContentType);
|
||||
if ((_btData != null) && (_btData.length > 0)) {
|
||||
_response.setContentLength(_btData.length);
|
||||
os = _response.getOutputStream();
|
||||
os.write(_btData);
|
||||
} else
|
||||
_response.setContentLength(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
|
||||
protected void zipBsonResponse(HttpServletResponse _response, Object _object)
|
||||
{
|
||||
setResponseEntity(_response, 200, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(_object));
|
||||
}
|
||||
|
||||
protected void jsonResponse(HttpServletResponse _response, Object _object)
|
||||
{
|
||||
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, DaoSerializer.toJson(_object));
|
||||
}
|
||||
|
||||
protected void jsonResponse(HttpServletResponse _response, String _json)
|
||||
{
|
||||
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, _json);
|
||||
}
|
||||
|
||||
protected String getRequestPayloadAsString(HttpServletRequest _req) {
|
||||
return NullUtils.toString(getRequestPayload(_req));
|
||||
}
|
||||
|
||||
protected byte[] getRequestPayload(HttpServletRequest _req) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = _req.getInputStream();
|
||||
return IOUtils.toByteArray(is);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
protected String[] path(HttpServletRequest _req) {
|
||||
return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/");
|
||||
}
|
||||
}
|
||||
17
zwave/lantern-service-zwave/src/main/resources/logback.xml
Normal file
17
zwave/lantern-service-zwave/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="com.lanternsoftware" level="INFO"/>
|
||||
|
||||
<root level="OFF">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,59 @@
|
||||
Power,Mode,Temperature,Code
|
||||
Off,Heat,72,0000 006C 0000 0083 0010 00D1 0010 0010 0010 0011 0010 00F1 0010 0030 0010 0030 0010 0071 0010 0030 0010 0010 0010 0031 0010 0031 0010 0030 0010 0011 0010 01B2 0080 0041 0010 0031 0010 0030 0010 0011 0010 0010 0010 0011 0010 0031 0010 0010 0010 0010 0010 0031 0010 0031 0010 0011 0010 0031 0010 0011 0010 0011 0010 0031 0010 0031 0010 0010 0010 0031 0010 0031 0010 0010 0010 0011 0010 0031 0010 0010 0010 0010 0010 0031 0010 0011 0010 0010 0010 0010 0010 0071 0010 0091 0010 0011 0010 00B1 0010 0091 0010 0071 0010 0011 0010 0011 0010 0031 0010 0010 0010 0010 0010 0031 0010 0031 0010 0010 0010 0031 0010 0011 0010 0011 0010 0011 0010 0030 0010 0010 0010 0051 0010 0010 0010 0010 0010 0011 0010 0011 0010 0071 0010 0030 0010 0010 0010 0031 0010 0010 0010 0010 0010 0031 0010 0031 0010 0031 0010 0010 0010 0031 0010 0031 0010 0010 0010 0010 0010 0010 0010 0010 0010 0011 0010 0011 0010 0011 0010 0010 0010 0010 0010 0011 0010 0010 0010 0031 0010 0010 0010 0010 0010 0010 0010 0011 0010 0011 0010 0011 0010 0011 0010 0030 0010 0010 0010 0011 0010 0051 0010 0010 0010 0010 0010 0010 0010 0031 0010 0011 0010 0010 0010 0030 0010 0010 0010 0031 0010 0010 0010 0010 0010 0010 0010 0071 0010 0010 0010 0031 0010 0031 0010 0010 0010 0011 0010 0010 0010 0010 0010 0030 0010 0031 0010 0010 0010 0030 0010 0031 0010 0031 0010 0011 0010 02CF
|
||||
On,Heat,61,
|
||||
On,Heat,62,
|
||||
On,Heat,63,
|
||||
On,Heat,64,
|
||||
On,Heat,65,
|
||||
On,Heat,66,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 01B1 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F8E
|
||||
On,Heat,67,0000 006D 0000 00BF 007F 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 01AF 007F 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F83
|
||||
On,Heat,68,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 01B0 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F8D
|
||||
On,Heat,69,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 01B0 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F8B
|
||||
On,Heat,70,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 01B0 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F8A
|
||||
On,Heat,71,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 01AF 007F 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F86
|
||||
On,Heat,72,0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 01B0 007F 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F89
|
||||
On,Heat,73,
|
||||
On,Heat,74,
|
||||
On,Heat,75,
|
||||
On,Heat,76,
|
||||
On,Heat,77,
|
||||
On,Heat,78,
|
||||
On,Heat,79,
|
||||
On,Heat,80,
|
||||
On,Heat,81,
|
||||
On,Heat,82,
|
||||
On,Heat,83,
|
||||
On,Heat,84,
|
||||
On,Heat,85,
|
||||
On,Heat,86,
|
||||
On,Heat,87,
|
||||
On,Heat,88,
|
||||
Off,Cool,72,
|
||||
On,Cool,61,
|
||||
On,Cool,62,
|
||||
On,Cool,63,
|
||||
On,Cool,64,
|
||||
On,Cool,65,
|
||||
On,Cool,66,
|
||||
On,Cool,67,
|
||||
On,Cool,68,
|
||||
On,Cool,69,
|
||||
On,Cool,70,
|
||||
On,Cool,71,
|
||||
On,Cool,72,
|
||||
On,Cool,73,
|
||||
On,Cool,74,
|
||||
On,Cool,75,
|
||||
On,Cool,76,
|
||||
On,Cool,77,
|
||||
On,Cool,78,
|
||||
On,Cool,79,
|
||||
On,Cool,80,
|
||||
On,Cool,81,
|
||||
On,Cool,82,
|
||||
On,Cool,83,
|
||||
On,Cool,84,
|
||||
On,Cool,85,
|
||||
On,Cool,86,
|
||||
On,Cool,87,
|
||||
On,Cool,88,
|
||||
|
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE web-app PUBLIC
|
||||
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
||||
|
||||
<web-app>
|
||||
<listener>
|
||||
<listener-class>com.lanternsoftware.zwave.context.Globals</listener-class>
|
||||
</listener>
|
||||
</web-app>
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.lanternsoftware.zwave;
|
||||
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import com.lanternsoftware.zwave.dao.MongoZWaveDao;
|
||||
|
||||
public class CreateConfig {
|
||||
public static void main(String[] args) {
|
||||
MongoZWaveDao dao = new MongoZWaveDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
ZWaveConfig config = dao.getConfig(1);
|
||||
// ZWaveConfig cconfig = DaoSerializer.parse(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "config - christmas lights.dat"), ZWaveConfig.class);
|
||||
// Switch c = CollectionUtils.filterOne(config.getSwitches(), _s->_s.getName().contains("hristm"));
|
||||
// CollectionUtils.filterMod(config.getSwitches(), _s->!_s.getRoom().equals("Treehouse"));
|
||||
// Switch treehouse = new Switch("Treehouse", "Interior", 14, true, true, null, 0);
|
||||
// Switch to = new Switch("Treehouse", "Floods", 15, true, true, null, 0);
|
||||
// Switch out = new Switch("Outside", "Repeater Outlet", 10, true, false, null, 0);
|
||||
// config.getSwitches().add(out);
|
||||
Switch c = CollectionUtils.filterOne(config.getSwitches(), _s->_s.getName().contains("Agitator"));
|
||||
c.setName("Septic Aerator");
|
||||
dao.putConfig(config);
|
||||
// if (c != null) {
|
||||
// c.setNodeId(8);
|
||||
// dao.putConfig(config);
|
||||
// }
|
||||
// ZWaveConfig config = DaoSerializer.parse(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "config.dat"), ZWaveConfig.class);
|
||||
// config.setAccountId(1);
|
||||
// config.getSwitches().add(new Switch("Garage", "Septic Agitator", 12, 0, true, false, false, null, 0, Arrays.asList(new SwitchTransition(20))));
|
||||
// Switch thermo = CollectionUtils.filterOne(config.getSwitches(), _sw->_sw.getNodeId() == 0);
|
||||
// if (thermo != null)
|
||||
// thermo.setNodeId(100);
|
||||
// config.getSwitches().add(new Switch("Basement", "Temperature", 101, true, false, "https://basement.lanternsoftware.com/thermometer/temp", 0));
|
||||
|
||||
/* ZWaveConfig config = new ZWaveConfig();
|
||||
List<Switch> switches = new ArrayList<>();
|
||||
switches.add(new Switch("Basement", "Main", 3, true, true, null, 0));
|
||||
switches.add(new Switch("Basement", "Main", 5, false, true, null, 0));
|
||||
switches.add(new Switch("Basement", "Bar", 4, true, true, null, 0));
|
||||
switches.add(new Switch("Basement", "Bar", 6, false, true, null, 0));
|
||||
switches.add(new Switch("Master Bedroom", "Heater", 7, true, true, "https://thermometer.lanternsoftware.com/thermometer/temp", 0));
|
||||
switches.add(new Switch("Bruce's Room", "Heater", 8, true, true, "https://bruce.lanternsoftware.com/thermometer/temp", 0));
|
||||
switches.add(new Switch("Master Bedroom", "Heater", 9, false, true, "", 0));
|
||||
Switch out = new Switch("Outside", "Christmas Lights", 10, true, false, "", 0);
|
||||
out.setSchedule(CollectionUtils.asArrayList(
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 0, 0),
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 10, 0xFF),
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 20, 0),
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 30, 0xFF),
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 40, 0),
|
||||
new SwitchTransition(Calendar.FRIDAY, 12, 42, 50, 0xFF)));
|
||||
switches.add(out);
|
||||
config.setSwitches(switches);
|
||||
*/
|
||||
// config.setSwitches(switches);
|
||||
// Switch sump = CollectionUtils.filterOne(config.getSwitches(), _c->_c.getNodeId() == 12);
|
||||
// SwitchSchedule transition = CollectionUtils.getFirst(sump.getSchedule());
|
||||
// transition.setLevel(0xFF);
|
||||
// transition.setMinutesPerHour(15);
|
||||
// dao.putConfig(config);
|
||||
dao.shutdown();
|
||||
// TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
||||
// Date next = transition.getNextTransition(tz);
|
||||
// System.out.println("Next Transition: " + DateUtils.format(tz, next, "hh:mm:ssa"));
|
||||
|
||||
// ResourceLoader.writeFile(LanternFiles.OPS_PATH + "config.dat", DaoSerializer.toJson(config));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.zwave;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
|
||||
|
||||
public class GenerateSerializers {
|
||||
public static void main(String[] args) {
|
||||
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "zwave", true, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.lanternsoftware.zwave;
|
||||
|
||||
import com.lanternsoftware.zwave.context.ZWaveApp;
|
||||
|
||||
public class TestStartup {
|
||||
public static void main(String[] args) {
|
||||
ZWaveApp app = new ZWaveApp();
|
||||
app.start();
|
||||
try {
|
||||
Thread.sleep(20000);
|
||||
} catch (InterruptedException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
app.stop();
|
||||
}
|
||||
}
|
||||
78
zwave/lantern-uirt/pom.xml
Normal file
78
zwave/lantern-uirt/pom.xml
Normal file
@@ -0,0 +1,78 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.services</groupId>
|
||||
<artifactId>lantern-uirt</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-uirt</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-dao</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>5.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<index>true</index>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.lanternsoftware.uirt;
|
||||
|
||||
import com.lanternsoftware.uirt.model.UIRTConfig;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sun.jna.win32.StdCallLibrary;
|
||||
import com.sun.jna.win32.W32APIOptions;
|
||||
|
||||
public class UsbUirt {
|
||||
private static String off = "0000 006D 0000 00BF 0080 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 01AF 007F 0040 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0F85";
|
||||
private UirtLibrary lib;
|
||||
private Pointer handle;
|
||||
|
||||
public interface UirtLibrary extends Library {
|
||||
interface ReceiveProc extends StdCallLibrary.StdCallCallback {
|
||||
boolean callback(Pointer _event, Pointer _userData);
|
||||
}
|
||||
interface LearnProc extends StdCallLibrary.StdCallCallback {
|
||||
boolean callback(int progress, int _sigQuality, long carrierFreq, Pointer _userData);
|
||||
}
|
||||
|
||||
Pointer UUIRTOpen();
|
||||
boolean UUIRTClose(Pointer _handle);
|
||||
boolean UUIRTGetDrvVersion(IntByReference _version);
|
||||
boolean UUIRTGetUUIRTConfig(Pointer _handle, UIRTConfig.ByReference _config);
|
||||
boolean UUIRTSetReceiveCallback(Pointer _handle, ReceiveProc _proc, Pointer _userData);
|
||||
boolean UUIRTSetRawReceiveCallback(Pointer _handle, ReceiveProc _proc, Pointer _userData);
|
||||
boolean UUIRTLearnIR(Pointer _handle, int codeFormat, PointerByReference irCode, LearnProc progressProc, Pointer _userData, IntByReference _abort, int _param1, Pointer reserved0, Pointer reserved1);
|
||||
boolean UUIRTTransmitIR(Pointer _handle, String _code, int _codeFormat, int repeatCount_, int _inactivityWaitTime, Pointer _event, Pointer reserved0, Pointer reserved1);
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
lib = Native.load("uuirtdrv", UirtLibrary.class, W32APIOptions.ASCII_OPTIONS);
|
||||
handle = lib.UUIRTOpen();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (isStarted())
|
||||
lib.UUIRTClose(handle);
|
||||
lib = null;
|
||||
}
|
||||
|
||||
public int getDriverVersion() {
|
||||
if (!isStarted())
|
||||
return 0;
|
||||
IntByReference version = new IntByReference();
|
||||
lib.UUIRTGetDrvVersion(version);
|
||||
return version.getValue();
|
||||
}
|
||||
|
||||
public UIRTConfig getConfig() {
|
||||
if (!isStarted())
|
||||
return null;
|
||||
UIRTConfig.ByReference configRef = new UIRTConfig.ByReference();
|
||||
lib.UUIRTGetUUIRTConfig(handle, configRef);
|
||||
return configRef;
|
||||
}
|
||||
|
||||
public void setReceiveCallback(UirtLibrary.ReceiveProc _proc) {
|
||||
if (isStarted())
|
||||
lib.UUIRTSetReceiveCallback(handle, _proc, null);
|
||||
}
|
||||
|
||||
public void setRawReceiveCallback(UirtLibrary.ReceiveProc _proc) {
|
||||
if (isStarted())
|
||||
lib.UUIRTSetRawReceiveCallback(handle, _proc, null);
|
||||
}
|
||||
|
||||
public String learnCode(UirtLibrary.LearnProc _proc) {
|
||||
PointerByReference codeRef = new PointerByReference();
|
||||
lib.UUIRTLearnIR(handle, 0, codeRef, _proc, null, null, 0, null, null);
|
||||
Pointer code = codeRef.getValue();
|
||||
return code == null ? null : code.getString(0);
|
||||
}
|
||||
|
||||
public boolean transmitIR(boolean _pronto, int _repeatCnt, int _inactivityWaitTime, String _code) {
|
||||
PointerByReference result = new PointerByReference();
|
||||
return lib.UUIRTTransmitIR(handle, _code, _pronto?0x0010:0x0000, _repeatCnt, _inactivityWaitTime, null, null, null);
|
||||
}
|
||||
|
||||
private boolean isStarted() {
|
||||
return (lib != null) && (handle != null);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
UsbUirt uirt = new UsbUirt();
|
||||
uirt.startup();
|
||||
uirt.transmitIR(true, 3, 0, off);
|
||||
uirt.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.lanternsoftware.uirt.model;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.Structure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class UIRTConfig extends Structure {
|
||||
public static class ByReference extends UIRTConfig implements Structure.ByReference {}
|
||||
|
||||
public boolean ledRX;
|
||||
public boolean ledTX;
|
||||
public boolean legacyRX;
|
||||
|
||||
public UIRTConfig() {
|
||||
}
|
||||
|
||||
public UIRTConfig(Pointer _value) {
|
||||
super(_value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getFieldOrder() {
|
||||
return Arrays.asList("ledRX", "ledTX", "legacyRX");
|
||||
}
|
||||
|
||||
public boolean isLedRX() {
|
||||
return ledRX;
|
||||
}
|
||||
|
||||
public void setLedRX(boolean _ledRX) {
|
||||
ledRX = _ledRX;
|
||||
}
|
||||
|
||||
public boolean isLedTX() {
|
||||
return ledTX;
|
||||
}
|
||||
|
||||
public void setLedTX(boolean _ledTX) {
|
||||
ledTX = _ledTX;
|
||||
}
|
||||
|
||||
public boolean isLegacyRX() {
|
||||
return legacyRX;
|
||||
}
|
||||
|
||||
public void setLegacyRX(boolean _legacyRX) {
|
||||
legacyRX = _legacyRX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.lanternsoftware.uirt.model;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.Structure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class UIRTEvent extends Structure {
|
||||
public static class ByReference extends UIRTEvent implements Structure.ByReference {}
|
||||
|
||||
public int code;
|
||||
public String data;
|
||||
|
||||
public UIRTEvent() {
|
||||
}
|
||||
|
||||
public UIRTEvent(Pointer p) {
|
||||
super(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getFieldOrder() {
|
||||
return Arrays.asList("code", "data");
|
||||
}
|
||||
}
|
||||
65
zwave/lantern-zwave/pom.xml
Normal file
65
zwave/lantern-zwave/pom.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.zwave</groupId>
|
||||
<artifactId>lantern-zwave</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-zwave</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.neuronrobotics</groupId>
|
||||
<artifactId>nrjavaserial</artifactId>
|
||||
<version>3.15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.29</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-dao</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,237 @@
|
||||
package com.lanternsoftware.zwave.controller;
|
||||
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||
import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
||||
import com.lanternsoftware.zwave.message.Message;
|
||||
import com.lanternsoftware.zwave.message.MessageEngine;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
import com.lanternsoftware.zwave.message.ResponseMessage;
|
||||
import com.lanternsoftware.zwave.message.impl.ByteMessage;
|
||||
import com.lanternsoftware.zwave.message.impl.ControllerCapabilitiesRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.ControllerInitialDataRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.GetControllerIdRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.SendDataRequest;
|
||||
import com.lanternsoftware.zwave.node.NodeManager;
|
||||
import gnu.io.CommPortIdentifier;
|
||||
import gnu.io.SerialPort;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Controller {
|
||||
private static final byte SOF = 0x01;
|
||||
private static final byte ACK = 0x06;
|
||||
private static final byte NAK = 0x15;
|
||||
private static final byte CAN = 0x18;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Controller.class);
|
||||
|
||||
private SerialPort serialPort;
|
||||
private OutputStream os;
|
||||
private boolean running = false;
|
||||
private AtomicInteger callbackId = new AtomicInteger(0);
|
||||
private final Object ackMutex = new Object();
|
||||
private final Object responseMutex = new Object();
|
||||
private final Object callbackMutex = new Object();
|
||||
private boolean responseReceived;
|
||||
private final Map<Byte, Byte> callbacks = new HashMap<>();
|
||||
private ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
private NodeManager nodeManager;
|
||||
|
||||
public boolean start(String _port) {
|
||||
try {
|
||||
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(_port);
|
||||
serialPort = portIdentifier.open("zwaveport", 2000);
|
||||
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
|
||||
serialPort.enableReceiveThreshold(1);
|
||||
serialPort.enableReceiveTimeout(1000);
|
||||
os = serialPort.getOutputStream();
|
||||
running = true;
|
||||
executor.submit(new MessageReceiver());
|
||||
MessageEngine.subscribe(new SendDataRequestHandler());
|
||||
nodeManager = new NodeManager(this);
|
||||
send(new ControllerCapabilitiesRequest());
|
||||
send(new ControllerInitialDataRequest());
|
||||
send(new GetControllerIdRequest());
|
||||
nodeManager.waitForStartup();
|
||||
logger.debug("Finishing Controller Start");
|
||||
return true;
|
||||
} catch (Exception _e) {
|
||||
if (serialPort != null) {
|
||||
serialPort.close();
|
||||
serialPort = null;
|
||||
}
|
||||
logger.error("Exception while starting controller", _e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
running = false;
|
||||
ConcurrencyUtils.sleep(2000);
|
||||
IOUtils.closeQuietly(os);
|
||||
if (serialPort != null) {
|
||||
serialPort.close();
|
||||
}
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
public void send(Message _message) {
|
||||
executor.submit(new MessageSender(_message));
|
||||
}
|
||||
|
||||
private class MessageReceiver implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = serialPort.getInputStream();
|
||||
int nextByte = 0;
|
||||
int offset = 0;
|
||||
while (running) {
|
||||
nextByte = is.read();
|
||||
if (nextByte == -1)
|
||||
continue;
|
||||
switch (nextByte) {
|
||||
case SOF:
|
||||
int messageLength = is.read();
|
||||
byte[] buffer = new byte[messageLength + 2];
|
||||
buffer[0] = SOF;
|
||||
buffer[1] = (byte) messageLength;
|
||||
offset = 2;
|
||||
while (offset < messageLength + 2) {
|
||||
offset += is.read(buffer, offset, messageLength + 2 - offset);
|
||||
}
|
||||
processIncomingMessage(buffer);
|
||||
break;
|
||||
case ACK:
|
||||
synchronized (ackMutex) {
|
||||
logger.debug("Received ACK");
|
||||
ackMutex.notify();
|
||||
}
|
||||
MessageEngine.publish(new ByteMessage((byte) nextByte));
|
||||
break;
|
||||
case NAK:
|
||||
case CAN:
|
||||
synchronized (ackMutex) {
|
||||
logger.debug("Received: {}", NullUtils.toHex(new byte[]{(byte) nextByte}));
|
||||
ackMutex.notify();
|
||||
}
|
||||
MessageEngine.publish(new ByteMessage((byte) nextByte));
|
||||
break;
|
||||
default:
|
||||
sendRaw(new byte[]{NAK});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException _e) {
|
||||
logger.error("Exception while receiving inbound, stopping controller", _e);
|
||||
stop();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageSender implements Runnable {
|
||||
private final Message message;
|
||||
|
||||
MessageSender(Message _message) {
|
||||
message = _message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (Controller.this) {
|
||||
byte callback = 0;
|
||||
String log = "Sending message outbound: " + message.describe();
|
||||
if (message.isCallbackExpected()) {
|
||||
callback = (byte) (callbackId.getAndIncrement() % 126 + 1);
|
||||
callbacks.put(callback, message.getNodeId());
|
||||
log += " callback: " + callback;
|
||||
}
|
||||
logger.info(log);
|
||||
byte[] data = message.toByteArray((byte) 0, callback);
|
||||
logger.debug("Sending outbound: {}", NullUtils.toHexBytes(data));
|
||||
responseReceived = false;
|
||||
sendRaw(data);
|
||||
synchronized (ackMutex) {
|
||||
ackMutex.wait(1000);
|
||||
}
|
||||
logger.debug("Finished outbound of: {}", message.describe());
|
||||
}
|
||||
if (message instanceof RequestMessage) {
|
||||
logger.debug("Waiting for response from: {}", message.describe());
|
||||
synchronized (responseMutex) {
|
||||
responseMutex.wait(1000);
|
||||
logger.debug("Response received: {}", responseReceived);
|
||||
responseReceived = false;
|
||||
}
|
||||
}
|
||||
if (message.isCallbackExpected()) {
|
||||
logger.debug("Waiting for callback from: {}", message.describe());
|
||||
synchronized (callbackMutex) {
|
||||
callbackMutex.wait(1000);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _e) {
|
||||
logger.error("Interrupted while sending outbound", _e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendRaw(byte[] _data) {
|
||||
try {
|
||||
os.write(_data);
|
||||
os.flush();
|
||||
} catch (IOException _e) {
|
||||
logger.error("IO exception while sending outbound", _e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processIncomingMessage(byte[] _buffer) {
|
||||
logger.debug("Received inbound: {}", NullUtils.toHexBytes(_buffer));
|
||||
logger.debug("Sending ACK");
|
||||
sendRaw(new byte[]{ACK});
|
||||
Message message = MessageEngine.decode(_buffer);
|
||||
if (message != null) {
|
||||
logger.info("Received message inbound: {}", message.describe());
|
||||
MessageEngine.publish(message);
|
||||
if (message instanceof ResponseMessage) {
|
||||
synchronized (responseMutex) {
|
||||
responseReceived = true;
|
||||
responseMutex.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SendDataRequestHandler implements IMessageSubscriber<SendDataRequest> {
|
||||
@Override
|
||||
public Class<SendDataRequest> getHandledMessageClass() {
|
||||
return SendDataRequest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(SendDataRequest _message) {
|
||||
Byte nodeId = callbacks.remove(_message.getCallbackId());
|
||||
if (nodeId != null) {
|
||||
logger.debug("Received callback for node: {} callback id: {}", nodeId, _message.getCallbackId());
|
||||
synchronized (callbackMutex) {
|
||||
callbackMutex.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum CommandClass {
|
||||
NO_OPERATION((byte)0x00, "NO_OPERATION"),
|
||||
BASIC((byte)0x20, "BASIC"),
|
||||
CONTROLLER_REPLICATION((byte)0x21, "CONTROLLER_REPLICATION"),
|
||||
APPLICATION_STATUS((byte)0x22, "APPLICATION_STATUS"),
|
||||
ZIP_SERVICES((byte)0x23, "ZIP_SERVICES"),
|
||||
ZIP_SERVER((byte)0x24, "ZIP_SERVER"),
|
||||
SWITCH_BINARY((byte)0x25, "SWITCH_BINARY", true, 0),
|
||||
SWITCH_MULTILEVEL((byte)0x26, "SWITCH_MULTILEVEL", true, 0),
|
||||
SWITCH_ALL((byte)0x27, "SWITCH_ALL"),
|
||||
SWITCH_TOGGLE_BINARY((byte)0x28, "SWITCH_TOGGLE_BINARY"),
|
||||
SWITCH_TOGGLE_MULTILEVEL((byte)0x29, "SWITCH_TOGGLE_MULTILEVEL"),
|
||||
CHIMNEY_FAN((byte)0x2A, "CHIMNEY_FAN"),
|
||||
SCENE_ACTIVATION((byte)0x2B, "SCENE_ACTIVATION"),
|
||||
SCENE_ACTUATOR_CONF((byte)0x2C, "SCENE_ACTUATOR_CONF"),
|
||||
SCENE_CONTROLLER_CONF((byte)0x2D, "SCENE_CONTROLLER_CONF"),
|
||||
ZIP_CLIENT((byte)0x2E, "ZIP_CLIENT"),
|
||||
ZIP_ADV_SERVICES((byte)0x2F, "ZIP_ADV_SERVICES"),
|
||||
SENSOR_BINARY((byte)0x30, "SENSOR_BINARY"),
|
||||
SENSOR_MULTILEVEL((byte)0x31, "SENSOR_MULTILEVEL"),
|
||||
METER((byte)0x32, "METER", true, 60),
|
||||
ZIP_ADV_SERVER((byte)0x33, "ZIP_ADV_SERVER"),
|
||||
ZIP_ADV_CLIENT((byte)0x34, "ZIP_ADV_CLIENT"),
|
||||
METER_PULSE((byte)0x35, "METER_PULSE"),
|
||||
METER_TBL_CONFIG((byte)0x3C, "METER_TBL_CONFIG"),
|
||||
METER_TBL_MONITOR((byte)0x3D, "METER_TBL_MONITOR"),
|
||||
METER_TBL_PUSH((byte)0x3E, "METER_TBL_PUSH"),
|
||||
THERMOSTAT_HEATING((byte)0x38, "THERMOSTAT_HEATING"),
|
||||
THERMOSTAT_MODE((byte)0x40, "THERMOSTAT_MODE"),
|
||||
THERMOSTAT_OPERATING_STATE((byte)0x42, "THERMOSTAT_OPERATING_STATE"),
|
||||
THERMOSTAT_SETPOINT((byte)0x43, "THERMOSTAT_SETPOINT"),
|
||||
THERMOSTAT_FAN_MODE((byte)0x44, "THERMOSTAT_FAN_MODE"),
|
||||
THERMOSTAT_FAN_STATE((byte)0x45, "THERMOSTAT_FAN_STATE"),
|
||||
CLIMATE_CONTROL_SCHEDULE((byte)0x46, "CLIMATE_CONTROL_SCHEDULE"),
|
||||
THERMOSTAT_SETBACK((byte)0x47, "THERMOSTAT_SETBACK"),
|
||||
DOOR_LOCK_LOGGING((byte)0x4C, "DOOR_LOCK_LOGGING"),
|
||||
SCHEDULE_ENTRY_LOCK((byte)0x4E, "SCHEDULE_ENTRY_LOCK"),
|
||||
BASIC_WINDOW_COVERING((byte)0x50, "BASIC_WINDOW_COVERING"),
|
||||
MTP_WINDOW_COVERING((byte)0x51, "MTP_WINDOW_COVERING"),
|
||||
MULTI_INSTANCE((byte)0x60, "MULTI_INSTANCE"),
|
||||
DOOR_LOCK((byte)0x62, "DOOR_LOCK"),
|
||||
USER_CODE((byte)0x63, "USER_CODE"),
|
||||
CONFIGURATION((byte)0x70, "CONFIGURATION"),
|
||||
ALARM((byte)0x71, "ALARM"),
|
||||
MANUFACTURER_SPECIFIC((byte)0x72, "MANUFACTURER_SPECIFIC"),
|
||||
POWERLEVEL((byte)0x73, "POWERLEVEL"),
|
||||
PROTECTION((byte)0x75, "PROTECTION"),
|
||||
LOCK((byte)0x76, "LOCK"),
|
||||
NODE_NAMING((byte)0x77, "NODE_NAMING"),
|
||||
FIRMWARE_UPDATE_MD((byte)0x7A, "FIRMWARE_UPDATE_MD"),
|
||||
GROUPING_NAME((byte)0x7B, "GROUPING_NAME"),
|
||||
REMOTE_ASSOCIATION_ACTIVATE((byte)0x7C, "REMOTE_ASSOCIATION_ACTIVATE"),
|
||||
REMOTE_ASSOCIATION((byte)0x7D, "REMOTE_ASSOCIATION"),
|
||||
BATTERY((byte)0x80, "BATTERY", true, 3600),
|
||||
CLOCK((byte)0x81, "CLOCK"),
|
||||
HAIL((byte)0x82, "HAIL"),
|
||||
WAKE_UP((byte)0x84, "WAKE_UP"),
|
||||
ASSOCIATION((byte)0x85, "ASSOCIATION"),
|
||||
VERSION((byte)0x86, "VERSION"),
|
||||
INDICATOR((byte)0x87, "INDICATOR"),
|
||||
PROPRIETARY((byte)0x88, "PROPRIETARY"),
|
||||
LANGUAGE((byte)0x89, "LANGUAGE"),
|
||||
TIME((byte)0x8A, "TIME"),
|
||||
TIME_PARAMETERS((byte)0x8B, "TIME_PARAMETERS"),
|
||||
GEOGRAPHIC_LOCATION((byte)0x8C, "GEOGRAPHIC_LOCATION"),
|
||||
COMPOSITE((byte)0x8D, "COMPOSITE"),
|
||||
MULTI_INSTANCE_ASSOCIATION((byte)0x8E, "MULTI_INSTANCE_ASSOCIATION"),
|
||||
MULTI_CMD((byte)0x8F, "MULTI_CMD"),
|
||||
ENERGY_PRODUCTION((byte)0x90, "ENERGY_PRODUCTION"),
|
||||
MANUFACTURER_PROPRIETARY((byte)0x91, "MANUFACTURER_PROPRIETARY"),
|
||||
SCREEN_MD((byte)0x92, "SCREEN_MD"),
|
||||
SCREEN_ATTRIBUTES((byte)0x93, "SCREEN_ATTRIBUTES"),
|
||||
SIMPLE_AV_CONTROL((byte)0x94, "SIMPLE_AV_CONTROL"),
|
||||
AV_CONTENT_DIRECTORY_MD((byte)0x95, "AV_CONTENT_DIRECTORY_MD"),
|
||||
AV_RENDERER_STATUS((byte)0x96, "AV_RENDERER_STATUS"),
|
||||
AV_CONTENT_SEARCH_MD((byte)0x97, "AV_CONTENT_SEARCH_MD"),
|
||||
SECURITY((byte)0x98, "SECURITY"),
|
||||
AV_TAGGING_MD((byte)0x99, "AV_TAGGING_MD"),
|
||||
IP_CONFIGURATION((byte)0x9A, "IP_CONFIGURATION"),
|
||||
ASSOCIATION_COMMAND_CONFIGURATION((byte)0x9B, "ASSOCIATION_COMMAND_CONFIGURATION"),
|
||||
SENSOR_ALARM((byte)0x9C, "SENSOR_ALARM"),
|
||||
SILENCE_ALARM((byte)0x9D, "SILENCE_ALARM"),
|
||||
SENSOR_CONFIGURATION((byte)0x9E, "SENSOR_CONFIGURATION"),
|
||||
MARK((byte)0xEF, "MARK"),
|
||||
NON_INTEROPERABLE((byte)0xF0, "NON_INTEROPERABLE"),
|
||||
ALL((byte)0xFF, null);
|
||||
|
||||
public final byte data;
|
||||
public final String label;
|
||||
public final boolean supportsPolling;
|
||||
public final int secondsRefreshInterval;
|
||||
private static final Map<Byte, CommandClass> classes = new HashMap<>();
|
||||
static {
|
||||
for (CommandClass cls : values()) {
|
||||
classes.put(cls.data, cls);
|
||||
}
|
||||
}
|
||||
|
||||
CommandClass(byte _data, String _label) {
|
||||
this(_data, _label, false, 0);
|
||||
}
|
||||
|
||||
CommandClass(byte _data, String _label, boolean _supportsPolling, int _secondsRefreshInterval) {
|
||||
data = _data;
|
||||
label = _label;
|
||||
supportsPolling = _supportsPolling;
|
||||
secondsRefreshInterval = _secondsRefreshInterval;
|
||||
}
|
||||
|
||||
public static CommandClass fromByte(byte _code) {
|
||||
CommandClass cls = classes.get(_code);
|
||||
return cls == null ? CommandClass.NO_OPERATION : cls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
public enum ControllerMessageType {
|
||||
None((byte)0x0,"None"),
|
||||
SerialApiGetInitData((byte)0x02,"SerialApiGetInitData"), // Request initial information about devices in network
|
||||
SerialApiApplicationNodeInfo((byte)0x03,"SerialApiApplicationNodeInfo"), // Set controller node information
|
||||
ApplicationCommandHandler((byte)0x04,"ApplicationCommandHandler"), // Handle application command
|
||||
GetControllerCapabilities((byte)0x05,"GetControllerCapabilities"), // Request controller capabilities (primary role, SUC/SIS availability)
|
||||
SerialApiSetTimeouts((byte)0x06,"SerialApiSetTimeouts"), // Set Serial API timeouts
|
||||
GetCapabilities((byte)0x07,"GetCapabilities"), // Request Serial API capabilities from the controller
|
||||
SerialApiSoftReset((byte)0x08,"SerialApiSoftReset"), // Soft reset. Restarts Z-Wave chip
|
||||
RfReceiveMode((byte)0x10,"RfReceiveMode"), // Power down the RF section of the stick
|
||||
SetSleepMode((byte)0x11,"SetSleepMode"), // Set the CPU into sleep mode
|
||||
SendNodeInfo((byte)0x12,"SendNodeInfo"), // Send Node Information Frame of the stick
|
||||
SendData((byte)0x13,"SendData"), // Send data.
|
||||
SendDataMulti((byte)0x14, "SendDataMulti"),
|
||||
GetVersion((byte)0x15,"GetVersion"), // Request controller hardware version
|
||||
SendDataAbort((byte)0x16,"SendDataAbort"), // Abort Send data.
|
||||
RfPowerLevelSet((byte)0x17,"RfPowerLevelSet"), // Set RF Power level
|
||||
SendDataMeta((byte)0x18, "SendDataMeta"),
|
||||
GetRandom((byte)0x1c,"GetRandom"), // ???
|
||||
MemoryGetId((byte)0x20,"MemoryGetId"), // ???
|
||||
MemoryGetByte((byte)0x21,"MemoryGetByte"), // Get a byte of memory.
|
||||
MemoryPutByte((byte)0x22, "MemoryPutByte"),
|
||||
ReadMemory((byte)0x23,"ReadMemory"), // Read memory.
|
||||
WriteMemory((byte)0x24, "WriteMemory"),
|
||||
SetLearnNodeState((byte)0x40,"SetLearnNodeState"), // ???
|
||||
IdentifyNode((byte)0x41,"IdentifyNode"), // Get protocol info (baud rate, listening, etc.) for a given node
|
||||
SetDefault((byte)0x42,"SetDefault"), // Reset controller and node info to default (original) values
|
||||
NewController((byte)0x43,"NewController"), // ???
|
||||
ReplicationCommandComplete((byte)0x44,"ReplicationCommandComplete"), // Replication send data complete
|
||||
ReplicationSendData((byte)0x45,"ReplicationSendData"), // Replication send data
|
||||
AssignReturnRoute((byte)0x46,"AssignReturnRoute"), // Assign a return route from the specified node to the controller
|
||||
DeleteReturnRoute((byte)0x47,"DeleteReturnRoute"), // Delete all return routes from the specified node
|
||||
RequestNodeNeighborUpdate((byte)0x48,"RequestNodeNeighborUpdate"), // Ask the specified node to update its neighbors (then read them from the controller)
|
||||
ApplicationUpdate((byte)0x49,"ApplicationUpdate"), // Get a list of supported (and controller) command classes
|
||||
AddNodeToNetwork((byte)0x4a,"AddNodeToNetwork"), // Control the addnode (or addcontroller) process...start, stop, etc.
|
||||
RemoveNodeFromNetwork((byte)0x4b,"RemoveNodeFromNetwork"), // Control the removenode (or removecontroller) process...start, stop, etc.
|
||||
CreateNewPrimary((byte)0x4c,"CreateNewPrimary"), // Control the createnewprimary process...start, stop, etc.
|
||||
ControllerChange((byte)0x4d,"ControllerChange"), // Control the transferprimary process...start, stop, etc.
|
||||
SetLearnMode((byte)0x50,"SetLearnMode"), // Put a controller into learn mode for replication/ receipt of configuration info
|
||||
AssignSucReturnRoute((byte)0x51,"AssignSucReturnRoute"), // Assign a return route to the SUC
|
||||
EnableSuc((byte)0x52,"EnableSuc"), // Make a controller a Static Update Controller
|
||||
RequestNetworkUpdate((byte)0x53,"RequestNetworkUpdate"), // Network update for a SUC(?)
|
||||
SetSucNodeID((byte)0x54,"SetSucNodeID"), // Identify a Static Update Controller node id
|
||||
DeleteSUCReturnRoute((byte)0x55,"DeleteSUCReturnRoute"), // Remove return routes to the SUC
|
||||
GetSucNodeId((byte)0x56,"GetSucNodeId"), // Try to retrieve a Static Update Controller node id (zero if no SUC present)
|
||||
SendSucId((byte)0x57, "SendSucId"),
|
||||
RequestNodeNeighborUpdateOptions((byte)0x5a,"RequestNodeNeighborUpdateOptions"), // Allow options for request node neighbor update
|
||||
RequestNodeInfo((byte)0x60,"RequestNodeInfo"), // Get info (supported command classes) for the specified node
|
||||
RemoveFailedNodeID((byte)0x61,"RemoveFailedNodeID"), // Mark a specified node id as failed
|
||||
IsFailedNodeID((byte)0x62,"IsFailedNodeID"), // Check to see if a specified node has failed
|
||||
ReplaceFailedNode((byte)0x63,"ReplaceFailedNode"), // Remove a failed node from the controller's list (?)
|
||||
GetRoutingInfo((byte)0x80,"GetRoutingInfo"), // Get a specified node's neighbor information from the controller
|
||||
LockRoute((byte)0x90, "LockRoute"),
|
||||
SerialApiSlaveNodeInfo((byte)0xA0,"SerialApiSlaveNodeInfo"), // Set application virtual slave node information
|
||||
ApplicationSlaveCommandHandler((byte)0xA1,"ApplicationSlaveCommandHandler"), // Slave command handler
|
||||
SendSlaveNodeInfo((byte)0xA2,"ApplicationSlaveCommandHandler"), // Send a slave node information frame
|
||||
SendSlaveData((byte)0xA3,"SendSlaveData"), // Send data from slave
|
||||
SetSlaveLearnMode((byte)0xA4,"SetSlaveLearnMode"), // Enter slave learn mode
|
||||
GetVirtualNodes((byte)0xA5,"GetVirtualNodes"), // Return all virtual nodes
|
||||
IsVirtualNode((byte)0xA6,"IsVirtualNode"), // Virtual node test
|
||||
WatchDogEnable((byte)0xB6, "WatchDogEnable"),
|
||||
WatchDogDisable((byte)0xB7, "WatchDogDisable"),
|
||||
WatchDogKick((byte)0xB6, "WatchDogKick"),
|
||||
RfPowerLevelGet((byte)0xBA,"RfPowerLevelSet"), // Get RF Power level
|
||||
GetLibraryType((byte)0xBD, "GetLibraryType"), // Gets the type of ZWave library on the stick
|
||||
SendTestFrame((byte)0xBE, "SendTestFrame"), // Send a test frame to a node
|
||||
GetProtocolStatus((byte)0xBF, "GetProtocolStatus"),
|
||||
SetPromiscuousMode((byte)0xD0,"SetPromiscuousMode"), // Set controller into promiscuous mode to listen to all frames
|
||||
PromiscuousApplicationCommandHandler((byte)0xD1,"PromiscuousApplicationCommandHandler"),
|
||||
ALL((byte)0xFF, null);
|
||||
|
||||
public final byte data;
|
||||
public final String label;
|
||||
|
||||
ControllerMessageType(byte _data, String _label) {
|
||||
data = _data;
|
||||
label = _label;
|
||||
}
|
||||
|
||||
private static Map<Byte, ControllerMessageType> types = CollectionUtils.transformToMap(Arrays.asList(values()), _type->_type.data);
|
||||
public static ControllerMessageType fromByte(byte _data) {
|
||||
ControllerMessageType type = types.get(_data);
|
||||
return type == null ? ControllerMessageType.None : type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public interface IMessageSubscriber<T extends Message> {
|
||||
Class<T> getHandledMessageClass();
|
||||
void onMessage(T _message);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class Message {
|
||||
protected byte nodeId;
|
||||
protected final ControllerMessageType controllerMessageType;
|
||||
protected final MessageType messageType;
|
||||
protected final CommandClass commandClass;
|
||||
protected final byte command;
|
||||
|
||||
public Message(ControllerMessageType _controllerMessageType, MessageType _messageType, CommandClass _commandClass, byte _command) {
|
||||
this((byte) 0, _controllerMessageType, _messageType, _commandClass, _command);
|
||||
}
|
||||
|
||||
public Message(byte _nodeId, ControllerMessageType _controllerMessageType, MessageType _messageType, CommandClass _commandClass, byte _command) {
|
||||
nodeId = _nodeId;
|
||||
controllerMessageType = _controllerMessageType;
|
||||
messageType = _messageType;
|
||||
commandClass = _commandClass;
|
||||
command = _command;
|
||||
}
|
||||
|
||||
public byte getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(byte _nodeId) {
|
||||
nodeId = _nodeId;
|
||||
}
|
||||
|
||||
public byte[] toPayload() {
|
||||
try {
|
||||
byte[] payload = getPayload();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
if (nodeId > 0)
|
||||
os.write(nodeId);
|
||||
|
||||
if (commandClass != CommandClass.NO_OPERATION) {
|
||||
os.write(payload.length + 2);
|
||||
os.write(commandClass.data);
|
||||
os.write(command);
|
||||
}
|
||||
if (payload.length > 0)
|
||||
os.write(payload);
|
||||
os.close();
|
||||
return os.toByteArray();
|
||||
} catch (IOException _e) {
|
||||
_e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void fromPayload(byte[] _payload) {
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public byte[] toByteArray(byte _transmitOptions, byte _callbackId) {
|
||||
try {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
byte[] payload = toPayload();
|
||||
os.write((byte) 0x01);
|
||||
int messageLength = payload.length + (isCallbackExpected() ? 5 : 3);
|
||||
os.write((byte) messageLength);
|
||||
os.write(messageType.data);
|
||||
os.write(controllerMessageType.data);
|
||||
if (payload.length > 0)
|
||||
os.write(payload);
|
||||
|
||||
if (isCallbackExpected()) {
|
||||
os.write(_transmitOptions);
|
||||
os.write(_callbackId);
|
||||
}
|
||||
|
||||
os.write((byte) 1);
|
||||
byte[] msg = os.toByteArray();
|
||||
msg[msg.length - 1] = calculateChecksum(msg);
|
||||
return msg;
|
||||
} catch (IOException _e) {
|
||||
_e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return toKey(controllerMessageType.data, messageType.data, commandClass.data, command);
|
||||
}
|
||||
|
||||
public static String toKey(byte _controllerMessageType, byte _messageType, byte _commandClass, byte _command) {
|
||||
return String.format("%02X%02X%02X%02X", _controllerMessageType, _messageType, _commandClass, _command);
|
||||
}
|
||||
|
||||
public static byte calculateChecksum(byte[] buffer) {
|
||||
byte checkSum = (byte) 0xFF;
|
||||
for (int i = 1; i < buffer.length - 1; i++) {
|
||||
checkSum = (byte) (checkSum ^ buffer[i]);
|
||||
}
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
protected byte[] asByteArray(int _byte) {
|
||||
byte[] ret = new byte[1];
|
||||
ret[0] = (byte) _byte;
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected byte[] asByteArray(byte... _bytes) {
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public boolean isCallbackExpected() {
|
||||
return (controllerMessageType == ControllerMessageType.SendData) && (messageType == MessageType.REQUEST);
|
||||
}
|
||||
|
||||
public String describe() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public abstract class MessageEngine {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessageEngine.class);
|
||||
|
||||
private static final Map<String, Message> messages = new HashMap<>();
|
||||
private static final Map<Class<?>, List<IMessageSubscriber<?>>> subscribers = new HashMap<>();
|
||||
static {
|
||||
for (Message m : ServiceLoader.load(Message.class)) {
|
||||
messages.put(m.getKey(), m);
|
||||
}
|
||||
for (IMessageSubscriber s : ServiceLoader.load(IMessageSubscriber.class)) {
|
||||
subscribe(s);
|
||||
}
|
||||
}
|
||||
|
||||
public static Message decode(byte[] _data) {
|
||||
byte messageCheckSum = Message.calculateChecksum(_data);
|
||||
byte messageCheckSumReceived = _data[_data.length - 1];
|
||||
if (messageCheckSum != messageCheckSumReceived) {
|
||||
logger.debug("Invalid checksum for message: {}", NullUtils.toHex(_data));
|
||||
return null;
|
||||
}
|
||||
MessageType messageType = _data[2] == 0x00 ? MessageType.REQUEST : MessageType.RESPONSE;
|
||||
ControllerMessageType controllerMessageType = ControllerMessageType.fromByte((byte)(_data[3] & 0xFF));
|
||||
int offset = ((messageType == MessageType.REQUEST) && NullUtils.isOneOf(controllerMessageType, ControllerMessageType.SendData, ControllerMessageType.ApplicationCommandHandler))?7:5;
|
||||
CommandClass commandClass = _data.length > offset + 1 ? CommandClass.fromByte((byte)(_data[offset] & 0xFF)):CommandClass.NO_OPERATION;
|
||||
byte command = ((commandClass == CommandClass.NO_OPERATION) || (_data.length <= offset+2))?0:(byte)(_data[offset+1] & 0xFF);
|
||||
Message message = messages.get(Message.toKey(controllerMessageType.data, messageType.data, commandClass.data, command));
|
||||
if (message == null) {
|
||||
logger.debug("Could not find message class for message: {} {} {} {}", controllerMessageType.label, messageType.name(), commandClass.label, command);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Message ret = message.getClass().newInstance();
|
||||
ret.fromPayload(_data);
|
||||
return ret;
|
||||
} catch (Exception _e) {
|
||||
_e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void publish(Message _m) {
|
||||
for (IMessageSubscriber s : CollectionUtils.makeNotNull(subscribers.get(_m.getClass()))) {
|
||||
s.onMessage(_m);
|
||||
}
|
||||
}
|
||||
|
||||
public static void subscribe(IMessageSubscriber<?> _subscriber) {
|
||||
CollectionUtils.addToMultiMap(_subscriber.getHandledMessageClass(), _subscriber, subscribers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public enum MessageType {
|
||||
REQUEST((byte)0),
|
||||
RESPONSE((byte)1);
|
||||
|
||||
public final byte data;
|
||||
|
||||
MessageType(byte _data) {
|
||||
data = _data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public abstract class MessageUtil {
|
||||
private static final int SIZE_MASK = 0x07;
|
||||
private static final int SCALE_MASK = 0x18;
|
||||
private static final int SCALE_SHIFT = 0x03;
|
||||
private static final int PRECISION_MASK = 0xe0;
|
||||
private static final int PRECISION_SHIFT = 0x05;
|
||||
|
||||
public static double getTemperatureCelsius(byte[] _payload, int _offset) {
|
||||
int size = _payload[_offset] & SIZE_MASK;
|
||||
int scale = (_payload[_offset] & SCALE_MASK) >> SCALE_SHIFT;
|
||||
int precision = (_payload[_offset] & PRECISION_MASK) >> PRECISION_SHIFT;
|
||||
|
||||
if ((size+_offset) >= _payload.length)
|
||||
return 0.0;
|
||||
|
||||
int value = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
value <<= 8;
|
||||
value |= _payload[_offset + i + 1] & 0xFF;
|
||||
}
|
||||
|
||||
BigDecimal result;
|
||||
if ((_payload[_offset + 1] & 0x80) == 0x80) {
|
||||
if (size == 1)
|
||||
value |= 0xffffff00;
|
||||
else if (size == 2)
|
||||
value |= 0xffff0000;
|
||||
}
|
||||
result = BigDecimal.valueOf(value);
|
||||
BigDecimal divisor = BigDecimal.valueOf(Math.pow(10, precision));
|
||||
double temp = result.divide(divisor, RoundingMode.HALF_EVEN).doubleValue();
|
||||
return (scale == 1) ? (temp-32)/1.8 : temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public abstract class NoCommandRequestMessage extends RequestMessage {
|
||||
public NoCommandRequestMessage(ControllerMessageType _controllerMessageType) {
|
||||
this((byte)0, _controllerMessageType);
|
||||
}
|
||||
|
||||
public NoCommandRequestMessage(byte _nodeId, ControllerMessageType _controllerMessageType) {
|
||||
super(_nodeId, _controllerMessageType, CommandClass.NO_OPERATION, (byte) 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public abstract class NoCommandResponseMessage extends ResponseMessage {
|
||||
public NoCommandResponseMessage(ControllerMessageType _controllerMessageType) {
|
||||
super(_controllerMessageType, CommandClass.NO_OPERATION, (byte) 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public abstract class RequestMessage extends Message {
|
||||
public RequestMessage(ControllerMessageType _controllerMessageType, CommandClass _commandClass, byte _command) {
|
||||
this((byte)0, _controllerMessageType, _commandClass, _command);
|
||||
}
|
||||
|
||||
public RequestMessage(byte _nodeId, ControllerMessageType _controllerMessageType, CommandClass _commandClass, byte _command) {
|
||||
super(_nodeId, _controllerMessageType, MessageType.REQUEST, _commandClass, _command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public abstract class ResponseMessage extends Message {
|
||||
public ResponseMessage(ControllerMessageType _controllerMessageType, CommandClass _commandClass, byte _command) {
|
||||
this((byte) 0, _controllerMessageType, _commandClass, _command);
|
||||
}
|
||||
|
||||
public ResponseMessage(byte _nodeId, ControllerMessageType _controllerMessageType, CommandClass _commandClass, byte _command) {
|
||||
super(_nodeId, _controllerMessageType, MessageType.RESPONSE, _commandClass, _command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.zwave.message;
|
||||
|
||||
public abstract class SendDataRequestMessage extends RequestMessage {
|
||||
public SendDataRequestMessage(CommandClass _commandClass, byte _command) {
|
||||
this((byte)0, _commandClass, _command);
|
||||
}
|
||||
|
||||
public SendDataRequestMessage(byte _nodeId, CommandClass _commandClass, byte _command) {
|
||||
super(_nodeId, ControllerMessageType.SendData, _commandClass, _command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ApplicationUpdateRequest extends RequestMessage {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ApplicationUpdateRequest.class);
|
||||
|
||||
private List<CommandClass> commandClasses;
|
||||
|
||||
public ApplicationUpdateRequest() {
|
||||
super(ControllerMessageType.ApplicationUpdate, CommandClass.NO_OPERATION, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
nodeId = _payload[5];
|
||||
if (_payload[4] == (byte) 0x84)
|
||||
logger.debug("Received node information for node: {}", nodeId);
|
||||
int length = _payload[6];
|
||||
commandClasses = new ArrayList<>();
|
||||
for (int i = 7; i < length + 7; i++) {
|
||||
if (_payload[i] != (byte) 0xef) {
|
||||
CommandClass commandClass = CommandClass.fromByte(_payload[i]);
|
||||
if (commandClass != CommandClass.NO_OPERATION) {
|
||||
logger.debug("Received command class: {} for node: {}", commandClass.name(), nodeId);
|
||||
commandClasses.add(commandClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<CommandClass> getCommandClasses() {
|
||||
return commandClasses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
|
||||
public class BinarySwitchSetRequest extends SendDataRequestMessage {
|
||||
private boolean on;
|
||||
|
||||
public BinarySwitchSetRequest() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public BinarySwitchSetRequest(boolean _on) {
|
||||
this((byte)0, _on);
|
||||
}
|
||||
|
||||
public BinarySwitchSetRequest(byte _nodeId, boolean _on) {
|
||||
super(_nodeId, CommandClass.SWITCH_BINARY, (byte)0x01);
|
||||
on = _on;
|
||||
}
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(boolean _on) {
|
||||
on = _on;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return asByteArray(on?0xFF:0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " on: " + on;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandRequestMessage;
|
||||
|
||||
public class ByteMessage extends NoCommandRequestMessage {
|
||||
private byte b;
|
||||
|
||||
public ByteMessage() {
|
||||
super(ControllerMessageType.None);
|
||||
}
|
||||
|
||||
public ByteMessage(byte _b) {
|
||||
super(ControllerMessageType.None);
|
||||
b = _b;
|
||||
}
|
||||
|
||||
public byte getByte() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setByte(byte _b) {
|
||||
b = _b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray(byte _transmitOptions, byte _callbackId) {
|
||||
return asByteArray(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandRequestMessage;
|
||||
|
||||
public class ControllerCapabilitiesRequest extends NoCommandRequestMessage {
|
||||
public ControllerCapabilitiesRequest() {
|
||||
super(ControllerMessageType.GetCapabilities);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandResponseMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ControllerCapabilitiesResponse extends NoCommandResponseMessage {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ControllerCapabilitiesResponse.class);
|
||||
|
||||
private String serialAPIVersion;
|
||||
private int manufacturerId;
|
||||
private int deviceType;
|
||||
private int deviceId;
|
||||
private Set<CommandClass> supportedCommandClasses;
|
||||
|
||||
public ControllerCapabilitiesResponse() {
|
||||
super(ControllerMessageType.GetCapabilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
serialAPIVersion = String.format("%d.%d", _payload[4], _payload[5]);
|
||||
manufacturerId = getShort(_payload, 6);
|
||||
deviceType = getShort(_payload, 8);
|
||||
deviceId = getShort(_payload, 10);
|
||||
supportedCommandClasses = new HashSet<>();
|
||||
for (int by = 12; by < _payload.length-1; by++) {
|
||||
for (int bi = 0; bi < 8; bi++) {
|
||||
if ((_payload[by] & (0x01 << bi)) != 0) {
|
||||
byte commandClassByte = (byte) (((by - 12) << 3) + bi + 1);
|
||||
CommandClass commandClass = CommandClass.fromByte(commandClassByte);
|
||||
if (commandClass != CommandClass.NO_OPERATION) {
|
||||
logger.debug("Supports command class: {}", commandClass.label);
|
||||
supportedCommandClasses.add(commandClass);
|
||||
} else {
|
||||
logger.debug("Supports unknown command class: {}", commandClassByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getShort(byte[] _data, int _offset) {
|
||||
return (toShort(_data[_offset]) << 8) | toShort(_data[_offset + 1]);
|
||||
}
|
||||
|
||||
private int toShort(byte _bt) {
|
||||
return _bt & 0xFF;
|
||||
}
|
||||
|
||||
public String getSerialAPIVersion() {
|
||||
return serialAPIVersion;
|
||||
}
|
||||
|
||||
public int getManufacturerId() {
|
||||
return manufacturerId;
|
||||
}
|
||||
|
||||
public int getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public Set<CommandClass> getSupportedCommandClasses() {
|
||||
return supportedCommandClasses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandRequestMessage;
|
||||
|
||||
public class ControllerInitialDataRequest extends NoCommandRequestMessage {
|
||||
public ControllerInitialDataRequest() {
|
||||
super(ControllerMessageType.SerialApiGetInitData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandResponseMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ControllerInitialDataResponse extends NoCommandResponseMessage {
|
||||
private boolean master;
|
||||
private boolean primary;
|
||||
private List<Byte> nodeIds;
|
||||
|
||||
public ControllerInitialDataResponse() {
|
||||
super(ControllerMessageType.SerialApiGetInitData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
int length = _payload[6];
|
||||
if (length == 29) {
|
||||
byte nodeId = 1;
|
||||
nodeIds = new ArrayList<>();
|
||||
for (int i = 7; i < 7 + length; i++) {
|
||||
byte curByte = _payload[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
int bit = 1 << j;
|
||||
if ((curByte & bit) == bit) {
|
||||
nodeIds.add(nodeId);
|
||||
}
|
||||
nodeId++;
|
||||
}
|
||||
}
|
||||
master = (_payload[5] & 0x1) == 0;
|
||||
primary = (_payload[5] & 0x4) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMaster() {
|
||||
return master;
|
||||
}
|
||||
|
||||
public boolean isPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public List<Byte> getNodeIds() {
|
||||
return nodeIds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
public class DeviceManufacturerActionRequest extends RequestMessage {
|
||||
public DeviceManufacturerActionRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public DeviceManufacturerActionRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.SendData, CommandClass.MANUFACTURER_SPECIFIC, (byte) 0x04);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandRequestMessage;
|
||||
|
||||
public class GetControllerIdRequest extends NoCommandRequestMessage {
|
||||
public GetControllerIdRequest() {
|
||||
super(ControllerMessageType.MemoryGetId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandResponseMessage;
|
||||
|
||||
public class GetControllerIdResponse extends NoCommandResponseMessage {
|
||||
private long homeId;
|
||||
private int controllerId;
|
||||
|
||||
public GetControllerIdResponse() {
|
||||
super(ControllerMessageType.MemoryGetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
homeId = (getByte(_payload, 4) << 24) | (getByte(_payload, 5) << 16) | (getByte(_payload, 6) << 8) | getByte(_payload, 7);
|
||||
controllerId = _payload[8];
|
||||
}
|
||||
|
||||
public long getHomeId() {
|
||||
return homeId;
|
||||
}
|
||||
|
||||
public void setHomeId(int _homeId) {
|
||||
homeId = _homeId;
|
||||
}
|
||||
|
||||
public int getControllerId() {
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
public void setControllerId(int _controllerId) {
|
||||
controllerId = _controllerId;
|
||||
}
|
||||
|
||||
private long getByte(byte[] _data, int _offset) {
|
||||
return _data[_offset] & 0xFF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
public class MultilevelSensorGetRequest extends RequestMessage {
|
||||
public MultilevelSensorGetRequest() {
|
||||
this((byte)0);
|
||||
}
|
||||
|
||||
public MultilevelSensorGetRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.SendData, CommandClass.SENSOR_MULTILEVEL, (byte)0x04);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.MessageUtil;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
public class MultilevelSensorReportRequest extends RequestMessage {
|
||||
private double temperature;
|
||||
|
||||
public MultilevelSensorReportRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public MultilevelSensorReportRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.ApplicationCommandHandler, CommandClass.SENSOR_MULTILEVEL, (byte) 0x05);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
nodeId = _payload[5];
|
||||
if (_payload[9] == (byte) 1)
|
||||
temperature = MessageUtil.getTemperatureCelsius(_payload, 10);
|
||||
}
|
||||
|
||||
public double getTemperatureCelsius() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " level: " + temperature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
public class MultilevelSwitchReportRequest extends RequestMessage {
|
||||
private int level;
|
||||
|
||||
public MultilevelSwitchReportRequest() {
|
||||
super(ControllerMessageType.ApplicationCommandHandler, CommandClass.SWITCH_MULTILEVEL, (byte) 0x03);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
nodeId = _payload[5];
|
||||
level = _payload[9];
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " level: " + level;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
|
||||
public class MultilevelSwitchSetRequest extends SendDataRequestMessage {
|
||||
private int level;
|
||||
|
||||
public MultilevelSwitchSetRequest() {
|
||||
this(99);
|
||||
}
|
||||
|
||||
public MultilevelSwitchSetRequest(int _level) {
|
||||
this((byte)0, _level);
|
||||
}
|
||||
|
||||
public MultilevelSwitchSetRequest(byte _nodeId, int _level) {
|
||||
super(_nodeId, CommandClass.SWITCH_MULTILEVEL, (byte) 0x01);
|
||||
level = _level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return asByteArray(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " level: " + level;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandRequestMessage;
|
||||
|
||||
public class NodeInfoRequest extends NoCommandRequestMessage {
|
||||
public NodeInfoRequest() {
|
||||
super(ControllerMessageType.RequestNodeInfo);
|
||||
}
|
||||
|
||||
public NodeInfoRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.RequestNodeInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.NoCommandResponseMessage;
|
||||
|
||||
public class NodeInfoResponse extends NoCommandResponseMessage {
|
||||
public NodeInfoResponse() {
|
||||
super(ControllerMessageType.RequestNodeInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
public class SendDataRequest extends RequestMessage {
|
||||
public enum TransmissionState {
|
||||
COMPLETE_OK((byte) 0x00, "Transmission complete and ACK received"),
|
||||
COMPLETE_NO_ACK((byte) 0x01, "Transmission complete, no ACK received"),
|
||||
COMPLETE_FAIL((byte) 0x02, "Transmission failed"),
|
||||
COMPLETE_NOT_IDLE((byte) 0x03, "Transmission failed, network busy"),
|
||||
COMPLETE_NOROUTE((byte) 0x04, "Tranmission complete, no return route");
|
||||
|
||||
public byte key;
|
||||
public String label;
|
||||
|
||||
TransmissionState(byte _key, String _label) {
|
||||
key = _key;
|
||||
label = _label;
|
||||
}
|
||||
|
||||
public static TransmissionState fromKey(byte _key) {
|
||||
for (TransmissionState state : values()) {
|
||||
if (state.key == _key)
|
||||
return state;
|
||||
}
|
||||
return COMPLETE_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
private TransmissionState state;
|
||||
private byte callbackId;
|
||||
|
||||
public SendDataRequest() {
|
||||
super(ControllerMessageType.SendData, CommandClass.NO_OPERATION, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
if (CollectionUtils.length(_payload) > 5) {
|
||||
callbackId = _payload[4];
|
||||
state = TransmissionState.fromKey(_payload[5]);
|
||||
}
|
||||
}
|
||||
|
||||
public TransmissionState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public byte getCallbackId() {
|
||||
return callbackId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " callbackId: " + callbackId + " state: " + state.name();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.ResponseMessage;
|
||||
|
||||
public class SendDataResponse extends ResponseMessage {
|
||||
private byte response;
|
||||
|
||||
public SendDataResponse() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public SendDataResponse(byte _response) {
|
||||
super(ControllerMessageType.SendData, CommandClass.NO_OPERATION, (byte) 0);
|
||||
response = _response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
if (CollectionUtils.length(_payload) > 0)
|
||||
response = _payload[0];
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return response != 0;
|
||||
}
|
||||
|
||||
public String describe() {
|
||||
return name() + ": " + (isSuccess() ? "SUCCESS" : "FAILURE");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
|
||||
public class ThermostatModeGetRequest extends SendDataRequestMessage {
|
||||
public ThermostatModeGetRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public ThermostatModeGetRequest(byte _nodeId) {
|
||||
super(_nodeId, CommandClass.THERMOSTAT_MODE, (byte) 0x02);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatMode;
|
||||
|
||||
public class ThermostatModeSetRequest extends SendDataRequestMessage {
|
||||
private ThermostatMode mode;
|
||||
|
||||
public ThermostatModeSetRequest() {
|
||||
this((byte) 0, ThermostatMode.OFF);
|
||||
}
|
||||
|
||||
public ThermostatModeSetRequest(byte _nodeId, ThermostatMode _mode) {
|
||||
super(_nodeId, CommandClass.THERMOSTAT_MODE, (byte) 0x01);
|
||||
mode = _mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return asByteArray(mode.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
||||
|
||||
public class ThermostatSetPointGetRequest extends SendDataRequestMessage {
|
||||
private ThermostatSetPointIndex index;
|
||||
|
||||
public ThermostatSetPointGetRequest() {
|
||||
this((byte) 0, ThermostatSetPointIndex.HEATING);
|
||||
}
|
||||
|
||||
public ThermostatSetPointGetRequest(byte _nodeId, ThermostatSetPointIndex _index) {
|
||||
super(_nodeId, CommandClass.THERMOSTAT_SETPOINT, (byte) 0x02);
|
||||
index = _index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return asByteArray(index.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.MessageUtil;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
||||
|
||||
public class ThermostatSetPointReportRequest extends RequestMessage {
|
||||
private ThermostatSetPointIndex index;
|
||||
private double temperature;
|
||||
|
||||
public ThermostatSetPointReportRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public ThermostatSetPointReportRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.ApplicationCommandHandler, CommandClass.THERMOSTAT_SETPOINT, (byte) 0x03);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
nodeId = _payload[5];
|
||||
index = ThermostatSetPointIndex.fromIndex(_payload[9]);
|
||||
if (index != null)
|
||||
temperature = MessageUtil.getTemperatureCelsius(_payload, 10);
|
||||
}
|
||||
|
||||
public ThermostatSetPointIndex getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public double getTemperatureCelsius() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " level: " + temperature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
||||
|
||||
public class ThermostatSetPointSetRequest extends SendDataRequestMessage {
|
||||
private ThermostatSetPointIndex index;
|
||||
private int level;
|
||||
|
||||
public ThermostatSetPointSetRequest() {
|
||||
this(ThermostatSetPointIndex.HEATING, 72);
|
||||
}
|
||||
|
||||
public ThermostatSetPointSetRequest(ThermostatSetPointIndex _index, int _level) {
|
||||
this((byte)0, _index, _level);
|
||||
}
|
||||
|
||||
public ThermostatSetPointSetRequest(byte _nodeId, ThermostatSetPointIndex _index, int _level) {
|
||||
super(_nodeId, CommandClass.THERMOSTAT_SETPOINT, (byte) 0x01);
|
||||
index = _index;
|
||||
level = _level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return asByteArray(index.index, (byte)9, (byte)level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId + " level: " + level;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||
|
||||
public class ThermostatSetPointSupportedGetRequest extends SendDataRequestMessage {
|
||||
public ThermostatSetPointSupportedGetRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public ThermostatSetPointSupportedGetRequest(byte _nodeId) {
|
||||
super(_nodeId, CommandClass.THERMOSTAT_SETPOINT, (byte) 0x04);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.lanternsoftware.zwave.message.impl;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class ThermostatSetPointSupportedReportRequest extends RequestMessage {
|
||||
private Set<Byte> supportedSetPointIndices;
|
||||
|
||||
public ThermostatSetPointSupportedReportRequest() {
|
||||
this((byte) 0);
|
||||
}
|
||||
|
||||
public ThermostatSetPointSupportedReportRequest(byte _nodeId) {
|
||||
super(_nodeId, ControllerMessageType.ApplicationCommandHandler, CommandClass.THERMOSTAT_SETPOINT, (byte) 0x05);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromPayload(byte[] _payload) {
|
||||
supportedSetPointIndices = new TreeSet<>();
|
||||
for (int i = 9; i < _payload.length - 1; ++i) {
|
||||
for (int bit = 0; bit < 8; ++bit) {
|
||||
if ((_payload[i] & (1 << bit)) != 0) {
|
||||
supportedSetPointIndices.add((byte)(((i - 9) << 3) + bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Byte> getSupportedSetPointIndices() {
|
||||
return supportedSetPointIndices;
|
||||
}
|
||||
|
||||
public boolean isSupportedIndex(byte _index) {
|
||||
return CollectionUtils.contains(supportedSetPointIndices, _index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return name() + " node: " + nodeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.lanternsoftware.zwave.message.thermostat;
|
||||
|
||||
public enum ThermostatMode {
|
||||
OFF((byte)0),
|
||||
HEAT((byte)1),
|
||||
COOL((byte)2),
|
||||
AUTO((byte)3),
|
||||
AUXILIARY((byte)4);
|
||||
|
||||
public final byte data;
|
||||
|
||||
ThermostatMode(byte _data) {
|
||||
data = _data;
|
||||
}
|
||||
|
||||
public static ThermostatMode fromByte(byte _bt) {
|
||||
for (ThermostatMode mode : values()) {
|
||||
if (mode.data == _bt)
|
||||
return mode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.lanternsoftware.zwave.message.thermostat;
|
||||
|
||||
public enum ThermostatSetPointIndex {
|
||||
HEATING((byte)1),
|
||||
COOLING((byte)2),
|
||||
FURNACE((byte)7),
|
||||
DRY_AIR((byte)8),
|
||||
MOIST_AIR((byte)9),
|
||||
AUTO_CHANGEOVER((byte)10),
|
||||
HEATING_ECON((byte)11),
|
||||
COOLING_ECON((byte)12),
|
||||
AWAY_HEATING((byte)13),
|
||||
COOLING_HEATING((byte)14),
|
||||
HEATING_MINIMUM((byte)101),
|
||||
COOLING_MINIMUM((byte)102),
|
||||
FURNACE_MINIMUM((byte)107),
|
||||
DRY_AIR_MINIMUM((byte)108),
|
||||
MOIST_AIR_MINIMUM((byte)109),
|
||||
AUTO_CHANGEOVER_MINIMUM((byte)110),
|
||||
HEATING_ECON_MINIMUM((byte)111),
|
||||
COOLING_ECON_MINIMUM((byte)112),
|
||||
AWAY_HEATING_MINIMUM((byte)113),
|
||||
COOLING_HEATING_MINIMUM((byte)114),
|
||||
HEATING_MAXIMUM((byte)201),
|
||||
COOLING_MAXIMUM((byte)202),
|
||||
FURNACE_MAXIMUM((byte)207),
|
||||
DRY_AIR_MAXIMUM((byte)208),
|
||||
MOIST_AIR_MAXIMUM((byte)209),
|
||||
AUTO_CHANGEOVER_MAXIMUM((byte)210),
|
||||
HEATING_ECON_MAXIMUM((byte)211),
|
||||
COOLING_ECON_MAXIMUM((byte)212),
|
||||
AWAY_HEATING_MAXIMUM((byte)213),
|
||||
COOLING_HEATING_MAXIMUM((byte)214);
|
||||
|
||||
public final byte index;
|
||||
|
||||
ThermostatSetPointIndex(byte _index) {
|
||||
index = _index;
|
||||
}
|
||||
|
||||
public static ThermostatSetPointIndex fromIndex(byte _index) {
|
||||
for (ThermostatSetPointIndex idx : values()) {
|
||||
if (idx.index == _index)
|
||||
return idx;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.lanternsoftware.zwave.node;
|
||||
|
||||
import com.lanternsoftware.zwave.message.CommandClass;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class Node {
|
||||
private byte id;
|
||||
private Set<CommandClass> commandClasses;
|
||||
|
||||
public Node() {
|
||||
}
|
||||
|
||||
public Node(byte _id, Set<CommandClass> _commandClasses) {
|
||||
id = _id;
|
||||
commandClasses = _commandClasses;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(byte _id) {
|
||||
id = _id;
|
||||
}
|
||||
|
||||
public Set<CommandClass> getCommandClasses() {
|
||||
return commandClasses;
|
||||
}
|
||||
|
||||
public void setCommandClasses(Set<CommandClass> _commandClasses) {
|
||||
commandClasses = _commandClasses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.lanternsoftware.zwave.node;
|
||||
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.zwave.controller.Controller;
|
||||
import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
||||
import com.lanternsoftware.zwave.message.MessageEngine;
|
||||
import com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest;
|
||||
import com.lanternsoftware.zwave.message.impl.ControllerInitialDataResponse;
|
||||
import com.lanternsoftware.zwave.message.impl.GetControllerIdResponse;
|
||||
import com.lanternsoftware.zwave.message.impl.NodeInfoRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class NodeManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger(NodeManager.class);
|
||||
|
||||
private Controller controller;
|
||||
private ControllerInitialDataResponse initialDataResponse;
|
||||
private GetControllerIdResponse controllerIdResponse;
|
||||
private final Set<Byte> missingNodes = new HashSet<>();
|
||||
private Map<Byte, Node> nodes = new HashMap<>();
|
||||
|
||||
public NodeManager(final Controller _controller) {
|
||||
controller = _controller;
|
||||
MessageEngine.subscribe(new IMessageSubscriber<ControllerInitialDataResponse>() {
|
||||
@Override
|
||||
public Class<ControllerInitialDataResponse> getHandledMessageClass() {
|
||||
return ControllerInitialDataResponse.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ControllerInitialDataResponse _response) {
|
||||
synchronized (NodeManager.this) {
|
||||
initialDataResponse = _response;
|
||||
init();
|
||||
}
|
||||
}
|
||||
});
|
||||
MessageEngine.subscribe(new IMessageSubscriber<GetControllerIdResponse>() {
|
||||
@Override
|
||||
public Class<GetControllerIdResponse> getHandledMessageClass() {
|
||||
return GetControllerIdResponse.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(GetControllerIdResponse _response) {
|
||||
synchronized (NodeManager.this) {
|
||||
controllerIdResponse = _response;
|
||||
init();
|
||||
}
|
||||
}
|
||||
});
|
||||
MessageEngine.subscribe(new IMessageSubscriber<ApplicationUpdateRequest>() {
|
||||
@Override
|
||||
public Class<ApplicationUpdateRequest> getHandledMessageClass() {
|
||||
return ApplicationUpdateRequest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ApplicationUpdateRequest _request) {
|
||||
synchronized (NodeManager.this) {
|
||||
if (missingNodes.remove(_request.getNodeId()))
|
||||
nodes.put(_request.getNodeId(), new Node(_request.getNodeId(), CollectionUtils.asHashSet(_request.getCommandClasses())));
|
||||
|
||||
logger.debug("Received command classes for node: {}", _request.getNodeId());
|
||||
requestNodeInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (!isStarted())
|
||||
return;
|
||||
missingNodes.clear();
|
||||
logger.info("Node Ids:{}", CollectionUtils.transformToCommaSeparated(initialDataResponse.getNodeIds(), String::valueOf));
|
||||
// missingNodes.addAll(CollectionUtils.filter(initialDataResponse.getNodeIds(), _b->_b != controllerIdResponse.getControllerId()));
|
||||
requestNodeInfo();
|
||||
}
|
||||
|
||||
private void requestNodeInfo() {
|
||||
if (!missingNodes.isEmpty())
|
||||
controller.send(new NodeInfoRequest(CollectionUtils.getFirst(missingNodes)));
|
||||
else
|
||||
notify();
|
||||
}
|
||||
|
||||
private boolean isStarted() {
|
||||
return ((initialDataResponse != null) && (controllerIdResponse != null));
|
||||
}
|
||||
|
||||
public void waitForStartup() {
|
||||
synchronized (this) {
|
||||
if (!isStarted()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
|
||||
com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest
|
||||
com.lanternsoftware.zwave.message.impl.ByteMessage
|
||||
com.lanternsoftware.zwave.message.impl.ControllerCapabilitiesRequest
|
||||
com.lanternsoftware.zwave.message.impl.ControllerCapabilitiesResponse
|
||||
com.lanternsoftware.zwave.message.impl.ControllerInitialDataRequest
|
||||
com.lanternsoftware.zwave.message.impl.ControllerInitialDataResponse
|
||||
com.lanternsoftware.zwave.message.impl.DeviceManufacturerActionRequest
|
||||
com.lanternsoftware.zwave.message.impl.GetControllerIdRequest
|
||||
com.lanternsoftware.zwave.message.impl.GetControllerIdResponse
|
||||
com.lanternsoftware.zwave.message.impl.MultilevelSensorGetRequest
|
||||
com.lanternsoftware.zwave.message.impl.MultilevelSensorReportRequest
|
||||
com.lanternsoftware.zwave.message.impl.MultilevelSwitchReportRequest
|
||||
com.lanternsoftware.zwave.message.impl.MultilevelSwitchSetRequest
|
||||
com.lanternsoftware.zwave.message.impl.NodeInfoRequest
|
||||
com.lanternsoftware.zwave.message.impl.NodeInfoResponse
|
||||
com.lanternsoftware.zwave.message.impl.SendDataRequest
|
||||
com.lanternsoftware.zwave.message.impl.SendDataResponse
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatModeGetRequest
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatSetPointGetRequest
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatSetPointReportRequest
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatSetPointSetRequest
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatSetPointSupportedGetRequest
|
||||
com.lanternsoftware.zwave.message.impl.ThermostatSetPointSupportedReportRequest
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.lanternsoftware.zwave;
|
||||
|
||||
public class TestBits {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Integer.toBinaryString(6));
|
||||
System.out.println(Integer.toBinaryString(0x18));
|
||||
}
|
||||
}
|
||||
21
zwave/pom.xml
Normal file
21
zwave/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
<groupId>com.lanternsoftware.zwave</groupId>
|
||||
<artifactId>zwave-reactor</artifactId>
|
||||
<name>zwave-reactor</name>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>lantern-datamodel-zwave</module>
|
||||
<module>lantern-service-thermometer</module>
|
||||
<module>lantern-service-zwave</module>
|
||||
<module>lantern-uirt</module>
|
||||
<module>lantern-zwave</module>
|
||||
</modules>
|
||||
</project>
|
||||
Reference in New Issue
Block a user