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:
Admin
2016-04-25 16:48:59 -05:00
parent ee45cee8e3
commit aecd589308
7 changed files with 147 additions and 25 deletions

View File

@@ -1,13 +1,13 @@
package com.bwssystems.HABridge.api; package com.bwssystems.HABridge.api;
public class CallItem { public class CallItem {
private String Item; private String item;
public String getItem() { public String getItem() {
return Item; return item;
} }
public void setItem(String item) { public void setItem(String anitem) {
Item = item; item = anitem;
} }
} }

View 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;
}
}

View File

@@ -35,6 +35,9 @@ public class DeviceDescriptor{
@SerializedName("onUrl") @SerializedName("onUrl")
@Expose @Expose
private String onUrl; private String onUrl;
@SerializedName("headers")
@Expose
private String headers;
@SerializedName("httpVerb") @SerializedName("httpVerb")
@Expose @Expose
private String httpVerb; private String httpVerb;
@@ -122,6 +125,14 @@ public class DeviceDescriptor{
this.id = id; this.id = id;
} }
public String getHeaders() {
return headers;
}
public void setHeaders(String headers) {
this.headers = headers;
}
public String getHttpVerb() { public String getHttpVerb() {
return httpVerb; return httpVerb;
} }

View File

@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.BridgeSettingsDescriptor; import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.api.CallItem; import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.UserCreateRequest; import com.bwssystems.HABridge.api.UserCreateRequest;
import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.api.hue.DeviceState; import com.bwssystems.HABridge.api.hue.DeviceState;
@@ -45,11 +46,13 @@ import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -330,6 +333,7 @@ public class HueMulator implements HueErrorStringSet {
String lightId = request.params(":id"); String lightId = request.params(":id");
String responseString = null; String responseString = null;
String url = null; String url = null;
NameValue[] theHeaders = null;
DeviceState state = null; DeviceState state = null;
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body()); log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
response.header("Access-Control-Allow-Origin", request.headers("Origin")); response.header("Access-Control-Allow-Origin", request.headers("Origin"));
@@ -351,6 +355,7 @@ public class HueMulator implements HueErrorStringSet {
return responseString; return responseString;
} }
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
responseString = this.formatSuccessHueResponse(state, request.body(), lightId); responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice"))) if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
@@ -367,7 +372,7 @@ public class HueMulator implements HueErrorStringSet {
} }
// make call // 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) { if (responseString == null) {
log.warn("Error on calling url to change device state: " + url); 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\"}}]"; 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")) { else if(device.getDeviceType().startsWith("exec")) {
Process p = Runtime.getRuntime().exec(url); log.debug("Exec Request called with url: " + url);
} if(!url.startsWith("[")) {
else if(url.contains("udp://")) if(url.startsWith("{\"item"))
{ url = "[" + url + "]";
if(!url.substring(0, 1).equalsIgnoreCase("[")) { else
url = "[{\"item\":\"" + url +"\"}]"; 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); 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++) { for(int i = 0; i < callItems.length; i++) {
if( i > 0) { if( i > 0) {
Thread.sleep(bridgeSettings.getButtonsleep()); Thread.sleep(bridgeSettings.getButtonsleep());
@@ -529,19 +558,28 @@ public class HueMulator implements HueErrorStringSet {
String intermediate = callItems[i].getItem().substring(6); String intermediate = callItems[i].getItem().substring(6);
String ipAddr = intermediate.substring(0, intermediate.indexOf(':')); String ipAddr = intermediate.substring(0, intermediate.indexOf(':'));
String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/')); String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/'));
String theBody = intermediate.substring(intermediate.indexOf('/')+1); String theBody = replaceIntensityValue(intermediate.substring(intermediate.indexOf('/')+1), state.getBri());
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
if(theBody.startsWith("0x")) { if(theBody.startsWith("0x")) {
sendData = DatatypeConverter.parseHexBinary(theBody.substring(2)); sendData = DatatypeConverter.parseHexBinary(theBody.substring(2));
} }
else else
sendData = theBody.getBytes(); sendData = theBody.getBytes();
InetAddress IPAddress = InetAddress.getByName(ipAddr); InetAddress IPAddress = InetAddress.getByName(ipAddr);
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port)); if(callItems[i].getItem().contains("udp://")) {
responseSocket.send(sendPacket); DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
responseSocket.close(); 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) { } 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\"}}]"; responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
i = callItems.length+1; i = callItems.length+1;
} }
@@ -549,8 +587,11 @@ public class HueMulator implements HueErrorStringSet {
} }
else else
{ {
if(!url.substring(0, 1).equalsIgnoreCase("[")) { if(!url.startsWith("[")) {
url = "[{\"item\":\"" + url +"\"}]"; if(url.startsWith("{\"item"))
url = "[" + url + "]";
else
url = "[{\"item\":\"" + url +"\"}]";
} }
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class); CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + url); 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 else
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri()); body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
// make call // 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); 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\"}}]"; responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
i = callItems.length+1; 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 // 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; HttpUriRequest request = null;
String theContent = null; String theContent = null;
try { try {
@@ -645,6 +686,11 @@ public class HueMulator implements HueErrorStringSet {
} }
log.debug("Making outbound call in doHttpRequest: " + request); log.debug("Making outbound call in doHttpRequest: " + request);
try { 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); HttpResponse response = httpClient.execute(request);
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode()); log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){ if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){

View File

@@ -112,6 +112,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
self.state.device.deviceType = "custom"; self.state.device.deviceType = "custom";
self.state.device.targetDevice = null; self.state.device.targetDevice = null;
self.state.device.offUrl = ""; self.state.device.offUrl = "";
self.state.device.headers = null;
self.state.device.httpVerb = null; self.state.device.httpVerb = null;
self.state.device.contentType = null; self.state.device.contentType = null;
self.state.device.contentBody = null; self.state.device.contentBody = null;
@@ -882,6 +883,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
targetDevice: $scope.device.targetDevice, targetDevice: $scope.device.targetDevice,
onUrl: $scope.device.onUrl, onUrl: $scope.device.onUrl,
offUrl: $scope.device.offUrl, offUrl: $scope.device.offUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb, httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType, contentType: $scope.device.contentType,
contentBody: $scope.device.contentBody, contentBody: $scope.device.contentBody,
@@ -1180,6 +1182,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
targetDevice: $scope.device.targetDevice, targetDevice: $scope.device.targetDevice,
onUrl: $scope.device.onUrl, onUrl: $scope.device.onUrl,
offUrl: $scope.device.offUrl, offUrl: $scope.device.offUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb, httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType, contentType: $scope.device.contentType,
contentBody: $scope.device.contentBody, contentBody: $scope.device.contentBody,

View File

@@ -44,6 +44,27 @@
<button class="btn btn-primary" ng-click="copyDevice()"> <button class="btn btn-primary" ng-click="copyDevice()">
Add Bridge Device</button> Add Bridge Device</button>
</div> </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="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type <label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
@@ -107,6 +128,17 @@
</div> </div>
</div> </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: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea>
</div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb <label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb

View File

@@ -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 <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 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 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)}) [{&quot;item&quot;:&quot;the payload&quot;},{&quot;item&quot;:&quot;another payload&quot;}] to execute multiple entries. Adding the value replacements (${intensity..byte},${intensity.percent},${intensity.math(X*1)})
will also work.</p> will also work.</p>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
@@ -107,7 +107,8 @@
<select name="device-type" id="device-type" ng-model="device.deviceType"> <select name="device-type" id="device-type" ng-model="device.deviceType">
<option value="">---Types if needed---</option> <!-- not selected / blank option --> <option value="">---Types if needed---</option> <!-- not selected / blank option -->
<option value="UDP">UDP</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> </select>
</div> </div>
</div> </div>
@@ -147,6 +148,17 @@
</div> </div>
</div> </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: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea>
</div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb <label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb