mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 00:20:26 +00:00
Finished testing and updating HUE passthru handling
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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,22 +354,37 @@ public class HueMulator {
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||
{
|
||||
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) {
|
||||
hueUser = userId;
|
||||
if((hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), errorString)) == null) {
|
||||
return errorString;
|
||||
}
|
||||
myHueHome.setTheHUERegisteredUser(hueUser);
|
||||
}
|
||||
|
||||
// make call
|
||||
if (!doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+hueUser+"/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());
|
||||
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 url 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\"}}]";
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
device.setDeviceState(state);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"No HUE configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.bwssystems.hue;
|
||||
|
||||
public interface HueErrorStringSet {
|
||||
public void setErrorString(String anError);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user