diff --git a/pom.xml b/pom.xml
index ba1f985..1cb1b1d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.armzilla.ha
amazon-echo-bridge
- 0.1.2
+ 0.1.3
jar
Amazon Echo Bridge
@@ -48,6 +48,11 @@
httpclient
4.3.6
+
+
+
+
+
diff --git a/src/main/java/com/armzilla/ha/api/hue/DeviceState.java b/src/main/java/com/armzilla/ha/api/hue/DeviceState.java
index 52af575..38f90e2 100644
--- a/src/main/java/com/armzilla/ha/api/hue/DeviceState.java
+++ b/src/main/java/com/armzilla/ha/api/hue/DeviceState.java
@@ -7,7 +7,7 @@
*/
public class DeviceState {
private boolean on;
- private int bri;
+ private int bri = 255;
private int hue;
private int sat;
private String effect;
@@ -96,4 +96,12 @@ public List getXy() {
public void setXy(List xy) {
this.xy = xy;
}
+
+ @Override
+ public String toString() {
+ return "DeviceState{" +
+ "on=" + on +
+ ", bri=" + bri +
+ '}';
+ }
}
diff --git a/src/main/java/com/armzilla/ha/hue/HueMulator.java b/src/main/java/com/armzilla/ha/hue/HueMulator.java
index 3fa207d..e407ff7 100644
--- a/src/main/java/com/armzilla/ha/hue/HueMulator.java
+++ b/src/main/java/com/armzilla/ha/hue/HueMulator.java
@@ -1,8 +1,11 @@
package com.armzilla.ha.hue;
import com.armzilla.ha.api.hue.DeviceResponse;
+import com.armzilla.ha.api.hue.DeviceState;
import com.armzilla.ha.api.hue.HueApiResponse;
import com.armzilla.ha.dao.*;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
@@ -25,7 +28,6 @@
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -35,12 +37,18 @@
@RequestMapping("/api")
public class HueMulator {
private static final Logger log = Logger.getLogger(HueMulator.class);
- protected static RestTemplate restTemplate = new RestTemplate();
+ private static final String INTENSITY_PERCENT = "${intensity.percent}";
+ private static final String INTENSITY_BYTE = "${intensity.byte}";
@Autowired
private DeviceRepository repository;
private HttpClient httpClient;
+ private ObjectMapper mapper;
+
+
public HueMulator(){
httpClient = HttpClients.createDefault(); //patched for now, moving away from HueMulator doing work
+ mapper = new ObjectMapper(); //work around Echo incorrect content type and breaking mapping. Map manually
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@@ -112,26 +120,53 @@ public ResponseEntity getLigth(@PathVariable(value = "lightId")
}
@RequestMapping(value = "/{userId}/lights/{lightId}/state", method = RequestMethod.PUT)
- public ResponseEntity stateChange(@PathVariable(value = "lightId") String lightId, @PathVariable(value = "userId") String userId, HttpServletRequest request, @RequestBody String body) {
+ public ResponseEntity stateChange(@PathVariable(value = "lightId") String lightId, @PathVariable(value = "userId") String userId, HttpServletRequest request, @RequestBody String requestString) {
+ /**
+ * strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
+ * it sends a json object
+ */
log.info("hue state change requested: " + userId + " from " + request.getRemoteAddr());
- log.info("hue stage change body: " + body);
- String setting;
- if (body.contains("true")) {
- setting = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]";
- } else {
- setting = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
+ log.info("hue stage change body: " + requestString );
+
+ DeviceState state = null;
+ try {
+ state = mapper.readValue(requestString, DeviceState.class);
+ } catch (IOException e) {
+ log.info("object mapper barfed on input", e);
+ return new ResponseEntity<>(null, null, HttpStatus.BAD_REQUEST);
}
+
DeviceDescriptor device = repository.findOne(lightId);
if (device == null) {
return new ResponseEntity<>(null, null, HttpStatus.NOT_FOUND);
}
+ String responseString;
String url;
- if (body.contains("true")) {
+ if (state.isOn()) {
+ responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]";
url = device.getOnUrl();
} else {
+ responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
url = device.getOffUrl();
}
+
+ /* light weight templating here, was going to use free marker but it was a bit too
+ * heavy for what we were trying to do.
+ *
+ * currently provides only two variables:
+ * intensity.byte : 0-255 brightness. this is raw from the echo
+ * intensity.percent : 0-100, adjusted for the vera
+ */
+ if(url.contains(INTENSITY_BYTE)){
+ String intensityByte = String.valueOf(state.getBri());
+ url = url.replace(INTENSITY_BYTE, intensityByte);
+ }else if(url.contains(INTENSITY_PERCENT)){
+ int percentBrightness = (int) Math.round(state.getBri()/255.0*100);
+ String intensityPercent = String.valueOf(percentBrightness);
+ url = url.replace(INTENSITY_PERCENT, intensityPercent);
+ }
+
//make call
if(!doHttpGETRequest(url)){
return new ResponseEntity<>(null, null, HttpStatus.SERVICE_UNAVAILABLE);
@@ -151,15 +186,17 @@ public ResponseEntity stateChange(@PathVariable(value = "lightId") Strin
headerMap.set("Content-Type", "application/json");
- ResponseEntity entity = new ResponseEntity<>(setting, headerMap, HttpStatus.OK);
+ ResponseEntity entity = new ResponseEntity<>(responseString, headerMap, HttpStatus.OK);
return entity;
}
- protected boolean doHttpGETRequest(String url){
+ protected boolean doHttpGETRequest(String url) {
+ log.info("calling GET on URL: " + url);
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(httpGet);
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
+ log.info("GET on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
return true;
}