mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Add rudimentary support for DS18B120 Thermometers, MH-Z19B CO2 Sensors, and ZWave.me controllers.
This commit is contained in:
parent
883cf7865d
commit
88933a2286
|
@ -15,7 +15,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanternsoftware.util</groupId>
|
<groupId>com.lanternsoftware.util</groupId>
|
||||||
<artifactId>lantern-util-common</artifactId>
|
<artifactId>lantern-util-servlet</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -29,10 +29,25 @@
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.2.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.neuronrobotics</groupId>
|
||||||
|
<artifactId>nrjavaserial</artifactId>
|
||||||
|
<version>5.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fazecast</groupId>
|
||||||
|
<artifactId>jSerialComm</artifactId>
|
||||||
|
<version>2.5.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hid4java</groupId>
|
<groupId>org.hid4java</groupId>
|
||||||
<artifactId>hid4java</artifactId>
|
<artifactId>hid4java</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pi4j</groupId>
|
||||||
|
<artifactId>pi4j-device</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -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<DS18B20Thermometer> 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() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.lanternsoftware.thermometer.context;
|
package com.lanternsoftware.thermometer;
|
||||||
|
|
||||||
import com.lanternsoftware.util.NullUtils;
|
import com.lanternsoftware.util.NullUtils;
|
||||||
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||||
|
@ -11,14 +11,15 @@ import org.slf4j.LoggerFactory;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
public class ThermometerApp {
|
public class HidThermometer implements IThermometer{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ThermometerApp.class);
|
private static final Logger LOG = LoggerFactory.getLogger(HidThermometer.class);
|
||||||
|
|
||||||
private HidDevice device;
|
private HidDevice device;
|
||||||
private final Timer timer = new Timer();
|
private final Timer timer = new Timer();
|
||||||
private double lastTemp;
|
private double lastTemp;
|
||||||
|
private final byte[] READ = hexToByte("0180330100000000");
|
||||||
|
|
||||||
public void start() {
|
public HidThermometer() {
|
||||||
HidServices hs = HidManager.getHidServices();
|
HidServices hs = HidManager.getHidServices();
|
||||||
for (HidDevice d : hs.getAttachedHidDevices()) {
|
for (HidDevice d : hs.getAttachedHidDevices()) {
|
||||||
if (NullUtils.isEqual(d.getVendorId(), (short) 0x413d) && NullUtils.isEqual(d.getProductId(), (short) 0x2107)) {
|
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()) {
|
if ((device != null) && device.open()) {
|
||||||
synchronized (device) {
|
final byte[] INIT1 = hexToByte("0182770100000000");
|
||||||
read(hexToByte("0182770100000000"));
|
final byte[] INIT2 = hexToByte("0186ff0100000000");
|
||||||
read(hexToByte("0186ff0100000000"));
|
synchronized (this) {
|
||||||
read(hexToByte("0182770100000000"));
|
read(INIT1);
|
||||||
read(hexToByte("0182770100000000"));
|
read(INIT2);
|
||||||
|
read(INIT1);
|
||||||
|
read(INIT1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.error("Failed to open HID Device");
|
LOG.error("Failed to open HID Device");
|
||||||
|
@ -45,7 +48,11 @@ public class ThermometerApp {
|
||||||
}, 0L, 10000L);
|
}, 0L, 10000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public boolean isConnected() {
|
||||||
|
return device != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
ConcurrencyUtils.sleep(10000);
|
ConcurrencyUtils.sleep(10000);
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
|
@ -100,14 +107,14 @@ public class ThermometerApp {
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
public double getTemperature() {
|
public double getTemperatureCelsius() {
|
||||||
return lastTemp;
|
return lastTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double readTemperature() {
|
private double readTemperature() {
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
synchronized (device) {
|
synchronized (this) {
|
||||||
byte[] response = read(hexToByte("0180330100000000"));
|
byte[] response = read(READ);
|
||||||
if (response == null)
|
if (response == null)
|
||||||
return 5.0;
|
return 5.0;
|
||||||
int rawReading = ((response[3] & 0xFF) + (response[2] << 8));
|
int rawReading = ((response[3] & 0xFF) + (response[2] << 8));
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.lanternsoftware.thermometer;
|
||||||
|
|
||||||
|
public interface ICO2Sensor {
|
||||||
|
int getPPM();
|
||||||
|
void shutdown();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.lanternsoftware.thermometer;
|
||||||
|
|
||||||
|
public interface IThermometer {
|
||||||
|
double getTemperatureCelsius();
|
||||||
|
boolean isConnected();
|
||||||
|
void shutdown();
|
||||||
|
}
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,27 @@
|
||||||
package com.lanternsoftware.thermometer.context;
|
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.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Globals implements ServletContextListener {
|
public class Globals implements ServletContextListener {
|
||||||
public static ThermometerApp app;
|
public static List<IThermometer> thermometers = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
app = new ThermometerApp();
|
IThermometer t = new HidThermometer();
|
||||||
app.start();
|
if (t.isConnected())
|
||||||
|
thermometers.add(t);
|
||||||
|
thermometers.addAll(DS18B20Thermometer.devices());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextDestroyed(ServletContextEvent sce) {
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
if (app != null) {
|
thermometers.forEach(IThermometer::shutdown);
|
||||||
app.stop();
|
|
||||||
app = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
package com.lanternsoftware.thermometer.servlet;
|
package com.lanternsoftware.thermometer.servlet;
|
||||||
|
|
||||||
|
import com.lanternsoftware.thermometer.IThermometer;
|
||||||
import com.lanternsoftware.thermometer.context.Globals;
|
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.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
|
|
||||||
@WebServlet("/temp")
|
@WebServlet("/temp/*")
|
||||||
public class TempServlet extends ThermoServlet {
|
public class TempServlet extends LanternServlet {
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||||
setResponseEntity(resp, "application/json", "{\"temp\": "+ Globals.app.getTemperature() + "}");
|
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 + "}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>/opt/currentmonitor/log/log.txt</file>
|
<file>/opt/tomcat/log/thermo.txt</file>
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
<fileNamePattern>/opt/currentmonitor/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
<fileNamePattern>/opt/currentmonitor/log/thermo.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
||||||
<maxFileSize>20MB</maxFileSize>
|
<maxFileSize>20MB</maxFileSize>
|
||||||
<maxHistory>20</maxHistory>
|
<maxHistory>20</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
|
@ -20,9 +20,10 @@
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<logger name="com.lanternsoftware" level="INFO"/>
|
<logger name="com.lanternsoftware" level="DEBUG"/>
|
||||||
|
|
||||||
<root level="OFF">
|
<root level="OFF">
|
||||||
<appender-ref ref="FILE"/>
|
<appender-ref ref="FILE"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
</root>
|
</root>
|
||||||
</configuration>
|
</configuration>
|
|
@ -1,16 +1,14 @@
|
||||||
package com.lanternsoftware.thermometer;
|
package com.lanternsoftware.thermometer;
|
||||||
|
|
||||||
import com.lanternsoftware.thermometer.context.ThermometerApp;
|
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||||
|
|
||||||
public class TestStartup {
|
public class TestStartup {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ThermometerApp app = new ThermometerApp();
|
IThermometer thermometer = new DS18B20Thermometer();
|
||||||
app.start();
|
for (int i=0; i<200; i++) {
|
||||||
try {
|
System.out.println(String.format("%.2f", thermometer.getTemperatureCelsius()));
|
||||||
Thread.sleep(20000);
|
ConcurrencyUtils.sleep(1000);
|
||||||
} catch (InterruptedException _e) {
|
|
||||||
_e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
app.stop();
|
thermometer.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.lanternsoftware.zwave;
|
||||||
|
|
||||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
import com.lanternsoftware.datamodel.zwave.SwitchType;
|
import com.lanternsoftware.datamodel.zwave.SwitchType;
|
||||||
|
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||||
import com.lanternsoftware.zwave.security.SecurityController;
|
import com.lanternsoftware.zwave.security.SecurityController;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -14,6 +15,8 @@ public class TestSecurity {
|
||||||
Switch sw = new Switch("Garage", "Door 1", 1000, true, false, null, 0);
|
Switch sw = new Switch("Garage", "Door 1", 1000, true, false, null, 0);
|
||||||
sw.setGpioPin(7);
|
sw.setGpioPin(7);
|
||||||
sw.setType(SwitchType.SECURITY);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.lanternsoftware.zwave.controller.Controller;
|
||||||
import com.lanternsoftware.zwave.dao.MongoZWaveDao;
|
import com.lanternsoftware.zwave.dao.MongoZWaveDao;
|
||||||
import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
||||||
import com.lanternsoftware.zwave.message.MessageEngine;
|
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.BinarySwitchReportRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
|
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.CRC16EncapRequest;
|
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 MultilevelSensorGetRequest((byte)11));
|
||||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING));
|
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING));
|
||||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING));
|
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING));
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
<logger name="com.lanternsoftware" level="INFO"/>
|
<logger name="com.lanternsoftware" level="DEBUG"/>
|
||||||
|
|
||||||
<root level="OFF">
|
<root level="OFF">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
|
|
@ -7,10 +7,10 @@ public class TestStartup {
|
||||||
ZWaveApp app = new ZWaveApp();
|
ZWaveApp app = new ZWaveApp();
|
||||||
app.start();
|
app.start();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(20000);
|
Thread.sleep(20000000);
|
||||||
} catch (InterruptedException _e) {
|
} catch (InterruptedException _e) {
|
||||||
_e.printStackTrace();
|
_e.printStackTrace();
|
||||||
}
|
}
|
||||||
app.stop();
|
Runtime.getRuntime().addShutdownHook(new Thread(app::stop, "Shutdown"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,13 +39,13 @@ public class Controller {
|
||||||
private SerialPort serialPort;
|
private SerialPort serialPort;
|
||||||
private OutputStream os;
|
private OutputStream os;
|
||||||
private boolean running = false;
|
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 ackMutex = new Object();
|
||||||
private final Object responseMutex = new Object();
|
private final Object responseMutex = new Object();
|
||||||
private final Object callbackMutex = new Object();
|
private final Object callbackMutex = new Object();
|
||||||
private boolean responseReceived;
|
private boolean responseReceived;
|
||||||
private final Map<Byte, Byte> callbacks = new HashMap<>();
|
private final Map<Byte, Byte> callbacks = new HashMap<>();
|
||||||
private ExecutorService executor = Executors.newFixedThreadPool(2);
|
private final ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||||
private NodeManager nodeManager;
|
private NodeManager nodeManager;
|
||||||
|
|
||||||
public boolean start(String _port) {
|
public boolean start(String _port) {
|
||||||
|
@ -172,8 +172,9 @@ public class Controller {
|
||||||
logger.debug("Finished outbound of: {}", message.describe());
|
logger.debug("Finished outbound of: {}", message.describe());
|
||||||
}
|
}
|
||||||
if (message instanceof RequestMessage) {
|
if (message instanceof RequestMessage) {
|
||||||
logger.debug("Waiting for response from: {}", message.describe());
|
|
||||||
synchronized (responseMutex) {
|
synchronized (responseMutex) {
|
||||||
|
logger.debug("Waiting for response from: {}", message.describe());
|
||||||
|
if (!responseReceived)
|
||||||
responseMutex.wait(1000);
|
responseMutex.wait(1000);
|
||||||
logger.debug("Response received: {}", responseReceived);
|
logger.debug("Response received: {}", responseReceived);
|
||||||
responseReceived = false;
|
responseReceived = false;
|
||||||
|
|
|
@ -33,9 +33,17 @@ public abstract class MessageEngine {
|
||||||
}
|
}
|
||||||
MessageType messageType = _data[2] == 0x00 ? MessageType.REQUEST : MessageType.RESPONSE;
|
MessageType messageType = _data[2] == 0x00 ? MessageType.REQUEST : MessageType.RESPONSE;
|
||||||
ControllerMessageType controllerMessageType = ControllerMessageType.fromByte((byte)(_data[3] & 0xFF));
|
ControllerMessageType controllerMessageType = ControllerMessageType.fromByte((byte)(_data[3] & 0xFF));
|
||||||
int offset = ((messageType == MessageType.REQUEST) && NullUtils.isOneOf(controllerMessageType, ControllerMessageType.SendData, ControllerMessageType.ApplicationCommandHandler))?7:5;
|
CommandClass commandClass = CommandClass.NO_OPERATION;
|
||||||
CommandClass commandClass = _data.length > offset + 1 ? CommandClass.fromByte((byte)(_data[offset] & 0xFF)):CommandClass.NO_OPERATION;
|
byte command = 0;
|
||||||
byte command = ((commandClass == CommandClass.NO_OPERATION) || (_data.length <= offset+2))?0:(byte)(_data[offset+1] & 0xFF);
|
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));
|
Message message = messages.get(Message.toKey(controllerMessageType.data, messageType.data, commandClass.data, command));
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
logger.debug("Could not find message class for message: {} {} {} {}", controllerMessageType.label, messageType.name(), commandClass.label, command);
|
logger.debug("Could not find message class for message: {} {} {} {}", controllerMessageType.label, messageType.name(), commandClass.label, command);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
com.lanternsoftware.zwave.message.impl.AddNodeToNetworkRequest
|
||||||
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
|
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
|
||||||
com.lanternsoftware.zwave.message.impl.AssociationGetRequest
|
com.lanternsoftware.zwave.message.impl.AssociationGetRequest
|
||||||
com.lanternsoftware.zwave.message.impl.AssociationReportRequest
|
com.lanternsoftware.zwave.message.impl.AssociationReportRequest
|
||||||
|
|
Loading…
Reference in New Issue
Block a user