mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Finished implementation of headers and tested. Added calls for TCP
request with UDP and also added the value replacement for dimming, this needs to be tested.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
package com.bwssystems.HABridge.api;
|
||||
|
||||
public class CallItem {
|
||||
private String Item;
|
||||
private String item;
|
||||
|
||||
public String getItem() {
|
||||
return Item;
|
||||
return item;
|
||||
}
|
||||
|
||||
public void setItem(String item) {
|
||||
Item = item;
|
||||
public void setItem(String anitem) {
|
||||
item = anitem;
|
||||
}
|
||||
}
|
||||
|
||||
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.HABridge.api;
|
||||
|
||||
public class NameValue {
|
||||
private String name;
|
||||
private String value;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,9 @@ public class DeviceDescriptor{
|
||||
@SerializedName("onUrl")
|
||||
@Expose
|
||||
private String onUrl;
|
||||
@SerializedName("headers")
|
||||
@Expose
|
||||
private String headers;
|
||||
@SerializedName("httpVerb")
|
||||
@Expose
|
||||
private String httpVerb;
|
||||
@@ -122,6 +125,14 @@ public class DeviceDescriptor{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(String headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getHttpVerb() {
|
||||
return httpVerb;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.hue;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
@@ -45,11 +46,13 @@ import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -330,6 +333,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String lightId = request.params(":id");
|
||||
String responseString = null;
|
||||
String url = null;
|
||||
NameValue[] theHeaders = null;
|
||||
DeviceState state = null;
|
||||
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
@@ -351,6 +355,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
return responseString;
|
||||
}
|
||||
|
||||
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||
@@ -367,7 +372,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
|
||||
// make call
|
||||
responseString = doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+myHueHome.getTheHUERegisteredUser()+"/lights/"+deviceId.getDeviceId()+"/state", HttpPut.METHOD_NAME, device.getContentType(), request.body());
|
||||
responseString = doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+myHueHome.getTheHUERegisteredUser()+"/lights/"+deviceId.getDeviceId()+"/state", HttpPut.METHOD_NAME, device.getContentType(), request.body(), null);
|
||||
if (responseString == null) {
|
||||
log.warn("Error on calling url to change device state: " + url);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling HUE to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
@@ -511,16 +516,40 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(device.getDeviceType().startsWith("Exec")) {
|
||||
Process p = Runtime.getRuntime().exec(url);
|
||||
}
|
||||
else if(url.contains("udp://"))
|
||||
{
|
||||
if(!url.substring(0, 1).equalsIgnoreCase("[")) {
|
||||
url = "[{\"item\":\"" + url +"\"}]";
|
||||
else if(device.getDeviceType().startsWith("exec")) {
|
||||
log.debug("Exec Request called with url: " + url);
|
||||
if(!url.startsWith("[")) {
|
||||
if(url.startsWith("{\"item"))
|
||||
url = "[" + url + "]";
|
||||
else
|
||||
url = "[{\"item\":\"" + url +"\"}]";
|
||||
}
|
||||
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
|
||||
for(int i = 0; i < callItems.length; i++) {
|
||||
if( i > 0) {
|
||||
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||
}
|
||||
try {
|
||||
log.debug("Executing request: " + callItems[i].getItem());
|
||||
Process p = Runtime.getRuntime().exec(callItems[i].getItem());
|
||||
log.debug("Process running: " + p.isAlive());
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not execute request: " + callItems[i].getItem(), e);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
i = callItems.length+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(url.contains("udp://") || url.contains("tcp://"))
|
||||
{
|
||||
log.debug("executing HUE api request for network call: " + url);
|
||||
if(!url.startsWith("[")) {
|
||||
if(url.startsWith("{\"item"))
|
||||
url = "[" + url + "]";
|
||||
else
|
||||
url = "[{\"item\":\"" + url +"\"}]";
|
||||
}
|
||||
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
|
||||
log.debug("executing HUE api request to UDP: " + url);
|
||||
for(int i = 0; i < callItems.length; i++) {
|
||||
if( i > 0) {
|
||||
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||
@@ -529,19 +558,28 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String intermediate = callItems[i].getItem().substring(6);
|
||||
String ipAddr = intermediate.substring(0, intermediate.indexOf(':'));
|
||||
String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/'));
|
||||
String theBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||
String theBody = replaceIntensityValue(intermediate.substring(intermediate.indexOf('/')+1), state.getBri());
|
||||
if(theBody.startsWith("0x")) {
|
||||
sendData = DatatypeConverter.parseHexBinary(theBody.substring(2));
|
||||
}
|
||||
else
|
||||
sendData = theBody.getBytes();
|
||||
InetAddress IPAddress = InetAddress.getByName(ipAddr);
|
||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||
responseSocket.send(sendPacket);
|
||||
responseSocket.close();
|
||||
if(callItems[i].getItem().contains("udp://")) {
|
||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||
responseSocket.send(sendPacket);
|
||||
responseSocket.close();
|
||||
}
|
||||
else if(callItems[i].getItem().contains("tcp://"))
|
||||
{
|
||||
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||
outToClient.write(sendData);
|
||||
dataSendSocket.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not send UDP Datagram packet for request.", e);
|
||||
log.warn("Could not send data for network request.", e);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
i = callItems.length+1;
|
||||
}
|
||||
@@ -549,8 +587,11 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!url.substring(0, 1).equalsIgnoreCase("[")) {
|
||||
url = "[{\"item\":\"" + url +"\"}]";
|
||||
if(!url.startsWith("[")) {
|
||||
if(url.startsWith("{\"item"))
|
||||
url = "[" + url + "]";
|
||||
else
|
||||
url = "[{\"item\":\"" + url +"\"}]";
|
||||
}
|
||||
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
|
||||
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + url);
|
||||
@@ -566,7 +607,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||
// make call
|
||||
if (doHttpRequest(anUrl, device.getHttpVerb(), device.getContentType(), body) == null) {
|
||||
if (doHttpRequest(anUrl, device.getHttpVerb(), device.getContentType(), body, theHeaders) == null) {
|
||||
log.warn("Error on calling url to change device state: " + anUrl);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
i = callItems.length+1;
|
||||
@@ -620,7 +661,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
|
||||
|
||||
// This function executes the url from the device repository against the vera
|
||||
protected String doHttpRequest(String url, String httpVerb, String contentType, String body) {
|
||||
protected String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
|
||||
HttpUriRequest request = null;
|
||||
String theContent = null;
|
||||
try {
|
||||
@@ -645,6 +686,11 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
log.debug("Making outbound call in doHttpRequest: " + request);
|
||||
try {
|
||||
if(headers != null && headers.length > 0) {
|
||||
for(int i = 0; i < headers.length; i++) {
|
||||
request.setHeader(headers[i].getName(), headers[i].getValue());
|
||||
}
|
||||
}
|
||||
HttpResponse 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){
|
||||
|
||||
@@ -112,6 +112,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
self.state.device.deviceType = "custom";
|
||||
self.state.device.targetDevice = null;
|
||||
self.state.device.offUrl = "";
|
||||
self.state.device.headers = null;
|
||||
self.state.device.httpVerb = null;
|
||||
self.state.device.contentType = null;
|
||||
self.state.device.contentBody = null;
|
||||
@@ -882,6 +883,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
targetDevice: $scope.device.targetDevice,
|
||||
onUrl: $scope.device.onUrl,
|
||||
offUrl: $scope.device.offUrl,
|
||||
headers: $scope.device.headers,
|
||||
httpVerb: $scope.device.httpVerb,
|
||||
contentType: $scope.device.contentType,
|
||||
contentBody: $scope.device.contentBody,
|
||||
@@ -1180,6 +1182,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
targetDevice: $scope.device.targetDevice,
|
||||
onUrl: $scope.device.onUrl,
|
||||
offUrl: $scope.device.offUrl,
|
||||
headers: $scope.device.headers,
|
||||
httpVerb: $scope.device.httpVerb,
|
||||
contentType: $scope.device.contentType,
|
||||
contentBody: $scope.device.contentBody,
|
||||
|
||||
@@ -44,6 +44,27 @@
|
||||
<button class="btn btn-primary" ng-click="copyDevice()">
|
||||
Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
<option value="switch">Switch</option>
|
||||
<option value="scene">Scene</option>
|
||||
<option value="activity">Activity</option>
|
||||
<option value="button">Button</option>
|
||||
<option value="thermo">Thermo</option>
|
||||
<option value="passthru">Pass Thru</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
|
||||
@@ -107,6 +128,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-headers">HTTP Headers </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<p class="text-muted">This area allows you to create any http 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. Currently, https is not supported. For Execution of
|
||||
a script or program, plese fill in the path. All manually entered calls 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)})
|
||||
[{"item":"the payload"},{"item":"another payload"}] to execute multiple entries. Adding the value replacements (${intensity..byte},${intensity.percent},${intensity.math(X*1)})
|
||||
will also work.</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
@@ -107,7 +107,8 @@
|
||||
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="Exec">Execute Script/Program</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,6 +148,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-headers">HTTP Headers </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||
|
||||
Reference in New Issue
Block a user