Updateing for API V 1.11 and Bridge V2 HUE handling.

This commit is contained in:
Admin
2016-06-02 16:51:02 -05:00
parent d7e29e2ee5
commit 39782fa339
8 changed files with 293 additions and 39 deletions

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>2.0.7-hal-d</version> <version>2.0.7-hal-e</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>

View File

@@ -11,6 +11,7 @@ public class DeviceResponse {
private String name; private String name;
private String modelid; private String modelid;
private String manufacturername; private String manufacturername;
private String luminaireuniqueid;
private String uniqueid; private String uniqueid;
private String swversion; private String swversion;
@@ -70,6 +71,14 @@ public class DeviceResponse {
this.swversion = swversion; this.swversion = swversion;
} }
public String getLuminaireuniqueid() {
return luminaireuniqueid;
}
public void setLuminaireuniqueid(String luminaireuniqueid) {
this.luminaireuniqueid = luminaireuniqueid;
}
public static DeviceResponse createResponse(DeviceDescriptor device){ public static DeviceResponse createResponse(DeviceDescriptor device){
DeviceResponse response = new DeviceResponse(); DeviceResponse response = new DeviceResponse();
response.setState(device.getDeviceState()); response.setState(device.getDeviceState());
@@ -80,6 +89,7 @@ public class DeviceResponse {
response.setType("Dimmable light"); response.setType("Dimmable light");
response.setModelid("LWB004"); response.setModelid("LWB004");
response.setSwversion("66012040"); response.setSwversion("66012040");
response.setLuminaireuniqueid(null);
return response; return response;
} }

View File

@@ -0,0 +1,18 @@
package com.bwssystems.HABridge.api.hue;
public class DeviceTypes {
private Boolean bridge;
private String[] lights;
public Boolean getBridge() {
return bridge;
}
public void setBridge(Boolean bridge) {
this.bridge = bridge;
}
public String[] getLights() {
return lights;
}
public void setLights(String[] lights) {
this.lights = lights;
}
}

View File

@@ -29,6 +29,10 @@ public class HueConfig
private String localtime; private String localtime;
private String timezone; private String timezone;
private String zigbeechannel; private String zigbeechannel;
private String modelid;
private String bridgeid;
private Boolean factorynew;
private String replacesbridgeid;
private Map<String, WhitelistEntry> whitelist; private Map<String, WhitelistEntry> whitelist;
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) { public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
@@ -37,7 +41,7 @@ public class HueConfig
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC")); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
aConfig.setMac(HueConfig.getMacAddress(ipaddress)); aConfig.setMac(HueConfig.getMacAddress(ipaddress));
aConfig.setApiversion("1.4.0"); aConfig.setApiversion("1.10.0");
aConfig.setPortalservices(false); aConfig.setPortalservices(false);
aConfig.setGateway(ipaddress); aConfig.setGateway(ipaddress);
aConfig.setSwversion("01005215"); aConfig.setSwversion("01005215");
@@ -53,6 +57,10 @@ public class HueConfig
aConfig.setLocaltime(dateFormat.format(new Date())); aConfig.setLocaltime(dateFormat.format(new Date()));
aConfig.setTimezone(TimeZone.getDefault().getID()); aConfig.setTimezone(TimeZone.getDefault().getID());
aConfig.setZigbeechannel("6"); aConfig.setZigbeechannel("6");
aConfig.setBridgeid("001788FFFE09A206");
aConfig.setModelid("BSB002");
aConfig.setFactorynew(false);
aConfig.setReplacesbridgeid(null);
Map<String, WhitelistEntry> awhitelist = new HashMap<>(); Map<String, WhitelistEntry> awhitelist = new HashMap<>();
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype)); awhitelist.put(userid, WhitelistEntry.createEntry(devicetype));
aConfig.setWhitelist(awhitelist); aConfig.setWhitelist(awhitelist);
@@ -235,4 +243,36 @@ public class HueConfig
public void setZigbeechannel(String zigbeechannel) { public void setZigbeechannel(String zigbeechannel) {
this.zigbeechannel = zigbeechannel; this.zigbeechannel = zigbeechannel;
} }
public String getModelid() {
return modelid;
}
public void setModelid(String modelid) {
this.modelid = modelid;
}
public String getBridgeid() {
return bridgeid;
}
public void setBridgeid(String bridgeid) {
this.bridgeid = bridgeid;
}
public Boolean getFactorynew() {
return factorynew;
}
public void setFactorynew(Boolean factorynew) {
this.factorynew = factorynew;
}
public String getReplacesbridgeid() {
return replacesbridgeid;
}
public void setReplacesbridgeid(String replacesbridgeid) {
this.replacesbridgeid = replacesbridgeid;
}
} }

View File

@@ -0,0 +1,136 @@
package com.bwssystems.HABridge.api.hue;
// import java.util.ArrayList;
import java.util.List;
/**
* Created by arm on 4/14/15.
*/
public class StateChangeBody {
private boolean on;
private int bri;
private int hue;
private int sat;
private String effect;
private int ct;
private String alert;
private List<Double> xy;
private int transitiontime;
private int bri_inc;
private int hue_inc;
private int sat_inc;
private List<Double> xy_inc;
private int ct_inc;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
public int getBri() {
return bri;
}
public void setBri(int bri) {
this.bri = bri;
}
public int getHue() {
return hue;
}
public void setHue(int hue) {
this.hue = hue;
}
public int getSat() {
return sat;
}
public void setSat(int sat) {
this.sat = sat;
}
public String getEffect() {
return effect;
}
public void setEffect(String effect) {
this.effect = effect;
}
public int getCt() {
return ct;
}
public void setCt(int ct) {
this.ct = ct;
}
public String getAlert() {
return alert;
}
public void setAlert(String alert) {
this.alert = alert;
}
public List<Double> getXy() {
return xy;
}
public void setXy(List<Double> xy) {
this.xy = xy;
}
public int getTransitiontime() {
return transitiontime;
}
public void setTransitiontime(int transitiontime) {
this.transitiontime = transitiontime;
}
public int getBri_inc() {
return bri_inc;
}
public void setBri_inc(int bri_inc) {
this.bri_inc = bri_inc;
}
public int getHue_inc() {
return hue_inc;
}
public void setHue_inc(int hue_inc) {
this.hue_inc = hue_inc;
}
public int getSat_inc() {
return sat_inc;
}
public void setSat_inc(int sat_inc) {
this.sat_inc = sat_inc;
}
public List<Double> getXy_inc() {
return xy_inc;
}
public void setXy_inc(List<Double> xy_inc) {
this.xy_inc = xy_inc;
}
public int getCt_inc() {
return ct_inc;
}
public void setCt_inc(int ct_inc) {
this.ct_inc = ct_inc;
}
}

View File

@@ -3,20 +3,36 @@ package com.bwssystems.HABridge.api.hue;
public class Swupdate public class Swupdate
{ {
private Integer updatestate;
private Boolean checkforupdate;
private DeviceTypes devicetypes;
private String text; private String text;
private Boolean notify; private Boolean notify;
private Integer updatestate;
private String url; private String url;
public static Swupdate createSwupdate() { public static Swupdate createSwupdate() {
Swupdate aSwupdate = new Swupdate(); Swupdate aSwupdate = new Swupdate();
aSwupdate.setUpdatestate(0);
aSwupdate.setCheckforupdate(false);
aSwupdate.setDevicetypes(new DeviceTypes());
aSwupdate.setNotify(false); aSwupdate.setNotify(false);
aSwupdate.setText(""); aSwupdate.setText("");
aSwupdate.setUpdatestate(0);
aSwupdate.setUrl(""); aSwupdate.setUrl("");
return aSwupdate; return aSwupdate;
} }
public Boolean getCheckforupdate() {
return checkforupdate;
}
public void setCheckforupdate(Boolean checkforupdate) {
this.checkforupdate = checkforupdate;
}
public DeviceTypes getDevicetypes() {
return devicetypes;
}
public void setDevicetypes(DeviceTypes devicetypes) {
this.devicetypes = devicetypes;
}
public String getText() { public String getText() {
return text; return text;
} }

View File

@@ -7,6 +7,7 @@ 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;
import com.bwssystems.HABridge.api.hue.HueApiResponse; import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.bwssystems.HABridge.api.hue.StateChangeBody;
import com.bwssystems.HABridge.dao.*; import com.bwssystems.HABridge.dao.*;
import com.bwssystems.NestBridge.NestInstruction; import com.bwssystems.NestBridge.NestInstruction;
import com.bwssystems.NestBridge.NestHome; import com.bwssystems.NestBridge.NestHome;
@@ -364,32 +365,41 @@ public class HueMulator implements HueErrorStringSet {
String responseString = null; String responseString = null;
String url = null; String url = null;
NameValue[] theHeaders = null; NameValue[] theHeaders = null;
StateChangeBody theStateChanges = null;
DeviceState state = null; DeviceState state = null;
boolean stateHasBri = false; boolean stateHasBri = false;
boolean stateHasBriInc = false;
boolean stateHasOn = false; boolean stateHasOn = false;
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"));
response.type("application/json; charset=utf-8"); response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK); response.status(HttpStatus.SC_OK);
try { theStateChanges = new Gson().fromJson(request.body(), StateChangeBody.class);
state = mapper.readValue(request.body(), DeviceState.class); if (theStateChanges == null) {
if(request.body().contains("\"bri\"")) log.warn("Could not parse state change body. Light state not changed.");
stateHasBri = true; responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId
if(request.body().contains("\"on\"")) + "\",\"description\": \"Could not parse state change body.\"}}]";
stateHasOn = true;
} catch (IOException e) {
log.warn("Object mapper barfed on input of body.", e);
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object mapper barfed on input of body.\"}}]";
return responseString; return responseString;
} }
if (request.body().contains("\"bri\""))
stateHasBri = true;
if (request.body().contains("\"bri_inc\""))
stateHasBriInc = true;
if (request.body().contains("\"on\""))
stateHasOn = true;
DeviceDescriptor device = repository.findOne(lightId); DeviceDescriptor device = repository.findOne(lightId);
if (device == null) { if (device == null) {
log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body()); log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]"; responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
return responseString; return responseString;
} }
state = device.getDeviceState();
if(state == null)
state = DeviceState.createDeviceState();
state.fillIn(); state.fillIn();
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class); theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
@@ -433,17 +443,20 @@ public class HueMulator implements HueErrorStringSet {
if(stateHasBri) if(stateHasBri)
{ {
if(state.getBri() > 0 && !state.isOn()) if(theStateChanges.getBri() > 0 && !theStateChanges.isOn())
state.setOn(true); state.setOn(true);
url = device.getDimUrl(); url = device.getDimUrl();
if(url == null || url.length() == 0) if(url == null || url.length() == 0)
url = device.getOnUrl(); url = device.getOnUrl();
}
else if(stateHasBriInc) {
} }
else else
{ {
if (state.isOn()) { if (theStateChanges.isOn()) {
url = device.getOnUrl(); url = device.getOnUrl();
if(state.getBri() <= 0) if(state.getBri() <= 0)
state.setBri(255); state.setBri(255);
@@ -536,9 +549,9 @@ public class HueMulator implements HueErrorStringSet {
if(thermoSetting.getControl().equalsIgnoreCase("temp")) { if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
if(request.body().contains("bri")) { if(request.body().contains("bri")) {
if(bridgeSettings.isFarenheit()) if(bridgeSettings.isFarenheit())
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false)) - 32.0)/1.8)); thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), theStateChanges.getBri(), false)) - 32.0)/1.8));
else else
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false)))); thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), theStateChanges.getBri(), false))));
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C"); log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp())); theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
} }
@@ -575,7 +588,7 @@ public class HueMulator implements HueErrorStringSet {
intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3); intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
else else
intermediate = callItems[i].getItem(); intermediate = callItems[i].getItem();
String anError = doExecRequest(intermediate, state, lightId); String anError = doExecRequest(intermediate, theStateChanges, lightId);
if(anError != null) { if(anError != null) {
responseString = anError; responseString = anError;
i = callItems.length+1; i = callItems.length+1;
@@ -611,11 +624,11 @@ public class HueMulator implements HueErrorStringSet {
hostAddr = hostPortion; hostAddr = hostPortion;
InetAddress IPAddress = InetAddress.getByName(hostAddr);; InetAddress IPAddress = InetAddress.getByName(hostAddr);;
if(theUrlBody.startsWith("0x")) { if(theUrlBody.startsWith("0x")) {
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), true); theUrlBody = replaceIntensityValue(theUrlBody, theStateChanges.getBri(), true);
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2)); sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} }
else { else {
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), false); theUrlBody = replaceIntensityValue(theUrlBody, theStateChanges.getBri(), false);
sendData = theUrlBody.getBytes(); sendData = theUrlBody.getBytes();
} }
if(callItems[i].getItem().contains("udp://")) { if(callItems[i].getItem().contains("udp://")) {
@@ -637,7 +650,7 @@ public class HueMulator implements HueErrorStringSet {
} }
else if(callItems[i].getItem().contains("exec://")) { else if(callItems[i].getItem().contains("exec://")) {
String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3); String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
String anError = doExecRequest(intermediate, state, lightId); String anError = doExecRequest(intermediate, theStateChanges, lightId);
if(anError != null) { if(anError != null) {
responseString = anError; responseString = anError;
i = callItems.length+1; i = callItems.length+1;
@@ -646,12 +659,12 @@ public class HueMulator implements HueErrorStringSet {
else { else {
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + callItems[i].getItem()); log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + callItems[i].getItem());
String anUrl = replaceIntensityValue(callItems[i].getItem(), state.getBri(), false); String anUrl = replaceIntensityValue(callItems[i].getItem(), theStateChanges.getBri(), false);
String body; String body;
if (state.isOn()) if (theStateChanges.isOn())
body = replaceIntensityValue(device.getContentBody(), state.getBri(), false); body = replaceIntensityValue(device.getContentBody(), theStateChanges.getBri(), false);
else else
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri(), false); body = replaceIntensityValue(device.getContentBodyOff(), theStateChanges.getBri(), false);
// make call // make call
if (doHttpRequest(anUrl, device.getHttpVerb(), device.getContentType(), body, theHeaders) == 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);
@@ -668,6 +681,7 @@ public class HueMulator implements HueErrorStringSet {
} }
if(!responseString.contains("[{\"error\":")) { if(!responseString.contains("[{\"error\":")) {
// FIXME update state with theStateChanges
device.setDeviceState(state); device.setDeviceState(state);
} }
return responseString; return responseString;
@@ -791,7 +805,7 @@ public class HueMulator implements HueErrorStringSet {
return theContent; return theContent;
} }
private String doExecRequest(String anItem, DeviceState state, String lightId) { private String doExecRequest(String anItem, StateChangeBody state, String lightId) {
log.debug("Executing request: " + anItem); log.debug("Executing request: " + anItem);
String responseString = null; String responseString = null;
try { try {
@@ -830,6 +844,14 @@ public class HueMulator implements HueErrorStringSet {
justState = true; justState = true;
} }
if(body.contains("bri_inc"))
{
if(justState)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri_inc\":" + state.getBri() + "}}";
justState = true;
}
if(body.contains("ct")) if(body.contains("ct"))
{ {
if(justState) if(justState)

View File

@@ -22,6 +22,22 @@ public class UpnpListener {
private boolean strict; private boolean strict;
private boolean traceupnp; private boolean traceupnp;
private BridgeControlDescriptor bridgeControl; private BridgeControlDescriptor bridgeControl;
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
private String discoveryTemplateNew = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"EXT:\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0\r\n" +
"ST: upnp:rootdevice\r\n" +
"hue-bridgeid: 001788FFFE09A206\r\n" +
"USN: uuid:88f6698f-2c83-4393-bd03-cd54a9f8595:upnp:rootdevice\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) { public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
super(); super();
@@ -189,16 +205,12 @@ public class UpnpListener {
return false; return false;
} }
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException { protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null; String discoveryResponse = null;
if(false)
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort); discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
else
discoveryResponse = String.format(discoveryTemplateNew, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort);
if(traceupnp) if(traceupnp)
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort); log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
else else