diff --git a/currentmonitor/lantern-currentmonitor/pom.xml b/currentmonitor/lantern-currentmonitor/pom.xml
index 360449b..06b2cb3 100644
--- a/currentmonitor/lantern-currentmonitor/pom.xml
+++ b/currentmonitor/lantern-currentmonitor/pom.xml
@@ -2,7 +2,7 @@
4.0.0
lantern-currentmonitor
jar
- 1.1.1
+ 1.1.2
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 9290598..e0fa9ec 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
@@ -7,27 +7,38 @@ import com.lanternsoftware.currentmonitor.bluetooth.BleHelper;
import com.lanternsoftware.currentmonitor.bluetooth.BleService;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.List;
public class BluetoothConfig {
+ private static final Logger LOG = LoggerFactory.getLogger(BluetoothConfig.class);
private final BleApplication app;
public BluetoothConfig(String _hubName, BleCharacteristicListener _listener) {
- BleHelper.getAdapter().setPowered(true);
- BleHelper.requestBusName("com.lanternsoftware");
- BleHelper.setBasePath("/com/lanternsoftware");
- HubConfigService service = new HubConfigService();
- List chars = CollectionUtils.transform(service.getCharacteristics(), _c->new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
- chars.forEach(_c->_c.setListener(_listener));
- app = new BleApplication("Lantern", _hubName, new BleService("HubConfig", service.getServiceUUID(), chars));
+ BleApplication a = null;
+ try {
+ BleHelper.getAdapter().setPowered(true);
+ BleHelper.requestBusName("com.lanternsoftware");
+ BleHelper.setBasePath("/com/lanternsoftware");
+ List chars = CollectionUtils.transform(HubConfigService.getCharacteristics(), _c -> new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
+ chars.forEach(_c -> _c.setListener(_listener));
+ a = new BleApplication("Lantern", _hubName, new BleService("HubConfig", HubConfigService.getServiceUUID(), chars));
+ }
+ catch (Throwable _t) {
+ LOG.error("Failed to initialize BLE service", _t);
+ }
+ app = a;
}
public void start() {
- app.start();
+ if (app != null)
+ app.start();
}
public void stop() {
- app.stop();
+ if (app != null)
+ 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 5d73f14..2150866 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
@@ -219,7 +219,7 @@ public class MonitorApp {
config = new MonitorConfig();
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
- pool = new HttpPool(10, 10, config.getSocketTimeout(), config.getConnectTimeout(), config.getSocketTimeout());
+ pool = HttpPool.builder().withValidateSSLCertificates(!config.isAcceptSelfSignedCertificates()).build();
if (NullUtils.isNotEmpty(config.getHost()))
host = NullUtils.terminateWith(config.getHost(), "/");
monitor.setDebug(config.isDebug());
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
index dd971fd..6ef3911 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
@@ -19,6 +19,7 @@ public class MonitorConfig {
private int socketTimeout;
private boolean postSamples = false;
private boolean needsCalibration = true;
+ private boolean acceptSelfSignedCertificates = false;
private String mqttBrokerUrl;
private String mqttUserName;
private String mqttPassword;
@@ -115,6 +116,14 @@ public class MonitorConfig {
needsCalibration = _needsCalibration;
}
+ public boolean isAcceptSelfSignedCertificates() {
+ return acceptSelfSignedCertificates;
+ }
+
+ public void setAcceptSelfSignedCertificates(boolean _acceptSelfSignedCertificates) {
+ acceptSelfSignedCertificates = _acceptSelfSignedCertificates;
+ }
+
public String getMqttBrokerUrl() {
return mqttBrokerUrl;
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
index a4e3e2b..374b2ac 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
@@ -36,6 +36,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer getCharacteristics() {
+ public static List getCharacteristics() {
return Arrays.asList(HubConfigCharacteristic.values());
}
diff --git a/pigpio/lantern-pigpio/src/main/resources/lib/armhf/lantern-pigpio.so b/pigpio/lantern-pigpio/src/main/resources/lib/armhf/lantern-pigpio.so
new file mode 100644
index 0000000..9561f72
Binary files /dev/null and b/pigpio/lantern-pigpio/src/main/resources/lib/armhf/lantern-pigpio.so differ
diff --git a/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpPool.java b/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpPool.java
index 049f1c7..ab71d3f 100644
--- a/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpPool.java
+++ b/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpPool.java
@@ -1,27 +1,36 @@
package com.lanternsoftware.util.http;
-import java.io.IOException;
-import java.io.InputStream;
-
+import com.lanternsoftware.util.NullUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.lanternsoftware.util.NullUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
public class HttpPool {
private static final Logger LOG = LoggerFactory.getLogger(HttpPool.class);
@@ -32,17 +41,43 @@ public class HttpPool {
private final PoolingHttpClientConnectionManager connectionManager;
public HttpPool(int _maxTotalConnections, int _maxPerRoute) {
- this(_maxTotalConnections, _maxPerRoute, 10000, 5000, 10000);
+ this(_maxTotalConnections, _maxPerRoute, null, null);
+ }
+
+ public HttpPool(int _maxTotalConnections, int _maxPerRoute, KeyStore _keystore, String _keystorePassword) {
+ this(_maxTotalConnections, _maxPerRoute, 10000, 5000, 10000, _keystore, _keystorePassword, true);
}
public HttpPool(int _maxTotalConnections, int _maxPerRoute, int _socketTimeoutMs, int _connectTimeoutMs, int _connectionRequestTimeoutMs) {
+ this(_maxTotalConnections, _maxPerRoute, _socketTimeoutMs, _connectTimeoutMs, _connectionRequestTimeoutMs, null, null, true);
+ }
+
+ public HttpPool(int _maxTotalConnections, int _maxPerRoute, int _socketTimeoutMs, int _connectTimeoutMs, int _connectionRequestTimeoutMs, KeyStore _keystore, String _keystorePassword, boolean _validateSSLCertificates) {
requestConfig = RequestConfig.custom().setSocketTimeout(_socketTimeoutMs).setConnectTimeout(_connectTimeoutMs).setConnectionRequestTimeout(_connectionRequestTimeoutMs).setCookieSpec(CookieSpecs.STANDARD).build();
keepAliveStrategy = (HttpResponse response, HttpContext context) -> 0;
- connectionManager = new PoolingHttpClientConnectionManager();
+ Registry registry = null;
+ if ((_keystore != null) || !_validateSSLCertificates) {
+ try {
+ SSLContextBuilder contextBuilder = SSLContexts.custom();
+ if (_keystore != null)
+ contextBuilder.loadKeyMaterial(_keystore, _keystorePassword.toCharArray());
+ if (!_validateSSLCertificates)
+ contextBuilder.loadTrustMaterial(null, (x509CertChain, authType) -> true);
+ SSLConnectionSocketFactory socketFactory = _validateSSLCertificates ? new SSLConnectionSocketFactory(contextBuilder.build()) : new SSLConnectionSocketFactory(contextBuilder.build(), NoopHostnameVerifier.INSTANCE);
+ registry = RegistryBuilder.create().register("https", socketFactory).register("http", new PlainConnectionSocketFactory()).build();
+ } catch (Exception _e) {
+ LOG.error("Failed to load SSL keystore", _e);
+ }
+ }
+ connectionManager = registry != null ? new PoolingHttpClientConnectionManager(registry) : new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(_maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(_maxPerRoute);
}
+ public static Builder builder() {
+ return new Builder();
+ }
+
public void shutdown() {
connectionManager.shutdown();
}
@@ -76,26 +111,28 @@ public class HttpPool {
}
public byte[] executeToByteArray(HttpUriRequest _request) {
+ return executeToPayload(_request).getPayload();
+ }
+
+ public HttpResponsePayload executeToPayload(HttpUriRequest _request) {
InputStream is = null;
CloseableHttpResponse resp = null;
try {
resp = execute(_request);
if (resp == null)
- return null;
- if ((resp.getStatusLine().getStatusCode() < 200) || (resp.getStatusLine().getStatusCode() >= 300)) {
+ return new HttpResponsePayload(HttpStatus.SC_INTERNAL_SERVER_ERROR, null);
+ if ((resp.getStatusLine().getStatusCode() < 200) || (resp.getStatusLine().getStatusCode() >= 300))
LOG.error("Failed to make http request to " + _request.getURI().toString() + ". Status code: " + resp.getStatusLine().getStatusCode());
- return null;
- }
HttpEntity entity = resp.getEntity();
if (entity != null) {
is = entity.getContent();
- return IOUtils.toByteArray(is);
+ return new HttpResponsePayload(resp.getStatusLine().getStatusCode(), IOUtils.toByteArray(is));
}
- return null;
+ return new HttpResponsePayload(resp.getStatusLine().getStatusCode(), null);
}
catch (Exception _e) {
LOG.error("Failed to make http request to " + _request.getURI().toString(), _e);
- return null;
+ return new HttpResponsePayload(HttpStatus.SC_INTERNAL_SERVER_ERROR, null);
}
finally {
IOUtils.closeQuietly(is);
@@ -106,4 +143,57 @@ public class HttpPool {
public static void addBasicAuthHeader(HttpUriRequest _request, String _username, String _password) {
_request.addHeader("Authorization", "Basic " + Base64.encodeBase64String(NullUtils.toByteArray(_username + ":" + _password)));
}
+
+ public static final class Builder {
+ private int maxTotalConnections = 10;
+ private int maxPerRoute = 10;
+ private int socketTimeoutMs = 10000;
+ private int connectTimeoutMs = 5000;
+ private int connectionRequestTimeoutMs = 10000;
+ private KeyStore keystore;
+ private String keystorePassword;
+ private boolean validateSSLCertificates = true;
+
+ private Builder() {
+ }
+
+ public Builder withMaxTotalConnections(int val) {
+ maxTotalConnections = val;
+ return this;
+ }
+
+ public Builder withMaxPerRoute(int val) {
+ maxPerRoute = val;
+ return this;
+ }
+
+ public Builder withSocketTimeoutMs(int val) {
+ socketTimeoutMs = val;
+ return this;
+ }
+
+ public Builder withConnectTimeoutMs(int val) {
+ connectTimeoutMs = val;
+ return this;
+ }
+
+ public Builder withConnectionRequestTimeoutMs(int val) {
+ connectionRequestTimeoutMs = val;
+ return this;
+ }
+
+ public Builder withKeystore(KeyStore _keystore, String _password) {
+ keystore = _keystore;
+ keystorePassword = _password;
+ return this;
+ }
+
+ public Builder withValidateSSLCertificates(boolean val) {
+ validateSSLCertificates = val;
+ return this;
+ }
+ public HttpPool build() {
+ return new HttpPool(maxTotalConnections, maxPerRoute, socketTimeoutMs, connectTimeoutMs, connectionRequestTimeoutMs, keystore, keystorePassword, validateSSLCertificates);
+ }
+ }
}
diff --git a/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpResponsePayload.java b/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpResponsePayload.java
new file mode 100644
index 0000000..062ab9d
--- /dev/null
+++ b/util/lantern-util-http/src/main/java/com/lanternsoftware/util/http/HttpResponsePayload.java
@@ -0,0 +1,29 @@
+package com.lanternsoftware.util.http;
+
+import com.lanternsoftware.util.NullUtils;
+
+public class HttpResponsePayload {
+ private final int status;
+ private final byte[] payload;
+
+ public HttpResponsePayload(int _status, byte[] _payload) {
+ status = _status;
+ payload = _payload;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public byte[] getPayload() {
+ return payload;
+ }
+
+ public boolean isSuccess() {
+ return (status >= 200) && (status < 300);
+ }
+
+ public String asString() {
+ return NullUtils.toString(payload);
+ }
+}
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 7a28df3..a9255c7 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
@@ -76,7 +76,6 @@ public class ZWaveApp {
private HttpPool pool;
private SwitchScheduleTask nextScheduleTask;
private final Map sensors = new HashMap<>();
- private final Object ZWAVE_MUTEX = new Object();
private ExecutorService executor = null;
public void start() {
@@ -559,17 +558,15 @@ public class ZWaveApp {
if (_sw.isSourceUrlValid())
return DaoSerializer.getDouble(DaoSerializer.parse(pool.executeToString(new HttpGet(_sw.getSourceUrl()))), "temp");
else if (_sw.isZWaveThermostat() && config.isMySwitch(_sw)) {
- synchronized (ZWAVE_MUTEX) {
- synchronized (sensors) {
- controller.send(new MultilevelSensorGetRequest((byte) _sw.getNodeId()));
- try {
- sensors.wait(3000);
- } catch (InterruptedException _e) {
- _e.printStackTrace();
- }
- Double temp = sensors.get(_sw.getNodeId());
- return (temp == null) ? 0.0 : temp;
+ synchronized (sensors) {
+ controller.send(new MultilevelSensorGetRequest((byte) _sw.getNodeId()));
+ try {
+ sensors.wait(3000);
+ } catch (InterruptedException _e) {
+ _e.printStackTrace();
}
+ Double temp = sensors.get(_sw.getNodeId());
+ return (temp == null) ? 0.0 : temp;
}
}
return 0.0;