diff --git a/currentmonitor/lantern-currentmonitor/pom.xml b/currentmonitor/lantern-currentmonitor/pom.xml
index 4127a67..25ece54 100644
--- a/currentmonitor/lantern-currentmonitor/pom.xml
+++ b/currentmonitor/lantern-currentmonitor/pom.xml
@@ -3,7 +3,7 @@
com.lanternsoftware.currentmonitor
lantern-currentmonitor
jar
- 1.0.0
+ 0.9.5
lantern-currentmonitor
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BluetoothConfig.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BluetoothConfig.java
index c95a8dc..9290598 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BluetoothConfig.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BluetoothConfig.java
@@ -9,10 +9,8 @@ import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.util.CollectionUtils;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-public class BluetoothConfig implements Runnable {
- private final AtomicBoolean running = new AtomicBoolean(true);
+public class BluetoothConfig {
private final BleApplication app;
public BluetoothConfig(String _hubName, BleCharacteristicListener _listener) {
@@ -25,15 +23,11 @@ public class BluetoothConfig implements Runnable {
app = new BleApplication("Lantern", _hubName, new BleService("HubConfig", service.getServiceUUID(), chars));
}
- @Override
- public void run() {
+ public void start() {
app.start();
}
public void stop() {
- synchronized (running) {
- running.set(false);
- }
app.stop();
}
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
index 54407e8..ac5d61f 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
@@ -90,59 +90,65 @@ public class MonitorApp {
HubConfigCharacteristic ch = NullUtils.toEnum(HubConfigCharacteristic.class, _name);
LOG.info("Char Received, Name: {} Value: {}", _name, _value);
monitor.submit(()->{
- switch (ch) {
- case HubIndex:
- if ((_value.length > 0)) {
- config.setHub(_value[0]);
- ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
- }
- break;
- case AuthCode:
- String value = NullUtils.toString(_value);
- if (NullUtils.isNotEmpty(value)) {
- authCode = value;
- config.setAuthCode(value);
- ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
- }
- break;
- case WifiCredentials:
- String ssid = HubConfigService.decryptWifiSSID(_value);
- String pwd = HubConfigService.decryptWifiPassword(_value);
- if (NullUtils.isNotEmpty(ssid) && NullUtils.isNotEmpty(pwd))
- WifiConfig.setCredentials(ssid, pwd);
- break;
- case Flash:
- if ((CollectionUtils.length(_value) == 0) || (_value[0] == 0)) {
- if (flasher != null) {
- flasher.stop();
- flasher = null;
+ synchronized (monitor) {
+ switch (ch) {
+ case Host:
+ if ((_value.length > 0)) {
+ config.setHost(NullUtils.terminateWith(NullUtils.toString(_value), "/") + "currentmonitor/");
+ ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
- else
- LEDFlasher.setLEDOn(false);
- }
- else {
- if (flasher == null) {
- flasher = new LEDFlasher();
- monitor.submit(flasher);
+ break;
+ case HubIndex:
+ if ((_value.length > 0)) {
+ config.setHub(_value[0]);
+ ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
- }
- break;
- case Restart:
- LOG.info("Restarting Current Monitor...");
- try {
- Runtime.getRuntime().exec("echo \"sudo systemctl restart currentmonitor\" | at now + 1 minute");
- } catch (IOException _e) {
- LOG.error("Exception occurred while trying to restart", _e);
- }
- break;
- case Reboot:
- LOG.info("Rebooting Pi...");
- try {
- Runtime.getRuntime().exec("sudo reboot now");
- } catch (IOException _e) {
- LOG.error("Exception occurred while trying to reboot", _e);
- }
- break;
+ break;
+ case AuthCode:
+ String value = NullUtils.toString(_value);
+ if (NullUtils.isNotEmpty(value)) {
+ authCode = value;
+ config.setAuthCode(value);
+ ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
+ }
+ break;
+ case WifiCredentials:
+ String ssid = HubConfigService.decryptWifiSSID(_value);
+ String pwd = HubConfigService.decryptWifiPassword(_value);
+ if (NullUtils.isNotEmpty(ssid) && NullUtils.isNotEmpty(pwd))
+ WifiConfig.setCredentials(ssid, pwd);
+ break;
+ case Flash:
+ if ((CollectionUtils.length(_value) == 0) || (_value[0] == 0)) {
+ if (flasher != null) {
+ flasher.stop();
+ flasher = null;
+ } else
+ LEDFlasher.setLEDOn(false);
+ } else {
+ if (flasher == null) {
+ flasher = new LEDFlasher();
+ monitor.submit(flasher);
+ }
+ }
+ break;
+ case Restart:
+ LOG.info("Restarting Current Monitor...");
+ try {
+ Runtime.getRuntime().exec(new String[]{"systemctl","restart","currentmonitor"});
+ } catch (IOException _e) {
+ LOG.error("Exception occurred while trying to restart", _e);
+ }
+ break;
+ case Reboot:
+ LOG.info("Rebooting Pi...");
+ try {
+ Runtime.getRuntime().exec(new String[]{"reboot","now"});
+ } catch (IOException _e) {
+ LOG.error("Exception occurred while trying to reboot", _e);
+ }
+ break;
+ }
}
});
}
@@ -159,7 +165,7 @@ public class MonitorApp {
return null;
}
});
- monitor.submit(bluetoothConfig);
+ bluetoothConfig.start();
if (NullUtils.isNotEmpty(config.getAuthCode()))
authCode = config.getAuthCode();
else {
@@ -190,7 +196,8 @@ public class MonitorApp {
}
List breakers = breakerConfig.getBreakersForHub(config.getHub());
LOG.info("Monitoring {} breakers for hub {}", CollectionUtils.size(breakers), hub.getHub());
- monitor.monitorPower(hub, breakers, 1000, logger);
+ if (CollectionUtils.size(breakers) > 0)
+ monitor.monitorPower(hub, breakers, 1000, logger);
}
monitor.submit(new PowerPoster());
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
@@ -341,7 +348,7 @@ public class MonitorApp {
ResourceLoader.writeFile(WORKING_DIR + "lantern-currentmonitor.jar", jar);
ConcurrencyUtils.sleep(10000);
try {
- Runtime.getRuntime().exec("echo \"sudo systemctl restart currentmonitor\" | at now + 1 minute");
+ Runtime.getRuntime().exec(new String[]{"systemctl","restart","currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
@@ -375,9 +382,9 @@ public class MonitorApp {
else if (NullUtils.isEqual(command, "extend_filesystem")) {
LOG.info("Extending filesystem and rebooting");
try {
- Runtime.getRuntime().exec("sudo raspi-config --expand-rootfs");
+ Runtime.getRuntime().exec(new String[]{"sudo","raspi-config","--expand-rootfs"});
ConcurrencyUtils.sleep(5000);
- Runtime.getRuntime().exec("sudo reboot now");
+ Runtime.getRuntime().exec(new String[]{"reboot","now"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to extend filesystem", _e);
}
@@ -386,7 +393,7 @@ public class MonitorApp {
else if (NullUtils.isEqual(command, "restart")) {
LOG.info("Restarting...");
try {
- Runtime.getRuntime().exec("echo \"sudo systemctl restart currentmonitor\" | at now + 1 minute");
+ Runtime.getRuntime().exec(new String[]{"systemctl","restart","currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/wifi/WifiConfig.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/wifi/WifiConfig.java
index cd3e9ed..d0e1d53 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/wifi/WifiConfig.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/wifi/WifiConfig.java
@@ -1,5 +1,7 @@
package com.lanternsoftware.currentmonitor.wifi;
+import com.lanternsoftware.util.CollectionUtils;
+import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
@@ -11,28 +13,17 @@ public abstract class WifiConfig {
private static final Logger LOG = LoggerFactory.getLogger(WifiConfig.class);
private static final String WIFI_CONFIG_PATH = "/etc/wpa_supplicant/wpa_supplicant.conf";
- private static final String CONF_FORMAT = "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\ncountry=US\nnetwork={\n\tssid=\"%s\"\n\t%s\n}\n";
+ private static final String CONF_FORMAT = "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\ncountry=US\n";
public static void setCredentials(String _ssid, String _password) {
- String[] commands = {"wpa_passphrase", _ssid, _password};
InputStream is = null;
try {
- is = Runtime.getRuntime().exec(commands).getInputStream();
- String newConf = IOUtils.toString(is);
+ is = Runtime.getRuntime().exec(new String[]{"wpa_passphrase", _ssid, _password}).getInputStream();
+ String newConf = CollectionUtils.delimit(CollectionUtils.filter(CollectionUtils.asArrayList(NullUtils.cleanSplit(IOUtils.toString(is), "\\r?\\n")), _s->!_s.trim().startsWith("#")), "\n");
if (newConf == null)
return;
- int idx = newConf.indexOf("psk=");
- if (idx > 0) {
- if (newConf.charAt(idx-1) == '#')
- idx = newConf.indexOf("psk=", idx+1);
- if (idx > 0) {
- int endIdx = newConf.indexOf("\n", idx);
- if (endIdx > 0) {
- String finalConf = String.format(CONF_FORMAT, _ssid, newConf.substring(idx, endIdx));
- ResourceLoader.writeFile(WIFI_CONFIG_PATH, finalConf);
- }
- }
- }
+ ResourceLoader.writeFile(WIFI_CONFIG_PATH, CONF_FORMAT+newConf);
+ Runtime.getRuntime().exec(new String[]{"wpa_cli","-i","wlan0","reconfigure"});
}
catch (Exception _e) {
LOG.error("Failed to write wifi credentials", _e);
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/HubConfigCharacteristic.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/HubConfigCharacteristic.java
index b58eea9..740a8f4 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/HubConfigCharacteristic.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/HubConfigCharacteristic.java
@@ -14,7 +14,8 @@ public enum HubConfigCharacteristic {
Reboot(6, CharacteristicFlag.WRITE),
AccountId(7, CharacteristicFlag.READ),
NetworkState(8, CharacteristicFlag.READ),
- Flash(9, CharacteristicFlag.WRITE);
+ Flash(9, CharacteristicFlag.WRITE),
+ Host(10, CharacteristicFlag.WRITE);
public final int idx;
public final UUID uuid;
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 0129530..ab57e6f 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
@@ -17,6 +17,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.BinarySwitchReportRequest;
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
import com.lanternsoftware.zwave.message.impl.MultilevelSensorGetRequest;
import com.lanternsoftware.zwave.message.impl.MultilevelSensorReportRequest;
@@ -45,7 +46,7 @@ public class ZWaveApp {
private ZWaveConfig config;
private Controller controller;
private final Map switches = new HashMap<>();
- private final Map> peers = new HashMap<>();
+ private final Map> peers = new HashMap<>();
private Timer timer;
private HttpPool pool;
private SwitchScheduleTask nextScheduleTask;
@@ -78,17 +79,17 @@ public class ZWaveApp {
t.printStackTrace();
}
config = dao.getConfig(1);
- Map> groups = new HashMap<>();
+ Map> groups = new HashMap<>();
for (Switch sw : CollectionUtils.makeNotNull(config.getSwitches())) {
switches.put(sw.getNodeId(), sw);
- CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw.getNodeId(), groups);
+ CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw, groups);
}
if (CollectionUtils.filterOne(config.getSwitches(), Switch::isUrlThermostat) != null) {
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
}
- for (List group : groups.values()) {
- for (Integer node : group) {
- peers.put(node, CollectionUtils.filter(group, _i -> !_i.equals(node)));
+ for (List group : groups.values()) {
+ for (Switch sw : group) {
+ peers.put(sw.getNodeId(), CollectionUtils.filter(group, _sw -> _sw.getNodeId() != sw.getNodeId()));
}
}
scheduleNextTransition();
@@ -136,19 +137,19 @@ public class ZWaveApp {
@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();
- }
- }
+ onSwitchLevelChange(_message.getNodeId(), _message.getLevel());
+ }
+ });
+
+ MessageEngine.subscribe(new IMessageSubscriber() {
+ @Override
+ public Class getHandledMessageClass() {
+ return BinarySwitchReportRequest.class;
+ }
+
+ @Override
+ public void onMessage(BinarySwitchReportRequest _message) {
+ onSwitchLevelChange(_message.getNodeId(), _message.getLevel());
}
});
@@ -164,6 +165,28 @@ public class ZWaveApp {
// controller.send(new ThermostatModeGetRequest((byte)11));
}
+ private void onSwitchLevelChange(int _primaryNodeId, int _primaryLevel) {
+ synchronized (switches) {
+ Switch sw = switches.get(_primaryNodeId);
+ if (sw != null) {
+ int newLevel = sw.isMultilevel()?_primaryLevel:((_primaryLevel == 0)?0:99);
+ sw.setLevel(newLevel);
+ for (Switch peer : CollectionUtils.makeNotNull(peers.get(_primaryNodeId))) {
+ logger.info("Mirror Event from node {} to node {}", _primaryNodeId, peer.getNodeId());
+ if (peer.isMultilevel()) {
+ peer.setLevel(newLevel);
+ controller.send(new MultilevelSwitchSetRequest((byte)peer.getNodeId(), newLevel));
+ }
+ else {
+ peer.setLevel(newLevel > 0?0xff:0);
+ controller.send(new BinarySwitchSetRequest((byte)peer.getNodeId(), newLevel > 0));
+ }
+ }
+ persistConfig();
+ }
+ }
+ }
+
private void scheduleNextTransition() {
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
if (nextScheduleTask != null)
@@ -185,7 +208,7 @@ public class ZWaveApp {
return;
sw.setLevel(_level);
if (!sw.isThermostat()) {
- setGroupSwitchLevel(_nodeId, _level, sw.isMultilevel());
+ setGroupSwitchLevel(sw, _level);
} else if (sw.isZWaveThermostat()) {
controller.send(new ThermostatSetPointSetRequest((byte) sw.getNodeId(), sw.getThermostatMode() == ThermostatMode.COOL ? ThermostatSetPointIndex.COOLING : ThermostatSetPointIndex.HEATING, _level));
} else {
@@ -252,11 +275,13 @@ public class ZWaveApp {
}
}
- private void setGroupSwitchLevel(int _primary, int _level, boolean _multilevel) {
- List 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 void setGroupSwitchLevel(Switch _primary, int _level) {
+ if (_primary == null)
+ return;
+ List nodes = CollectionUtils.asArrayList(_primary);
+ nodes.addAll(CollectionUtils.makeNotNull(peers.get(_primary.getNodeId())));
+ for (Switch node : nodes) {
+ controller.send(node.isMultilevel() ? new MultilevelSwitchSetRequest((byte) node.getNodeId(), _level) : new BinarySwitchSetRequest((byte) node.getNodeId(), _level > 0));
}
}
@@ -268,10 +293,10 @@ public class ZWaveApp {
if (sw.isUrlThermostat() && !sw.isThermometer()) {
double tempF = getTemperatureCelsius(sw) * 1.8 + 32;
if (tempF > sw.getLevel() + 0.4) {
- setGroupSwitchLevel(sw.getNodeId(), 0, false);
+ setGroupSwitchLevel(sw, 0);
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);
+ setGroupSwitchLevel(sw, (byte) 0xf);
logger.info("Turning {} {} on, temp is: {} set to: {}", sw.getRoom(), sw.getName(), tempF + " set to: ", sw.getLevel());
}
}
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 ad85e90..ee78e31 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
@@ -53,8 +53,8 @@ public class Controller {
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);
+ serialPort.disableReceiveThreshold();
+ serialPort.enableReceiveTimeout(500);
os = serialPort.getOutputStream();
running = true;
executor.submit(new MessageReceiver());
diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java
new file mode 100644
index 0000000..9b6feef
--- /dev/null
+++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java
@@ -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 BinarySwitchReportRequest extends RequestMessage {
+ private int level;
+
+ public BinarySwitchReportRequest() {
+ super(ControllerMessageType.ApplicationCommandHandler, CommandClass.SWITCH_BINARY, (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;
+ }
+}
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 4480d56..9a6e892 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,5 +1,6 @@
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest
+com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest
com.lanternsoftware.zwave.message.impl.ByteMessage
com.lanternsoftware.zwave.message.impl.ControllerCapabilitiesRequest
com.lanternsoftware.zwave.message.impl.ControllerCapabilitiesResponse