@@ -35,7 +36,7 @@
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Domoticz Devices' list below will show what
is already setup for your Domoticz.
-
+
Also, use this select menu for which type of dim control you would
like to be generated:
-
Use the check boxes by the names to use the bulk addition
+
Use the check boxes by the names to use the bulk addition
feature. Select your items and dim control type if wanted, then click
bulk add below. Your items will be added with on and off or dim and
off if selected with the name of the device from the Domoticz.
@@ -43,7 +44,7 @@
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
also work. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command.
-
When copying, update the name and select the "Add Bridge
+
When copying, update the name and select the "Add Bridge
Device" Button.
From 745986f08f538649c26934ee633638c7e996d0f6 Mon Sep 17 00:00:00 2001
From: Admin
Date: Fri, 24 Feb 2017 15:45:45 -0600
Subject: [PATCH 16/24] Finished Domoticz updates
---
pom.xml | 2 +-
.../plugins/domoticz/DomoticzHandler.java | 62 +++++++++++++++----
.../plugins/domoticz/DomoticzHome.java | 56 ++++++++++++++---
.../HABridge/plugins/http/HTTPHandler.java | 42 ++++++-------
4 files changed, 121 insertions(+), 41 deletions(-)
diff --git a/pom.xml b/pom.xml
index ca0a205..b10f483 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.1.4c
+ 4.2.0jarHA Bridge
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
index 379c7b7..56ada5a 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
@@ -3,11 +3,12 @@ package com.bwssystems.HABridge.plugins.domoticz;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-
+import java.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.NamedIP;
+import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.google.gson.Gson;
@@ -16,32 +17,33 @@ public class DomoticzHandler {
private static final String GET_REQUEST = "/json.htm?type=";
private static final String DEVICES_TYPE = "devices";
private static final String SCENES_TYPE = "scenes";
- private static final String FILTER_USED = "&used=";
- private HTTPHandler httpClient;
+ private static final String FILTER_USED = "&used=true";
private NamedIP domoticzAddress;
public DomoticzHandler(NamedIP addressName) {
super();
- httpClient = new HTTPHandler();
domoticzAddress = addressName;
}
- public List getDevices() {
- return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED);
+ public List getDevices(HTTPHandler httpClient) {
+ return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED, httpClient);
}
- public List getScenes() {
- return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null);
+ public List getScenes(HTTPHandler httpClient) {
+ return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null, httpClient);
}
- private List getDomoticzDevices(String rootRequest, String type, String postpend) {
+ private List getDomoticzDevices(String rootRequest, String type, String postpend, HTTPHandler httpClient) {
Devices theDomoticzApiResponse = null;
List deviceList = null;
String theUrl = null;
String theData;
- theUrl = "http://" + domoticzAddress.getIp() + ":" + domoticzAddress.getPort() + rootRequest + type;
- theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
+ if(postpend != null && !postpend.isEmpty())
+ theUrl = buildUrl(rootRequest + type + postpend);
+ else
+ theUrl = buildUrl(rootRequest + type);
+ theData = httpClient.doHttpRequest(theUrl, null, null, null, buildHeaders());
if(theData != null) {
log.debug("GET " + type + " DomoticzApiResponse - data: " + theData);
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
@@ -70,6 +72,44 @@ public class DomoticzHandler {
return deviceList;
}
+ public String buildUrl(String thePayload) {
+ String newUrl = null;
+
+ if(thePayload != null && !thePayload.isEmpty()) {
+ if(domoticzAddress.getSecure() != null && domoticzAddress.getSecure())
+ newUrl = "https://";
+ else
+ newUrl = "http://";
+
+ newUrl = newUrl + domoticzAddress.getIp();
+
+ if(domoticzAddress.getPort() != null && !domoticzAddress.getPort().isEmpty())
+ newUrl = newUrl + ":" + domoticzAddress.getPort();
+
+ if(thePayload.startsWith("/"))
+ newUrl = newUrl + thePayload;
+ else
+ newUrl = newUrl + "/" + thePayload;
+ }
+
+ return newUrl;
+ }
+
+ public NameValue[] buildHeaders() {
+ NameValue[] headers = null;
+
+ if(domoticzAddress.getUsername() != null && !domoticzAddress.getUsername().isEmpty()
+ && domoticzAddress.getPassword() != null && !domoticzAddress.getPassword().isEmpty()) {
+ NameValue theAuth = new NameValue();
+ theAuth.setName("Authorization");
+ String encoding = Base64.getEncoder().encodeToString((domoticzAddress.getUsername() + ":" + domoticzAddress.getPassword()).getBytes());
+ theAuth.setValue("Basic " + encoding);
+ headers = new NameValue[1];
+ headers[0] = theAuth;
+ }
+
+ return headers;
+ }
public NamedIP getDomoticzAddress() {
return domoticzAddress;
}
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
index ce08ecf..e03b40a 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
@@ -1,6 +1,5 @@
package com.bwssystems.HABridge.plugins.domoticz;
-import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -17,13 +16,16 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
+import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
+import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.google.gson.Gson;
public class DomoticzHome implements Home {
private static final Logger log = LoggerFactory.getLogger(DomoticzHome.class);
private Map domoticzs;
private Boolean validDomoticz;
+ private HTTPHandler httpClient;
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
super();
@@ -40,14 +42,14 @@ public class DomoticzHome implements Home {
List deviceList = new ArrayList();
while(keys.hasNext()) {
String key = keys.next();
- theResponse = domoticzs.get(key).getDevices();
+ theResponse = domoticzs.get(key).getDevices(httpClient);
if(theResponse != null)
addDomoticzDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get lights for Domoticz with name: " + key + ", skipping this Domoticz.");
continue;
}
- theResponse = domoticzs.get(key).getScenes();
+ theResponse = domoticzs.get(key).getScenes(httpClient);
if(theResponse != null)
addDomoticzDevices(deviceList, theResponse, key);
else
@@ -70,6 +72,7 @@ public class DomoticzHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
+ Devices theDomoticzApiResponse = null;
String responseString = null;
String theUrl = anItem.getItem().getAsString();
@@ -78,13 +81,38 @@ public class DomoticzHome implements Home {
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
String hostAddr = null;
- String port = null;
if (hostPortion.contains(":")) {
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
- port = hostPortion.substring(intermediate.indexOf(':') + 1);
} else
hostAddr = hostPortion;
-
+ DomoticzHandler theHandler = findHandlerByAddress(hostAddr);
+ if(theHandler != null){
+ String theData;
+ String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
+ intensity, targetBri, targetBriInc, false);
+ theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, null, theHandler.buildHeaders());
+ try {
+ theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
+ if(theDomoticzApiResponse.getStatus().equals("OK"))
+ responseString = null;
+ else {
+ log.warn("Call failed for Domoticz " + theHandler.getDomoticzAddress().getName() + " with status " + theDomoticzApiResponse.getStatus() + " for item " + theDomoticzApiResponse.getTitle());
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ } catch (Exception e) {
+ log.warn("Cannot interrpret result from call for Domoticz " + theHandler.getDomoticzAddress().getName() + " as response is not parsable.");
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ } else {
+ log.warn("Domoticz Call could not complete, no address found: " + theUrl);
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
} else {
log.warn("Domoticz Call to be presented as http(s)://(:)/payload, format of request unknown: " + theUrl);
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
@@ -100,6 +128,7 @@ public class DomoticzHome implements Home {
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
if(!validDomoticz)
return null;
+ httpClient = new HTTPHandler();
domoticzs = new HashMap();
Iterator theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
while(theList.hasNext()) {
@@ -116,12 +145,23 @@ public class DomoticzHome implements Home {
private DomoticzHandler findHandlerByAddress(String hostAddress) {
DomoticzHandler aHandler = null;
-
+ boolean found = false;
+ Iterator keys = domoticzs.keySet().iterator();
+ while(keys.hasNext()) {
+ String key = keys.next();
+ aHandler = domoticzs.get(key);
+ if(aHandler != null && aHandler.getDomoticzAddress().getIp().equals(hostAddress)) {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ aHandler = null;
return aHandler;
}
@Override
public void closeHome() {
- // noop
+ httpClient.closeHandler();
}
}
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
index 245b729..5a78902 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
+
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
@@ -11,20 +12,20 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.ssl.SSLContexts;
+
import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
-import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,23 +34,23 @@ import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
- private HttpClient httpClient;
-// private CloseableHttpClient httpclientSSL;
+// private HttpClient httpClient;
+ private CloseableHttpClient httpClient;
// private SSLContext sslcontext;
// private SSLConnectionSocketFactory sslsf;
-// private RequestConfig globalConfig;
+ private RequestConfig globalConfig;
public HTTPHandler() {
- httpClient = HttpClients.createDefault();
+// httpClient = HttpClients.createDefault();
// Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
// Trust own CA and all self-signed certs
// sslcontext = SSLContexts.createDefault();
// Allow TLSv1 protocol only
// sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLS" }, null,
// SSLConnectionSocketFactory.getDefaultHostnameVerifier());
-// globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
-// httpclientSSL = HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(globalConfig).build();
+ globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
+ httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
}
@@ -142,23 +143,22 @@ public class HTTPHandler {
return theContent;
}
- public HttpClient getHttpClient() {
+// public HttpClient getHttpClient() {
+// return httpClient;
+// }
+
+
+ public CloseableHttpClient getHttpClient() {
return httpClient;
}
-// public CloseableHttpClient getHttpclientSSL() {
-// return httpclientSSL;
-// }
-
-
public void closeHandler() {
+ try {
+ httpClient.close();
+ } catch (IOException e) {
+ // noop
+ }
httpClient = null;
-// try {
-// httpclientSSL.close();
-// } catch (IOException e) {
-// // noop
-// }
-// httpclientSSL = null;
}
}
From 54e9303708a1f131959fd744885af6dd318aa19b Mon Sep 17 00:00:00 2001
From: Admin
Date: Fri, 24 Feb 2017 15:53:35 -0600
Subject: [PATCH 17/24] merge reqdme
---
README.md | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index 5286e0e..0ef7aef 100644
--- a/README.md
+++ b/README.md
@@ -33,27 +33,23 @@ ATTENTION: This requires JDK 1.8 to run
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
```
-java -jar ha-bridge-4.1.4.jar
+java -jar ha-bridge-4.2.0.jar
```
### Automation on Linux systems
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
-Create the directory and make sure that ha-bridge-4.1.2.jar is in your /home/pi/habridge directory.
-Create the directory and make sure that ha-bridge-4.1.4.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.0.jar is in your /home/pi/habridge directory.
```
pi@raspberrypi:~ $ mkdir habridge
pi@raspberrypi:~ $ cd habridge
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.2/ha-bridge-4.1.2.jar
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.4/ha-bridge-4.1.4.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.0/ha-bridge-4.2.0.jar
```
-Create the directory and make sure that ha-bridge-4.1.2.jar is in your /home/pi/habridge directory.
-Create the directory and make sure that ha-bridge-4.1.4.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.0.jar is in your /home/pi/habridge directory.
```
pi@raspberrypi:~ $ mkdir habridge
pi@raspberrypi:~ $ cd habridge
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.2/ha-bridge-4.1.2.jar
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.4/ha-bridge-4.1.4.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.0/ha-bridge-4.2.0.jar
```
#### System Control Setup on a pi (preferred)
For next gen Linux systems (this includes the Raspberry Pi), here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
@@ -73,8 +69,7 @@ After=network.target
[Service]
Type=simple
-ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.2.jar
-ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.4.jar
+ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.0.jar
[Install]
WantedBy=multi-user.target
@@ -109,8 +104,7 @@ Then cut and past this, modify any locations that are not correct
```
cd /home/pi/habridge
rm /home/pi/habridge/habridge-log.txt
-nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.2.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
-nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.4.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
+nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
chmod 777 /home/pi/habridge/habridge-log.txt
```
From 4de14217b486b54918b3ab4d4f4800cf6a304d2b Mon Sep 17 00:00:00 2001
From: Admin
Date: Thu, 2 Mar 2017 16:36:56 -0600
Subject: [PATCH 18/24] Fixed null http handler issue for close
---
pom.xml | 2 +-
.../com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index b10f483..b62cad6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.2.0
+ 4.2.0ajarHA Bridge
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
index e03b40a..45f66a7 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
@@ -161,7 +161,8 @@ public class DomoticzHome implements Home {
}
@Override
public void closeHome() {
- httpClient.closeHandler();
+ if(httpClient != null)
+ httpClient.closeHandler();
}
}
From 7b97bd75aeca8eed6177db576bc899e4fa054063 Mon Sep 17 00:00:00 2001
From: Admin
Date: Fri, 3 Mar 2017 16:25:45 -0600
Subject: [PATCH 19/24] fixed uniqueid on copy
---
pom.xml | 2 +-
src/main/resources/public/scripts/app.js | 5 ++++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index b62cad6..af9159c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.2.0a
+ 4.2.0bjarHA Bridge
diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js
index 612162d..484f08b 100644
--- a/src/main/resources/public/scripts/app.js
+++ b/src/main/resources/public/scripts/app.js
@@ -2447,8 +2447,11 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
bridgeService.displayWarn("Error adding device. Name has not been changed from original.", null);
return;
}
- if (copy)
+ if (copy) {
$scope.device.id = null;
+ $scope.device.uniqueid = null;
+ $scope.device.mapId = $scope.device.mapId + "-copy";
+ }
if($scope.mapTypeSelected !== undefined && $scope.mapTypeSelected !== null)
$scope.device.mapType = $scope.mapTypeSelected[0];
else
From a578aa9fd800314d06585bebc1278535f37c1169 Mon Sep 17 00:00:00 2001
From: Admin
Date: Mon, 6 Mar 2017 16:30:23 -0600
Subject: [PATCH 20/24] Update TCP handling to save connection. Added debug to
http handler.
---
pom.xml | 2 +-
.../HABridge/plugins/http/HTTPHandler.java | 97 +++++++++----------
.../HABridge/plugins/tcp/TCPHome.java | 49 +++++++---
3 files changed, 82 insertions(+), 66 deletions(-)
diff --git a/pom.xml b/pom.xml
index af9159c..e6f5f92 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.2.0b
+ 4.2.0cjarHA Bridge
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
index 5a78902..7c6ef96 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
@@ -5,16 +5,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.ssl.SSLContexts;
-
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
@@ -34,21 +24,11 @@ import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
-// private HttpClient httpClient;
private CloseableHttpClient httpClient;
-// private SSLContext sslcontext;
-// private SSLConnectionSocketFactory sslsf;
private RequestConfig globalConfig;
public HTTPHandler() {
-// httpClient = HttpClients.createDefault();
- // Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
- // Trust own CA and all self-signed certs
-// sslcontext = SSLContexts.createDefault();
- // Allow TLSv1 protocol only
-// sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLS" }, null,
-// SSLConnectionSocketFactory.getDefaultHostnameVerifier());
globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
}
@@ -101,40 +81,55 @@ public class HTTPHandler {
request.setHeader(headers[i].getName(), headers[i].getValue());
}
}
+ HttpResponse response;
try {
- HttpResponse response;
- // Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
-// if (url.startsWith("xyzhttps"))
-// response = httpclientSSL.execute(request);
-// else
+ for(int retryCount = 0; retryCount < 2; retryCount++) {
response = httpClient.execute(request);
- log.debug((httpVerb == null ? "GET" : httpVerb) + " execute on URL responded: "
- + response.getStatusLine().getStatusCode());
- if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
- if (response.getEntity() != null) {
- try {
- theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
- // content
- // for
- // data
- EntityUtils.consume(response.getEntity()); // close out
- // inputstream
- // ignore
- // content
- } catch (Exception e) {
- log.debug("Error ocurred in handling response entity after successful call, still responding success. "
- + e.getMessage(), e);
+ log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: "
+ + response.getStatusLine().getStatusCode());
+ if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
+ if (response.getEntity() != null) {
+ try {
+ theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
+ // content
+ // for
+ // data
+ EntityUtils.consume(response.getEntity()); // close out
+ // inputstream
+ // ignore
+ // content
+ } catch (Exception e) {
+ log.debug("Error ocurred in handling response entity after successful call, still responding success. "
+ + e.getMessage(), e);
+ }
+ log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
}
- }
- } else {
- log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
- try {
- EntityUtils.consume(response.getEntity()); // close out
- // inputstream
- // ignore
- // content
- } catch (Exception e) {
- //noop
+ retryCount = 2;
+ } else {
+ log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
+ try {
+ String someContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
+ // content
+ // for
+ // data
+ EntityUtils.consume(response.getEntity()); // close out
+ // inputstream
+ // ignore
+ // content
+ log.debug("Unsuccessfull response - The http response is <<<" + someContent + ">>>");
+ } catch (Exception e) {
+ //noop
+ }
+ if (response.getStatusLine().getStatusCode() == 504) {
+ log.warn("HTTP response code was 504, retrying...");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ // noop
+ }
+ }
+ else
+ retryCount = 2;
}
}
} catch (IOException e) {
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
index 5fb124b..aea477c 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
@@ -1,9 +1,13 @@
package com.bwssystems.HABridge.plugins.tcp;
import java.io.DataOutputStream;
+import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import javax.xml.bind.DatatypeConverter;
@@ -21,6 +25,7 @@ import com.bwssystems.HABridge.hue.TimeDecode;
public class TCPHome implements Home {
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
private byte[] sendData;
+ private Map theSockets;
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
@@ -31,6 +36,7 @@ public class TCPHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
+ Socket dataSendSocket = null;
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
String theUrl = anItem.getItem().getAsString();
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("tcp://")) {
@@ -40,15 +46,25 @@ public class TCPHome implements Home {
String hostAddr = null;
String port = null;
InetAddress IPAddress = null;
- if (hostPortion.contains(":")) {
- hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
- port = hostPortion.substring(intermediate.indexOf(':') + 1);
- } else
- hostAddr = hostPortion;
- try {
- IPAddress = InetAddress.getByName(hostAddr);
- } catch (UnknownHostException e) {
- // noop
+ dataSendSocket = theSockets.get(hostPortion);
+ if(dataSendSocket == null) {
+ if (hostPortion.contains(":")) {
+ hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
+ port = hostPortion.substring(intermediate.indexOf(':') + 1);
+ } else
+ hostAddr = hostPortion;
+ try {
+ IPAddress = InetAddress.getByName(hostAddr);
+ } catch (UnknownHostException e) {
+ // noop
+ }
+
+ try {
+ dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
+ theSockets.put(hostPortion, dataSendSocket);
+ } catch (Exception e) {
+ // noop
+ }
}
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
@@ -59,13 +75,10 @@ public class TCPHome implements Home {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
sendData = theUrlBody.getBytes();
}
-
try {
- Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
outToClient.write(sendData);
outToClient.flush();
- dataSendSocket.close();
} catch (Exception e) {
// noop
}
@@ -77,6 +90,7 @@ public class TCPHome implements Home {
@Override
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
log.info("TCP Home created.");
+ theSockets = new HashMap();
return this;
}
@@ -88,8 +102,15 @@ public class TCPHome implements Home {
@Override
public void closeHome() {
- // noop
-
+ Iterator> anIterator = theSockets.entrySet().iterator();
+ while(anIterator.hasNext()) {
+ Socket aSocket = (Socket) anIterator.next();
+ try {
+ aSocket.close();
+ } catch (IOException e) {
+ // noop
+ }
+ }
}
}
From f6cb41b8801ec1f22330e7823267f6d0e73f823a Mon Sep 17 00:00:00 2001
From: Admin
Date: Tue, 7 Mar 2017 16:36:25 -0600
Subject: [PATCH 21/24] Fixed hex handling of intensity. Added handling for \n,
\t, \r and so forth in tcp,udp and mqtt.
---
pom.xml | 7 ++++++-
.../HABridge/hue/BrightnessDecode.java | 21 +++++++++++++++----
.../HABridge/plugins/mqtt/MQTTHandler.java | 3 ++-
.../HABridge/plugins/tcp/TCPHome.java | 2 ++
.../HABridge/plugins/udp/UDPHome.java | 2 ++
5 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/pom.xml b/pom.xml
index e6f5f92..e28f6ac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.2.0c
+ 4.2.0djarHA Bridge
@@ -126,6 +126,11 @@
lifx-sdk-java2.1.6
+
+ org.apache.commons
+ commons-lang3
+ 3.5
+
diff --git a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
index 7c31f11..9c5b7c9 100644
--- a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
+++ b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
@@ -3,6 +3,8 @@ package com.bwssystems.HABridge.hue;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
+
+import org.apache.commons.lang3.Conversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.java.dev.eval.Expression;
@@ -44,7 +46,7 @@ public class BrightnessDecode {
}
if (request.contains(INTENSITY_BYTE)) {
if (isHex) {
- String hexValue = Integer.toHexString(intensity);
+ String hexValue = convertToHex(intensity);
request = request.replace(INTENSITY_BYTE, hexValue);
} else {
String intensityByte = String.valueOf(intensity);
@@ -53,7 +55,7 @@ public class BrightnessDecode {
} else if (request.contains(INTENSITY_PERCENT)) {
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
if (isHex) {
- String hexValue = Integer.toHexString(percentBrightness);
+ String hexValue = convertToHex(percentBrightness);
request = request.replace(INTENSITY_PERCENT, hexValue);
} else {
String intensityPercent = String.valueOf(percentBrightness);
@@ -72,7 +74,7 @@ public class BrightnessDecode {
BigDecimal result = exp.eval(variables);
Integer endResult = Math.round(result.floatValue());
if (isHex) {
- String hexValue = Integer.toHexString(endResult);
+ String hexValue = convertToHex(endResult);
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, hexValue);
} else {
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE,
@@ -89,4 +91,15 @@ public class BrightnessDecode {
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
}
-}
+
+ // Apache Commons Conversion utils likes little endian too much
+ private static String convertToHex(int theValue) {
+ String destHex = "00";
+ String hexValue = Conversion.intToHex(theValue, 0, destHex, 0, 2);
+ byte[] theBytes = hexValue.getBytes();
+ byte[] newBytes = new byte[2];
+ newBytes[0] = theBytes[1];
+ newBytes[1] = theBytes[0];
+ return new String(newBytes);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java
index d96ab68..e40001f 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java
@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.plugins.mqtt;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
@@ -47,7 +48,7 @@ public class MQTTHandler {
}
public void publishMessage(String topic, String content) {
- MqttMessage message = new MqttMessage(content.getBytes());
+ MqttMessage message = new MqttMessage(StringEscapeUtils.unescapeJava(content).getBytes());
message.setQos(qos);
try {
myClient.publish(topic, message);
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
index aea477c..42e05f9 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
@@ -11,6 +11,7 @@ import java.util.Map;
import javax.xml.bind.DatatypeConverter;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -73,6 +74,7 @@ public class TCPHome implements Home {
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
+ theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();
}
try {
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java
index b93a72e..1244bff 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
import javax.xml.bind.DatatypeConverter;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,6 +60,7 @@ public class UDPHome implements Home {
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
+ theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();
}
try {
From ed8fc95782387f4a232ac8e76630b2cb5fb903c0 Mon Sep 17 00:00:00 2001
From: Admin
Date: Wed, 8 Mar 2017 14:59:04 -0600
Subject: [PATCH 22/24] Fixed HA group support. Added JSON check for new
devices. Added Device level filtering. Added decimal percentage.
---
README.md | 20 +++++-----
pom.xml | 4 +-
.../HABridge/dao/DeviceDescriptor.java | 11 ++++++
.../HABridge/dao/DeviceRepository.java | 27 +++++++++++++
.../devicemanagmeent/DeviceResource.java | 39 ++++++++++++++++++-
.../HABridge/hue/BrightnessDecode.java | 6 +++
.../bwssystems/HABridge/hue/HueMulator.java | 7 ++--
.../HABridge/plugins/hass/HomeAssistant.java | 8 +++-
.../HABridge/plugins/tcp/TCPHome.java | 25 ++++++++----
.../public/views/domoticzdevice.html | 1 +
.../resources/public/views/editdevice.html | 13 +++++--
.../resources/public/views/haldevice.html | 1 +
.../resources/public/views/hassdevice.html | 1 +
.../resources/public/views/veradevice.html | 1 +
14 files changed, 134 insertions(+), 30 deletions(-)
diff --git a/README.md b/README.md
index 0ef7aef..da5977a 100644
--- a/README.md
+++ b/README.md
@@ -33,23 +33,23 @@ ATTENTION: This requires JDK 1.8 to run
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
```
-java -jar ha-bridge-4.2.0.jar
+java -jar ha-bridge-4.2.1.jar
```
### Automation on Linux systems
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
-Create the directory and make sure that ha-bridge-4.2.0.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.1.jar is in your /home/pi/habridge directory.
```
pi@raspberrypi:~ $ mkdir habridge
pi@raspberrypi:~ $ cd habridge
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.0/ha-bridge-4.2.0.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.1/ha-bridge-4.2.1.jar
```
-Create the directory and make sure that ha-bridge-4.2.0.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.1.jar is in your /home/pi/habridge directory.
```
pi@raspberrypi:~ $ mkdir habridge
pi@raspberrypi:~ $ cd habridge
-pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.0/ha-bridge-4.2.0.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.1/ha-bridge-4.2.1.jar
```
#### System Control Setup on a pi (preferred)
For next gen Linux systems (this includes the Raspberry Pi), here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
@@ -69,7 +69,7 @@ After=network.target
[Service]
Type=simple
-ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.0.jar
+ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.1.jar
[Install]
WantedBy=multi-user.target
@@ -104,7 +104,7 @@ Then cut and past this, modify any locations that are not correct
```
cd /home/pi/habridge
rm /home/pi/habridge/habridge-log.txt
-nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
+nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.1.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
chmod 777 /home/pi/habridge/habridge-log.txt
```
@@ -354,7 +354,7 @@ Headers can be added as well using a Json construct [{"name":"header type name",
Another option that is detected by the bridge is to use UDP or TCP direct calls such as `udp://:/` to send a UDP request. TCP calls are handled the same way as `tcp://:/`. If your data for the UDP or TCP request is formatted as "0x00F009B9" lexical hex format, the bridge will convert the data into a binary stream to send.
-You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}". See Value Passing Controls Below.
+You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}". See Value Passing Controls Below.
Examples:
```
@@ -408,7 +408,7 @@ OR
```
#### Value Passing Controls
-There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.byte}" and "${intensity.math(using X in your calc)}".
+There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.decimal_percent}", "${intensity.byte}" and "${intensity.math(using X in your calc)}".
You can control items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}".
For the items that want to have a date time put into the message, utilize ${time.format(yyyy-MM-ddTHH:mm:ssXXX)} where "yyyy-MM-ddTHH:mm:ssXXX" can be any format from the Java SimpleDateFormat documented here: https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
e.g.
@@ -518,7 +518,7 @@ contentBodyOff | string | This is the content body that you would like to send w
}
```
#### Dimming Control Example
-Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value.
+Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} for 0-255 for straight pass through of the value.
e.g.
```
{
diff --git a/pom.xml b/pom.xml
index e28f6ac..638a919 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridgeha-bridge
- 4.2.0d
+ 4.2.1jarHA Bridge
@@ -48,7 +48,7 @@
com.github.bwssytemsnest-controller
- 1.0.13
+ 1.0.14org.slf4j
diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
index a727c26..547b04e 100644
--- a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
+++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
@@ -62,6 +62,9 @@ public class DeviceDescriptor{
@SerializedName("noState")
@Expose
private boolean noState;
+ @SerializedName("requesterAddress")
+ @Expose
+ private String requesterAddress;
private DeviceState deviceState;
@@ -219,6 +222,14 @@ public class DeviceDescriptor{
this.noState = noState;
}
+ public String getRequesterAddress() {
+ return requesterAddress;
+ }
+
+ public void setRequesterAddress(String requesterAddress) {
+ this.requesterAddress = requesterAddress;
+ }
+
public boolean containsType(String aType) {
if(aType == null)
return false;
diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
index a06a8d8..cf44ecb 100644
--- a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
+++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
@@ -83,6 +83,33 @@ public class DeviceRepository extends BackupHandler {
return list;
}
+ public List findAllByRequester(String anAddress) {
+ List list = new ArrayList(devices.values());
+ List theReturnList = new ArrayList();
+ Iterator anIterator = list.iterator();
+ DeviceDescriptor theDevice;
+ String theRequesterAddress;
+
+ HashMap addressMap;
+ while (anIterator.hasNext()) {
+ theDevice = anIterator.next();
+ theRequesterAddress = theDevice.getRequesterAddress();
+ addressMap = new HashMap();
+ if(theRequesterAddress != null) {
+ if (theRequesterAddress.contains(",")) {
+ String[] theArray = theRequesterAddress.split(",");
+ for (String v : theArray) {
+ addressMap.put(v.trim(), v.trim());
+ }
+ } else
+ addressMap.put(theRequesterAddress, theRequesterAddress);
+ }
+ if (theRequesterAddress == null || theRequesterAddress.length() == 0 || addressMap.containsKey(anAddress))
+ theReturnList.add(theDevice);
+ }
+ return theReturnList;
+ }
+
public DeviceDescriptor findOne(String id) {
return devices.get(id);
}
diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
index 98aaa63..e4bb6ca 100644
--- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
+++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
@@ -18,12 +18,15 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.HomeManager;
+import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
import com.bwssystems.HABridge.dao.ErrorMessage;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonSyntaxException;
/**
spark core server for bridge configuration
@@ -33,11 +36,13 @@ public class DeviceResource {
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
private DeviceRepository deviceRepository;
private HomeManager homeManager;
+ private Gson aGsonHandler;
private static final Set supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
homeManager = aHomeManager;
+ aGsonHandler = new GsonBuilder().create();
setupEndpoints();
}
@@ -65,14 +70,44 @@ public class DeviceResource {
else {
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
}
+ CallItem[] callItems = null;
+ String errorMessage = null;
for(int i = 0; i < devices.length; i++) {
if(devices[i].getContentBody() != null ) {
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
response.status(HttpStatus.SC_BAD_REQUEST);
- log.debug("Bad http verb in create a Device(s): " + request.body());
- return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
+ errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
}
}
+ try {
+ if(devices[i].getOnUrl() != null && !devices[i].getOnUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getOnUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
+ try {
+ if(devices[i].getDimUrl() != null && !devices[i].getDimUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getDimUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
+ try {
+ if(devices[i].getOffUrl() != null && !devices[i].getOffUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getOffUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
}
deviceRepository.save(devices);
diff --git a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
index 9c5b7c9..ff6c186 100644
--- a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
+++ b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
@@ -12,6 +12,7 @@ import net.java.dev.eval.Expression;
public class BrightnessDecode {
private static final Logger log = LoggerFactory.getLogger(BrightnessDecode.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}";
+ private static final String INTENSITY_DECIMAL_PERCENT = "${intensity.decimal_percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}";
private static final String INTENSITY_MATH = "${intensity.math(";
private static final String INTENSITY_MATH_VALUE = "X";
@@ -61,6 +62,11 @@ public class BrightnessDecode {
String intensityPercent = String.valueOf(percentBrightness);
request = request.replace(INTENSITY_PERCENT, intensityPercent);
}
+ } else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
+ float decimalBrightness = (float) (intensity / 255.0);
+
+ String intensityPercent = String.format("%1.2f", decimalBrightness);
+ request = request.replace(INTENSITY_DECIMAL_PERCENT, intensityPercent);
} else if (request.contains(INTENSITY_MATH)) {
Map variables = new HashMap();
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
index 017d8e2..dca0dfe 100644
--- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
+++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
@@ -668,7 +668,8 @@ public class HueMulator {
log.debug("hue lights list requested: " + userId + " from " + requestIp);
theErrors = validateWhitelistUser(userId, false);
if (theErrors == null) {
- List deviceList = repository.findActive();
+ List deviceList = repository.findAllByRequester(requestIp);
+// List deviceList = repository.findActive();
deviceResponseMap = new HashMap();
for (DeviceDescriptor device : deviceList) {
DeviceResponse deviceResponse = null;
@@ -944,8 +945,8 @@ public class HueMulator {
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
- if(!filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
- log.debug("filter for requester address not present in list: " + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
+ if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
+ log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
}
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java b/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java
index 9f6a702..dcf4b54 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java
@@ -41,7 +41,12 @@ public class HomeAssistant {
aUrl = "https";
else
aUrl = "http";
- aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/" + aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
+ String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
+ aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
+ if(domain.equals("group"))
+ aUrl = aUrl + "homeassistant";
+ else
+ aUrl = aUrl + domain;
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
NameValue[] headers = null;
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
@@ -62,6 +67,7 @@ public class HomeAssistant {
aUrl = aUrl + "/turn_off";
aBody = aBody + "}";
}
+ log.debug("Calling HomeAssistant with url: " + aUrl);
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
log.debug("call Command return is: <" + theData + ">");
return true;
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
index 42e05f9..53cb664 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
@@ -82,7 +82,13 @@ public class TCPHome implements Home {
outToClient.write(sendData);
outToClient.flush();
} catch (Exception e) {
- // noop
+ log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
+ try {
+ dataSendSocket.close();
+ } catch (IOException e1) {
+ // noop
+ }
+ theSockets.remove(hostPortion);
}
} else
log.warn("Tcp Call to be presented as tcp://:/payload, format of request unknown: " + theUrl);
@@ -104,13 +110,16 @@ public class TCPHome implements Home {
@Override
public void closeHome() {
- Iterator> anIterator = theSockets.entrySet().iterator();
- while(anIterator.hasNext()) {
- Socket aSocket = (Socket) anIterator.next();
- try {
- aSocket.close();
- } catch (IOException e) {
- // noop
+ log.debug("Shutting down TCP sockets.");
+ if(theSockets != null && !theSockets.isEmpty()) {
+ Iterator keys = theSockets.keySet().iterator();
+ while(keys.hasNext()) {
+ String key = keys.next();
+ try {
+ theSockets.get(key).close();
+ } catch (IOException e) {
+ // noop
+ }
}
}
}
diff --git a/src/main/resources/public/views/domoticzdevice.html b/src/main/resources/public/views/domoticzdevice.html
index 7f4f151..7629889 100644
--- a/src/main/resources/public/views/domoticzdevice.html
+++ b/src/main/resources/public/views/domoticzdevice.html
@@ -43,6 +43,7 @@
+
diff --git a/src/main/resources/public/views/editdevice.html b/src/main/resources/public/views/editdevice.html
index f380fdd..ea8df42 100644
--- a/src/main/resources/public/views/editdevice.html
+++ b/src/main/resources/public/views/editdevice.html
@@ -33,7 +33,7 @@
fields the bridge uses. Please use care when updating these fields as
you may break the settings used by the bridge to call a specific end
point device.
-
This area allows you to create any http or
+
This area allows you to create any http, tcp or
udp call to an endpoint. You can use the default GET or select the
http verb type below and configure a payload for either on, dim or
off methods. For Execution of a
@@ -41,7 +41,7 @@
can use Json notation of array with [{"item":"the
payload"},{"item":"another payload"}] to
execute multiple entries. Adding the value replacements
- (${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
+ (${intensity.byte},${intensity.percent},${intensity.decimal_percent},${intensity.math(X*1)}) will
also work. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command.
When copying, update the name and select the "Add Bridge
@@ -65,17 +65,22 @@
ng-model="device.name" placeholder="Device Name">
-
Inactive
+
{{device.inactive}}
-
No State (Do not update state for device)
+
{{device.noState}}
+
+
+
+
diff --git a/src/main/resources/public/views/haldevice.html b/src/main/resources/public/views/haldevice.html
index 13878cf..38b2cd3 100644
--- a/src/main/resources/public/views/haldevice.html
+++ b/src/main/resources/public/views/haldevice.html
@@ -42,6 +42,7 @@
+
diff --git a/src/main/resources/public/views/hassdevice.html b/src/main/resources/public/views/hassdevice.html
index bf241ea..1ff957d 100644
--- a/src/main/resources/public/views/hassdevice.html
+++ b/src/main/resources/public/views/hassdevice.html
@@ -43,6 +43,7 @@
+
diff --git a/src/main/resources/public/views/veradevice.html b/src/main/resources/public/views/veradevice.html
index 68105af..79c4fe7 100644
--- a/src/main/resources/public/views/veradevice.html
+++ b/src/main/resources/public/views/veradevice.html
@@ -43,6 +43,7 @@
+
From 62e366c028d38982dc7124a0603ead846a304dda Mon Sep 17 00:00:00 2001
From: BWS Systems
Date: Wed, 8 Mar 2017 16:03:51 -0600
Subject: [PATCH 23/24] Add pics
---
README.md | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/README.md b/README.md
index da5977a..ae82f42 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,32 @@
# ha-bridge
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo or Google Home. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
+Here are some diagrams to put this software in perspective.
+
+The Echo Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Amazon Echo |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
+The Google Home Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Google Home |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
+THe Harmony Hub Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Harmony Hub |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
**SECURITY RISK: If you are unsure on how this software operates and what it exposes to your network, please make sure you understand that it can allow root access to your system. It is best practice to not open this to the Internet through your router as there are no security protocols in place to protect the system. The License agreement states specifically that you use this at your own risk.**
**ATTENTION: This requires a physical Amazon Echo, Dot or Tap and does not work with prototype devices built using the Alexa Voice Service e.g. Amazon's Alexa AVS Sample App and Sam Machin's AlexaPi. The AVS version does not have any capability for Hue Bridge discovery!**
From 1b676632fe4e0f7796fe6f200fe81c82c5b7249a Mon Sep 17 00:00:00 2001
From: Sam Turner
Date: Thu, 9 Mar 2017 14:58:25 +0000
Subject: [PATCH 24/24] delete kodivolume.md as there is now a page in the wiki
---
kodivolume.md | 144 --------------------------------------------------
1 file changed, 144 deletions(-)
delete mode 100644 kodivolume.md
diff --git a/kodivolume.md b/kodivolume.md
deleted file mode 100644
index 165278d..0000000
--- a/kodivolume.md
+++ /dev/null
@@ -1,144 +0,0 @@
-# Kodi volume control using dim commands & JSON-RPC
-
-You can use HA Bridge to adjust the Kodi software volume output. This allows you to use dim commands and set the volume level with percentage values.
-
-### What is JSON-RPC?
-
-The short answer is JSON-RPC an interface to communicate with Kodi. [See the official Kodi Wiki for more info](http://kodi.wiki/view/JSON-RPC_API)
-
-### Setup Kodi to allow control through JSON-RPC
-
-In Kodi navigate to Settings/Services/Control ([screenshot](http://kodi.wiki/view/Settings/Services/Control))
-
-Turn **ON** the following:
-- Allow control of Kodi via HTTP
-- Allow remote control from applications on this system
-- Allow remote control from applications on other systems
-
-Change the **username** to something unique and set a strong **password**.
-
-Make a note of the **PORT**
-### Adding the device to HA Bridge
-
-Access the HA Bridge Configuration in your browser and open the **Manual Add** tab.
-#### Name
-
-Give the device a unique name that doesn’t include **“volume”** as it will cause conflicts with the Echo’s built in volume controls. A device name of **“cody sound”** works well.
-#### Device type
-
-Select **TCP** in the dropdown
-### URLs
-
-This section might seem a little long winded and if you know what you are doing then feel free to jump ahead.
-#### Building the URL
-
-We need to log into the Kodi web server without having to fill in the popup each time. You can do this by putting the username and password in the URL. It is not a good idea to do this on other websites as it does put your password in clear view, but for your local network it is fine.
-
-Use the example below replacing the relevant sections with the details that you defined in the Kodi settings screen in the first step. Replacing the IP with the address of the machine that Kodi is running on.
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc
-```
-##### Testing the URL in a browser
-
-Before you continue, open your custom URL in a browser (making sure Kodi is running). If all is working as it should you will see a big page of JSON that starts with:
-
-``` json
-{
- "description": "JSON-RPC API of XBMC",
- "id": "http://xbmc.org/jsonrpc/ServiceDescription.json",
-```
-
-If you don’t see something that looks like the code above, then go back and double check your settings.
-#### The JSON request
-
-The URL is what connects you to Kodi, JSON is what is used to communicate with it. The JSON that is used to set the volume level is:
-
-``` json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-##### Joining the URL and JSON
-
-Join the two together by adding `?request=` to the end of the URL and then add the JSON to the end of the request. You will end up with something like:
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-### Testing the request in a browser
-
-Go ahead and test the combined URL/JSON in a browser changing **100** to whatever level you want to set. Kodi should adjust the volume accordingly, try a few different levels to be sure it is working correctly.
-
-The browser will reformat the URL each time you press return so don’t build the URL in the browser bar without making a copy first.
-
-Ideally build the URL in a text document which you can easily edit and then copy/paste each time.
-
-### Prepare the three URLs
-
-You want to end up with three full URLs in your text file, one for each of the commands.
-
-**ON**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-
-**DIM**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":45},"id":1}
-```
-
-**OFF**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
-```
-
-### Test the three URLS
-
-You should now be able to control the volume of Kodi using the structured URL you built above in a browser.
-
-If you can’t get it to work in a browser then you won’t be able to get it to work in HA Bridge.
-
-
-### Manually adding the device
-
-Add a new manual device and give it a name e.g. “Cody Sound”
-
-Set `Device type` to `Custom`
-
-Use the same URL for all three (ON, OFF, DIM)
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=
-```
-
-* `HTTP Verb` to `POST`
-* `Content type` to `application/json`
-
-**Content body On**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-**Content body Dim**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":${intensity.percent}},"id":1}
-```
-**Content body Off**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
-```
-
-
-### HA Bridge
-
-Save and test the button in the Bridge Devices tab and hopefully it should turn the volume up in Kodi.
-
-### Controlling the Device
-
-You can use the commands as listed in the [README](https://github.com/bwssytems/ha-bridge#ask-alexa)
-
-“Set Cody Sound to 50 percent”
-“Cody Sound to 70 percent”
-
-Remembering that “Turn on Cody Sound” will set the volume to 100%, and “Turn off Cody Sound” will mute.