Finished testing and updating HUE passthru handling

This commit is contained in:
Admin
2016-04-22 10:58:54 -05:00
parent 05418fdda1
commit b73a4cd666
7 changed files with 103 additions and 38 deletions

View File

@@ -69,7 +69,7 @@ public class HABridge {
// setup the class to handle the resource setup rest api
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome);
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome);
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome);
theHueMulator.setupServer();
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());

View File

@@ -13,6 +13,8 @@ import com.bwssystems.harmony.HarmonyHandler;
import com.bwssystems.harmony.HarmonyHome;
import com.bwssystems.harmony.RunActivity;
import com.bwssystems.hue.HueDeviceIdentifier;
import com.bwssystems.hue.HueErrorStringSet;
import com.bwssystems.hue.HueHome;
import com.bwssystems.hue.HueUtil;
import com.bwssystems.nest.controller.Nest;
import com.bwssystems.util.JsonTransformer;
@@ -47,6 +49,7 @@ import java.math.BigDecimal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -57,7 +60,7 @@ import javax.xml.bind.DatatypeConverter;
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
*/
public class HueMulator {
public class HueMulator implements HueErrorStringSet {
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}";
@@ -69,14 +72,16 @@ public class HueMulator {
private DeviceRepository repository;
private HarmonyHome myHarmonyHome;
private Nest theNest;
private HueHome myHueHome;
private HttpClient httpClient;
private ObjectMapper mapper;
private BridgeSettingsDescriptor bridgeSettings;
private byte[] sendData;
private String hueUser;
private String errorString;
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome){
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome){
httpClient = HttpClients.createDefault();
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -89,13 +94,17 @@ public class HueMulator {
this.theNest = aNestHome.getTheNest();
else
this.theNest = null;
if(theBridgeSettings.isValidHue())
this.myHueHome = aHueHome;
else
this.myHueHome = null;
bridgeSettings = theBridgeSettings;
hueUser = null;
errorString = null;
}
// This function sets up the sparkjava rest calls for the hue api
public void setupServer() {
String errorString = null;
log.info("Hue emulator service started....");
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
@@ -345,23 +354,38 @@ public class HueMulator {
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
{
url = device.getOnUrl();
HueDeviceIdentifier deviceId = new Gson().fromJson(url, HueDeviceIdentifier.class);
if(hueUser == null) {
hueUser = userId;
if((hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), errorString)) == null) {
return errorString;
}
if(myHueHome != null) {
url = device.getOnUrl();
HueDeviceIdentifier deviceId = new Gson().fromJson(url, HueDeviceIdentifier.class);
if(myHueHome.getTheHUERegisteredUser() == null) {
hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), myHueHome.getTheHUERegisteredUser(), this);
if(hueUser == null) {
return errorString;
}
myHueHome.setTheHUERegisteredUser(hueUser);
}
// make call
responseString = doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+myHueHome.getTheHUERegisteredUser()+"/lights/"+deviceId.getDeviceId()+"/state", HttpPut.METHOD_NAME, device.getContentType(), request.body());
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\"}}]";
}
else if(responseString.contains("[{\"error\":") && responseString.contains("unauthorized user")) {
myHueHome.setTheHUERegisteredUser(null);
hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), myHueHome.getTheHUERegisteredUser(), this);
if(hueUser == null) {
return errorString;
}
myHueHome.setTheHUERegisteredUser(hueUser);
}
else if(!responseString.contains("[{\"error\":"))
device.setDeviceState(state);
}
// make call
if (!doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+hueUser+"/lights/"+deviceId.getDeviceId()+"/state", HttpPut.METHOD_NAME, device.getContentType(), request.body())) {
log.warn("Error on calling url to change device state: " + url);
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
else
device.setDeviceState(state);
return responseString;
else
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"No HUE configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
return responseString;
}
if(request.body().contains("bri"))
@@ -520,7 +544,7 @@ public class HueMulator {
else
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
// make call
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
if (doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body) == null) {
log.warn("Error on calling url to change device state: " + url);
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
@@ -572,8 +596,9 @@ public class HueMulator {
// This function executes the url from the device repository against the vera
protected boolean doHttpRequest(String url, String httpVerb, String contentType, String body) {
protected String doHttpRequest(String url, String httpVerb, String contentType, String body) {
HttpUriRequest request = null;
String theContent = null;
try {
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
request = new HttpGet(url);
@@ -592,20 +617,20 @@ public class HueMulator {
}
} catch(IllegalArgumentException e) {
log.warn("Error calling out to HA gateway: IllegalArgumentException in log", e);
return false;
return null;
}
log.debug("Making outbound call in doHttpRequest: " + request);
try {
HttpResponse response = httpClient.execute(request);
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
return true;
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
}
} catch (IOException e) {
log.warn("Error calling out to HA gateway: IOException in log", e);
}
return false;
return theContent;
}
private String formatSuccessHueResponse(DeviceState state, String body, String lightId) {
@@ -676,4 +701,9 @@ public class HueMulator {
return responseString;
}
@Override
public void setErrorString(String anError) {
errorString = anError;
}
}

View File

@@ -5,6 +5,7 @@ import com.bwssystems.HABridge.api.hue.DeviceResponse;
public class HueDevice {
private DeviceResponse device;
private String huedeviceid;
private String hueaddress;
private String huename;
public DeviceResponse getDevice() {
@@ -13,6 +14,12 @@ public class HueDevice {
public void setDevice(DeviceResponse adevice) {
this.device = adevice;
}
public String getHuedeviceid() {
return huedeviceid;
}
public void setHuedeviceid(String huedeviceid) {
this.huedeviceid = huedeviceid;
}
public String getHueaddress() {
return hueaddress;
}

View File

@@ -0,0 +1,5 @@
package com.bwssystems.hue;
public interface HueErrorStringSet {
public void setErrorString(String anError);
}

View File

@@ -17,6 +17,7 @@ import com.bwssystems.HABridge.api.hue.HueApiResponse;
public class HueHome {
private static final Logger log = LoggerFactory.getLogger(HueHome.class);
private Map<String, HueInfo> hues;
private String theHUERegisteredUser;
public HueHome(BridgeSettingsDescriptor bridgeSettings) {
hues = new HashMap<String, HueInfo>();
@@ -25,8 +26,9 @@ public class HueHome {
Iterator<NamedIP> theList = bridgeSettings.getHueaddress().getDevices().iterator();
while(theList.hasNext()) {
NamedIP aHue = theList.next();
hues.put(aHue.getName(), new HueInfo(aHue));
hues.put(aHue.getName(), new HueInfo(aHue, this));
}
theHUERegisteredUser = null;
}
public List<HueDevice> getDevices() {
@@ -41,8 +43,10 @@ public class HueHome {
if(theDevices != null) {
Iterator<String> deviceKeys = theDevices.keySet().iterator();
while(deviceKeys.hasNext()) {
String theDeviceKey = deviceKeys.next();
HueDevice aNewHueDevice = new HueDevice();
aNewHueDevice.setDevice(theDevices.get(deviceKeys.next()));
aNewHueDevice.setDevice(theDevices.get(theDeviceKey));
aNewHueDevice.setHuedeviceid(theDeviceKey);
aNewHueDevice.setHueaddress(hues.get(key).getHueAddress().getIp());
aNewHueDevice.setHuename(key);
deviceList.add(aNewHueDevice);
@@ -58,4 +62,12 @@ public class HueHome {
}
return deviceList;
}
public String getTheHUERegisteredUser() {
return theHUERegisteredUser;
}
public void setTheHUERegisteredUser(String theHUERegisteredUser) {
this.theHUERegisteredUser = theHUERegisteredUser;
}
}

View File

@@ -15,22 +15,24 @@ import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.google.gson.Gson;
public class HueInfo {
public class HueInfo implements HueErrorStringSet {
private static final Logger log = LoggerFactory.getLogger(HueInfo.class);
private HttpClient httpClient;
private NamedIP hueAddress;
private String theUser;
private HueHome theHueHome;
private String errorString = null;
public HueInfo(NamedIP addressName) {
public HueInfo(NamedIP addressName, HueHome aHueHome) {
super();
httpClient = HttpClients.createDefault();
hueAddress = addressName;
theUser = "habridge";
theHueHome = aHueHome;
}
public HueApiResponse getHueApiResponse() {
HueApiResponse theHueApiResponse = null;
String errorString = null;
String theUrl = "http://" + hueAddress.getIp() + HueUtil.HUE_REQUEST + "/" + theUser;
String theData;
@@ -48,10 +50,13 @@ public class HueInfo {
log.debug("GET HueApiResponse - data: " + theData);
if(theData.contains("[{\"error\":")) {
if(theData.contains("unauthorized user")) {
if((theUser = HueUtil.registerWithHue(httpClient, hueAddress.getIp(), hueAddress.getName(), errorString)) == null) {
theUser = HueUtil.registerWithHue(httpClient, hueAddress.getIp(), hueAddress.getName(), theHueHome.getTheHUERegisteredUser(), this);
if(theUser == null) {
log.warn("Register to Hue for " + hueAddress.getName() + " returned error: " + errorString);
return null;
}
else
theHueHome.setTheHUERegisteredUser(theUser);
retryCount++;
}
else {
@@ -98,4 +103,9 @@ public class HueInfo {
public void setHueAddress(NamedIP hueAddress) {
this.hueAddress = hueAddress;
}
@Override
public void setErrorString(String anError) {
errorString = anError;
}
}

View File

@@ -19,12 +19,13 @@ public class HueUtil {
private static final Logger log = LoggerFactory.getLogger(HueUtil.class);
public static final String HUE_REQUEST = "/api";
public static final String registerWithHue(HttpClient anHttpClient, String ipAddress, String aName, String errorString) {
UserCreateRequest theLogin;
String theUser = null;
theLogin = new UserCreateRequest();
public static final String registerWithHue(HttpClient anHttpClient, String ipAddress, String aName, String theUser, HueErrorStringSet errorStringSet) {
UserCreateRequest theLogin = new UserCreateRequest();
theLogin.setDevicetype("HA Bridge");
theLogin.setUsername("habridge");
if(theUser == null)
theLogin.setUsername("habridge");
else
theLogin.setUsername(theUser);
HttpPost postRequest = new HttpPost("http://" + ipAddress + HUE_REQUEST);
ContentType parsedContentType = ContentType.parse("application/json");
StringEntity requestBody = new StringEntity(new Gson().toJson(theLogin), parsedContentType);
@@ -42,7 +43,7 @@ public class HueUtil {
}
else
log.warn("registerWithHue returned an unexpected error: " + theBody);
errorString = theBody;
errorStringSet.setErrorString(theBody);
}
else {
SuccessUserResponse[] theResponses = new Gson().fromJson(theBody, SuccessUserResponse[].class); //read content for data, SuccessUserResponse[].class);