From 88933a2286df8efaaac93b7354a1565697e4b44e Mon Sep 17 00:00:00 2001 From: MarkBryanMilligan Date: Tue, 26 Oct 2021 15:45:13 -0500 Subject: [PATCH] Add rudimentary support for DS18B120 Thermometers, MH-Z19B CO2 Sensors, and ZWave.me controllers. --- zwave/lantern-service-thermometer/pom.xml | 19 +- .../thermometer/DS18B20Thermometer.java | 41 +++++ ...hermometerApp.java => HidThermometer.java} | 35 ++-- .../thermometer/ICO2Sensor.java | 6 + .../thermometer/IThermometer.java | 7 + .../thermometer/MHZ19BCO2Sensor.java | 165 ++++++++++++++++++ .../thermometer/TestThermo.java | 16 -- .../thermometer/context/Globals.java | 19 +- .../thermometer/servlet/TempServlet.java | 17 +- .../src/main/resources/logback.xml | 7 +- .../thermometer/TestStartup.java | 14 +- .../lanternsoftware/zwave/TestSecurity.java | 5 +- .../zwave/context/ZWaveApp.java | 3 + .../src/main/resources/logback.xml | 2 +- .../lanternsoftware/zwave/TestStartup.java | 4 +- .../zwave/controller/Controller.java | 9 +- .../zwave/message/MessageEngine.java | 14 +- .../message/impl/AddNodeToNetworkRequest.java | 17 ++ .../com.lanternsoftware.zwave.message.Message | 1 + 19 files changed, 334 insertions(+), 67 deletions(-) create mode 100644 zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/DS18B20Thermometer.java rename zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/{context/ThermometerApp.java => HidThermometer.java} (80%) create mode 100644 zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/ICO2Sensor.java create mode 100644 zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/IThermometer.java create mode 100644 zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/MHZ19BCO2Sensor.java delete mode 100644 zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/TestThermo.java create mode 100644 zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/AddNodeToNetworkRequest.java diff --git a/zwave/lantern-service-thermometer/pom.xml b/zwave/lantern-service-thermometer/pom.xml index bd618d2..3160a85 100644 --- a/zwave/lantern-service-thermometer/pom.xml +++ b/zwave/lantern-service-thermometer/pom.xml @@ -15,7 +15,7 @@ com.lanternsoftware.util - lantern-util-common + lantern-util-servlet 1.0.0 @@ -29,10 +29,25 @@ logback-classic 1.2.3 + + com.neuronrobotics + nrjavaserial + 5.2.1 + + + com.fazecast + jSerialComm + 2.5.1 + org.hid4java hid4java - 0.5.0 + 0.7.0 + + + com.pi4j + pi4j-device + 1.3 diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/DS18B20Thermometer.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/DS18B20Thermometer.java new file mode 100644 index 0000000..30e3b27 --- /dev/null +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/DS18B20Thermometer.java @@ -0,0 +1,41 @@ +package com.lanternsoftware.thermometer; + +import com.lanternsoftware.util.CollectionUtils; +import com.pi4j.component.temperature.TemperatureSensor; +import com.pi4j.component.temperature.impl.TmpDS18B20DeviceType; +import com.pi4j.io.w1.W1Device; +import com.pi4j.io.w1.W1Master; + +import java.util.List; + +public class DS18B20Thermometer implements IThermometer { + W1Device device; + + public static List devices() { + W1Master master = new W1Master(); + return CollectionUtils.transform(master.getDevices(TmpDS18B20DeviceType.FAMILY_CODE), DS18B20Thermometer::new); + } + + public DS18B20Thermometer() { + W1Master master = new W1Master(); + device = CollectionUtils.getFirst(master.getDevices(TmpDS18B20DeviceType.FAMILY_CODE)); + } + + public DS18B20Thermometer(W1Device _device) { + device = _device; + } + + @Override + public double getTemperatureCelsius() { + return device == null?-273:((TemperatureSensor) device).getTemperature(); + } + + @Override + public boolean isConnected() { + return device != null; + } + + @Override + public void shutdown() { + } +} diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/ThermometerApp.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/HidThermometer.java similarity index 80% rename from zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/ThermometerApp.java rename to zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/HidThermometer.java index a682b96..912ae3d 100644 --- a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/ThermometerApp.java +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/HidThermometer.java @@ -1,4 +1,4 @@ -package com.lanternsoftware.thermometer.context; +package com.lanternsoftware.thermometer; import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.concurrency.ConcurrencyUtils; @@ -11,14 +11,15 @@ import org.slf4j.LoggerFactory; import java.util.Timer; import java.util.TimerTask; -public class ThermometerApp { - private static final Logger LOG = LoggerFactory.getLogger(ThermometerApp.class); +public class HidThermometer implements IThermometer{ + private static final Logger LOG = LoggerFactory.getLogger(HidThermometer.class); private HidDevice device; private final Timer timer = new Timer(); private double lastTemp; + private final byte[] READ = hexToByte("0180330100000000"); - public void start() { + public HidThermometer() { HidServices hs = HidManager.getHidServices(); for (HidDevice d : hs.getAttachedHidDevices()) { if (NullUtils.isEqual(d.getVendorId(), (short) 0x413d) && NullUtils.isEqual(d.getProductId(), (short) 0x2107)) { @@ -27,11 +28,13 @@ public class ThermometerApp { } } if ((device != null) && device.open()) { - synchronized (device) { - read(hexToByte("0182770100000000")); - read(hexToByte("0186ff0100000000")); - read(hexToByte("0182770100000000")); - read(hexToByte("0182770100000000")); + final byte[] INIT1 = hexToByte("0182770100000000"); + final byte[] INIT2 = hexToByte("0186ff0100000000"); + synchronized (this) { + read(INIT1); + read(INIT2); + read(INIT1); + read(INIT1); } } else { LOG.error("Failed to open HID Device"); @@ -45,7 +48,11 @@ public class ThermometerApp { }, 0L, 10000L); } - public void stop() { + public boolean isConnected() { + return device != null; + } + + public void shutdown() { timer.cancel(); ConcurrencyUtils.sleep(10000); if (device != null) { @@ -100,14 +107,14 @@ public class ThermometerApp { } return response; } - public double getTemperature() { + public double getTemperatureCelsius() { return lastTemp; } - public double readTemperature() { + private double readTemperature() { if (device != null) { - synchronized (device) { - byte[] response = read(hexToByte("0180330100000000")); + synchronized (this) { + byte[] response = read(READ); if (response == null) return 5.0; int rawReading = ((response[3] & 0xFF) + (response[2] << 8)); diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/ICO2Sensor.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/ICO2Sensor.java new file mode 100644 index 0000000..a619e4f --- /dev/null +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/ICO2Sensor.java @@ -0,0 +1,6 @@ +package com.lanternsoftware.thermometer; + +public interface ICO2Sensor { + int getPPM(); + void shutdown(); +} diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/IThermometer.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/IThermometer.java new file mode 100644 index 0000000..cadb5e7 --- /dev/null +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/IThermometer.java @@ -0,0 +1,7 @@ +package com.lanternsoftware.thermometer; + +public interface IThermometer { + double getTemperatureCelsius(); + boolean isConnected(); + void shutdown(); +} diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/MHZ19BCO2Sensor.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/MHZ19BCO2Sensor.java new file mode 100644 index 0000000..921c6c9 --- /dev/null +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/MHZ19BCO2Sensor.java @@ -0,0 +1,165 @@ +package com.lanternsoftware.thermometer; + +import com.lanternsoftware.util.concurrency.ConcurrencyUtils; +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.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicInteger; + +public class MHZ19BCO2Sensor implements ICO2Sensor { + private static final Logger LOG = LoggerFactory.getLogger(MHZ19BCO2Sensor.class); + + private static final int DEFAULT_TIMEOUT = 1000; + + private static final byte[] CMD_GAS_CONCENTRATION = {(byte)0xff, 0x01, (byte)0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; + private static final byte[] CMD_CALIBRATE_ZERO_POINT = {(byte)0xff, 0x01, (byte)0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78}; + private static final byte[] CMD_AUTO_CALIBRATION_ON_WITHOUT_CHECKSUM = {(byte)0xff, 0x01, (byte)0x79, (byte)0xa0, 0x00, 0x00, 0x00, 0x00}; + private static final byte[] CMD_AUTO_CALIBRATION_OFF_WITHOUT_CHECKSUM = {(byte)0xff, 0x01, (byte)0x79, 0x00, 0x00, 0x00, 0x00, 0x00}; + + private static final int CALIBRATE_SPAN_POINT_MIN = 1000; + + private SerialPort serialPort; + private InputStream is; + private OutputStream os; + + private MHZ19BCO2Sensor(String _port) { + this(_port, DEFAULT_TIMEOUT); + } + + private MHZ19BCO2Sensor(String _port, int _timeout) { + try { + CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(_port); + serialPort = portIdentifier.open("co2port", 2000); + serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + serialPort.enableReceiveTimeout(_timeout); + serialPort.enableReceiveThreshold(9); + is = serialPort.getInputStream(); + os = serialPort.getOutputStream(); + } catch (Exception _e) { + if (serialPort != null) { + serialPort.close(); + serialPort = null; + } + LOG.error("Exception while starting MHZ19BCO2Sensor", _e); + } + } + + public void shutdown() { + IOUtils.closeQuietly(is); + IOUtils.closeQuietly(os); + if (serialPort != null) + serialPort.close(); + } + + private void write(byte[] out) { + try { + int length = is.available(); + if (length > 0) { + byte[] unread = new byte[length]; + int read = is.read(unread, 0, length); + LOG.debug("deleted unread buffer length:{}", read); + } + os.write(out, 0, out.length); + } + catch (Exception _e) { + LOG.error("Exception while writing to MHZ19B", _e); + } + } + + private byte getCheckSum(byte[] data) { + int ret = 0; + for (int i = 1; i <= 7; i++) { + ret += data[i]; + } + return (byte)(~(byte)(ret & 0x000000ff) + 1); + } + + private byte[] getCommandWithCheckSum(byte[] baseCommand) { + byte[] checkSum = {getCheckSum(baseCommand)}; + byte[] data = new byte[baseCommand.length + 1]; + System.arraycopy(baseCommand, 0, data, 0, baseCommand.length); + System.arraycopy(checkSum, 0, data, baseCommand.length, 1); + return data; + } + + @Override + public int getPPM() { + write(CMD_GAS_CONCENTRATION); + try { + ByteBuffer buf = ByteBuffer.allocate(2); + byte[] data = new byte[9]; + if (is.read(data, 0, 9) < 9) + return 0; + buf.put(data[2]); + buf.put(data[3]); + return buf.getShort(0); + } + catch (Exception _e) { + LOG.error("Could not read value from MHZ19B", _e); + return 0; + } + } + + public void setCalibrateZeroPoint() { + write(CMD_CALIBRATE_ZERO_POINT); + } + + public void setCalibrateSpanPoint(int point) { + if (point < CALIBRATE_SPAN_POINT_MIN) { + LOG.info("since span needs at least {} ppm, set it to {} ppm.", CALIBRATE_SPAN_POINT_MIN, CALIBRATE_SPAN_POINT_MIN); + point = CALIBRATE_SPAN_POINT_MIN; + } + + byte high = (byte)((point / 256) & 0x000000ff); + byte low = (byte)((point % 256) & 0x000000ff); + byte[] CMD_CALIBRATE_SPAN_POINT = {(byte)0xff, 0x01, (byte)0x88, high, low, 0x00, 0x00, 0x00}; + + write(getCommandWithCheckSum(CMD_CALIBRATE_SPAN_POINT)); + LOG.info("set the calibration span point to {} ppm.", point); + } + + public void setAutoCalibration(boolean set) { + if (set) { + write(getCommandWithCheckSum(CMD_AUTO_CALIBRATION_ON_WITHOUT_CHECKSUM)); + LOG.info("set auto calibration to ON."); + } else { + write(getCommandWithCheckSum(CMD_AUTO_CALIBRATION_OFF_WITHOUT_CHECKSUM)); + LOG.info("set auto calibration to OFF."); + } + } + + private void setDetectionRange(int range) { + byte high = (byte)((range / 256) & 0x000000ff); + byte low = (byte)((range % 256) & 0x000000ff); + byte[] CMD_DETECTION_RANGE = {(byte)0xff, 0x01, (byte)0x99, high, low, 0x00, 0x00, 0x00}; + + write(getCommandWithCheckSum(CMD_DETECTION_RANGE)); + LOG.info("set the detection range to {} ppm.", range); + } + + public void setDetectionRange2000() { + setDetectionRange(2000); + } + + public void setDetectionRange5000() { + setDetectionRange(5000); + } + + public static void main(String[] args) { + MHZ19BCO2Sensor mhz19b = new MHZ19BCO2Sensor("/dev/ttyAMA0"); + mhz19b.setDetectionRange5000(); + mhz19b.setAutoCalibration(false); + AtomicInteger i = new AtomicInteger(0); + while (i.incrementAndGet() < 2000) { + LOG.debug("co2: {}PPM", mhz19b.getPPM()); + ConcurrencyUtils.sleep(5000); + } + Runtime.getRuntime().addShutdownHook(new Thread(mhz19b::shutdown, "Shutdown")); + } +} diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/TestThermo.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/TestThermo.java deleted file mode 100644 index 1ccfe7b..0000000 --- a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/TestThermo.java +++ /dev/null @@ -1,16 +0,0 @@ -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(); - } -} diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/Globals.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/Globals.java index 553f540..d8d46aa 100644 --- a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/Globals.java +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/context/Globals.java @@ -1,22 +1,27 @@ package com.lanternsoftware.thermometer.context; +import com.lanternsoftware.thermometer.DS18B20Thermometer; +import com.lanternsoftware.thermometer.HidThermometer; +import com.lanternsoftware.thermometer.IThermometer; + import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import java.util.ArrayList; +import java.util.List; public class Globals implements ServletContextListener { - public static ThermometerApp app; + public static List thermometers = new ArrayList<>(); @Override public void contextInitialized(ServletContextEvent sce) { - app = new ThermometerApp(); - app.start(); + IThermometer t = new HidThermometer(); + if (t.isConnected()) + thermometers.add(t); + thermometers.addAll(DS18B20Thermometer.devices()); } @Override public void contextDestroyed(ServletContextEvent sce) { - if (app != null) { - app.stop(); - app = null; - } + thermometers.forEach(IThermometer::shutdown); } } diff --git a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/servlet/TempServlet.java b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/servlet/TempServlet.java index 1eccd99..16cac6a 100644 --- a/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/servlet/TempServlet.java +++ b/zwave/lantern-service-thermometer/src/main/java/com/lanternsoftware/thermometer/servlet/TempServlet.java @@ -1,18 +1,23 @@ package com.lanternsoftware.thermometer.servlet; +import com.lanternsoftware.thermometer.IThermometer; import com.lanternsoftware.thermometer.context.Globals; +import com.lanternsoftware.util.CollectionUtils; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.servlet.LanternServlet; -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 { +@WebServlet("/temp/*") +public class TempServlet extends LanternServlet { @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - setResponseEntity(resp, "application/json", "{\"temp\": "+ Globals.app.getTemperature() + "}"); + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + int idx = DaoSerializer.toInteger(CollectionUtils.get(path(req), 0)); + IThermometer therm = CollectionUtils.get(Globals.thermometers, idx); + double temp = therm == null ? -273 : therm.getTemperatureCelsius(); + setResponseEntity(resp, "application/json", "{\"temp\": "+ temp + "}"); } } diff --git a/zwave/lantern-service-thermometer/src/main/resources/logback.xml b/zwave/lantern-service-thermometer/src/main/resources/logback.xml index 939eaaa..e39eed9 100644 --- a/zwave/lantern-service-thermometer/src/main/resources/logback.xml +++ b/zwave/lantern-service-thermometer/src/main/resources/logback.xml @@ -9,9 +9,9 @@ - /opt/currentmonitor/log/log.txt + /opt/tomcat/log/thermo.txt - /opt/currentmonitor/log/log.%d{yyyy-MM-dd}.%i.txt + /opt/currentmonitor/log/thermo.%d{yyyy-MM-dd}.%i.txt 20MB 20 @@ -20,9 +20,10 @@ - + + \ No newline at end of file diff --git a/zwave/lantern-service-thermometer/src/test/java/com/lanternsoftware/thermometer/TestStartup.java b/zwave/lantern-service-thermometer/src/test/java/com/lanternsoftware/thermometer/TestStartup.java index 5dc82b4..a04074f 100644 --- a/zwave/lantern-service-thermometer/src/test/java/com/lanternsoftware/thermometer/TestStartup.java +++ b/zwave/lantern-service-thermometer/src/test/java/com/lanternsoftware/thermometer/TestStartup.java @@ -1,16 +1,14 @@ package com.lanternsoftware.thermometer; -import com.lanternsoftware.thermometer.context.ThermometerApp; +import com.lanternsoftware.util.concurrency.ConcurrencyUtils; public class TestStartup { public static void main(String[] args) { - ThermometerApp app = new ThermometerApp(); - app.start(); - try { - Thread.sleep(20000); - } catch (InterruptedException _e) { - _e.printStackTrace(); + IThermometer thermometer = new DS18B20Thermometer(); + for (int i=0; i<200; i++) { + System.out.println(String.format("%.2f", thermometer.getTemperatureCelsius())); + ConcurrencyUtils.sleep(1000); } - app.stop(); + thermometer.shutdown(); } } diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/TestSecurity.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/TestSecurity.java index 31fc024..80a742e 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/TestSecurity.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/TestSecurity.java @@ -2,6 +2,7 @@ package com.lanternsoftware.zwave; import com.lanternsoftware.datamodel.zwave.Switch; import com.lanternsoftware.datamodel.zwave.SwitchType; +import com.lanternsoftware.util.concurrency.ConcurrencyUtils; import com.lanternsoftware.zwave.security.SecurityController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,6 +15,8 @@ public class TestSecurity { Switch sw = new Switch("Garage", "Door 1", 1000, true, false, null, 0); sw.setGpioPin(7); sw.setType(SwitchType.SECURITY); - c.listen(sw, (nodeId, _open) -> LOG.info("Door is " + (_open ? "OPEN" : "CLOSED"))); + c.listen(sw, (nodeId, _open) -> LOG.error("Door event, now " + (_open ? "OPEN" : "CLOSED"))); + ConcurrencyUtils.sleep(60000); + c.shutdown(); } } diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java index ac5799a..d4aa332 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java @@ -22,6 +22,7 @@ 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.AddNodeToNetworkRequest; import com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest; import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest; import com.lanternsoftware.zwave.message.impl.CRC16EncapRequest; @@ -226,6 +227,8 @@ public class ZWaveApp { } }); + controller.send(new MultilevelSwitchSetRequest((byte)2, 0xFF)); + // controller.send(new MultilevelSensorGetRequest((byte)11)); // controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING)); // controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING)); diff --git a/zwave/lantern-service-zwave/src/main/resources/logback.xml b/zwave/lantern-service-zwave/src/main/resources/logback.xml index 0c83f96..ece41c5 100644 --- a/zwave/lantern-service-zwave/src/main/resources/logback.xml +++ b/zwave/lantern-service-zwave/src/main/resources/logback.xml @@ -9,7 +9,7 @@ - + diff --git a/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/TestStartup.java b/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/TestStartup.java index ef3b633..0a1777d 100644 --- a/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/TestStartup.java +++ b/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/TestStartup.java @@ -7,10 +7,10 @@ public class TestStartup { ZWaveApp app = new ZWaveApp(); app.start(); try { - Thread.sleep(20000); + Thread.sleep(20000000); } catch (InterruptedException _e) { _e.printStackTrace(); } - app.stop(); + Runtime.getRuntime().addShutdownHook(new Thread(app::stop, "Shutdown")); } } diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/controller/Controller.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/controller/Controller.java index a89cc68..de5b428 100644 --- a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/controller/Controller.java +++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/controller/Controller.java @@ -39,13 +39,13 @@ public class Controller { private SerialPort serialPort; private OutputStream os; private boolean running = false; - private AtomicInteger callbackId = new AtomicInteger(0); + private final 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 callbacks = new HashMap<>(); - private ExecutorService executor = Executors.newFixedThreadPool(2); + private final ExecutorService executor = Executors.newFixedThreadPool(2); private NodeManager nodeManager; public boolean start(String _port) { @@ -172,9 +172,10 @@ public class Controller { 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("Waiting for response from: {}", message.describe()); + if (!responseReceived) + responseMutex.wait(1000); logger.debug("Response received: {}", responseReceived); responseReceived = false; } diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/MessageEngine.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/MessageEngine.java index 83f62cd..c24357d 100644 --- a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/MessageEngine.java +++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/MessageEngine.java @@ -33,9 +33,17 @@ public abstract class MessageEngine { } 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); + CommandClass commandClass = CommandClass.NO_OPERATION; + byte command = 0; + int offset = 5; + if (NullUtils.isOneOf(controllerMessageType, ControllerMessageType.SendData, ControllerMessageType.ApplicationCommandHandler)) { + if (messageType == MessageType.REQUEST) + offset = 7; + if (_data.length > offset + 1) + commandClass = CommandClass.fromByte((byte)(_data[offset] & 0xFF)); + if (_data.length > offset + 2) + command = (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); diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/AddNodeToNetworkRequest.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/AddNodeToNetworkRequest.java new file mode 100644 index 0000000..c48399a --- /dev/null +++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/AddNodeToNetworkRequest.java @@ -0,0 +1,17 @@ +package com.lanternsoftware.zwave.message.impl; + +import com.lanternsoftware.zwave.message.ControllerMessageType; +import com.lanternsoftware.zwave.message.NoCommandRequestMessage; + +public class AddNodeToNetworkRequest extends NoCommandRequestMessage { + public AddNodeToNetworkRequest() { + super(ControllerMessageType.AddNodeToNetwork); + } + + @Override + public byte[] getPayload() { + byte[] payload = new byte[1]; + payload[0] = (byte)0x05; + return payload; + } +} diff --git a/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message b/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message index 231b36f..68627d2 100644 --- a/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message +++ b/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message @@ -1,3 +1,4 @@ +com.lanternsoftware.zwave.message.impl.AddNodeToNetworkRequest com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest com.lanternsoftware.zwave.message.impl.AssociationGetRequest com.lanternsoftware.zwave.message.impl.AssociationReportRequest