mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Fixed handling of dim and brigthen requests as they were not setting the
state appropriately for other systems. Fixed handling of data return from an http call if the entity was empty. Fixes #102 Fixes #107
This commit is contained in:
16
README.md
16
README.md
@@ -21,7 +21,7 @@ Then locate the jar and start the server with:
|
||||
ATTENTION: This requires JDK 1.8 to run
|
||||
|
||||
```
|
||||
java -jar ha-bridge-W.X.Y.jar
|
||||
java -jar ha-bridge-2.0.5.jar
|
||||
```
|
||||
### Automation on Linux systems
|
||||
To have this conigured and running automatically ther eare a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
|
||||
@@ -35,7 +35,7 @@ After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.0.4.jar
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.0.5.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -109,7 +109,7 @@ This screen displays the last 512 or number of rows defined in the config screen
|
||||
|
||||
The bottom part of the Logs Screen has configuration to change the logging levels as it is running. The ROOT is the basic setting and will turn on only top level logging. To set logging at a lower level, select the `Show All Loggers` checkbox and then you can set the explicit level on each of the processes components. The most helpful logger would be setting DEBUG for com.bwssystems.HABridge.hue.HueMulator component. Changing this and then selecting the `Update Log Levels` button applies the new log settings.
|
||||
### Bridge Device Additions
|
||||
You must configure devices before you will have any thing for the Echo or other contoller that is connected to the ha-bridge to receive.
|
||||
You must configure devices before you will have any thing for the Echo or other controller that is connected to the ha-bridge to receive.
|
||||
#### Helpers
|
||||
The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest and Hue to create devices that the bridge will present.
|
||||
|
||||
@@ -217,13 +217,15 @@ OFF Commands |
|
||||
DIM Commands |
|
||||
| Alexa, brighten `<Device Name>` to `<Position>`
|
||||
| Alexa, dim `<Device Name> to <Position>`
|
||||
| Alexa, brighten `<Device Name>`
|
||||
| Alexa, dim `<Device Name>`
|
||||
| Alexa, raise `<Device Name>` to `<Position>`
|
||||
| Alexa, lower `<Device Name>` to `<Position>`
|
||||
| Alexa, set `<Device Name>` to `<Position>`
|
||||
| Alexa, turn up `<Device Name>` to `<Position>`
|
||||
| Alexa, turn down `<Device Name>` to `<Position>`
|
||||
|
||||
To see what Alexa thinks you said, you can check in the home page for your alexa.
|
||||
To see what Alexa thinks you said, you can check in the home page for your Alexa.
|
||||
|
||||
To view or remove devices that Alexa knows about, you can use the mobile app `Menu / Settings / Connected Home` or go to http://echo.amazon.com/#cards.
|
||||
## Configuration REST API Usage
|
||||
@@ -264,7 +266,7 @@ contentBodyOff | string | This is the content body that you would like to send w
|
||||
}
|
||||
```
|
||||
#### Dimming Control Example
|
||||
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass trhough of the value.
|
||||
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value.
|
||||
e.g.
|
||||
```
|
||||
{
|
||||
@@ -872,7 +874,7 @@ rules | object | A collection of all rules and their attributes. This is not giv
|
||||
## UPNP Emulation of HUE
|
||||
This section will discuss the UPNP implementation of this bridge based as much as can be for the HUE.
|
||||
### UPNP listening
|
||||
The HA Bridge default UPNP listner is started on port 1900 on the upnp multicast address of 239.255.255.250. All ethernet interfaces that are active are bound to and the repsonse port is set to the one given on the command line above or the default of 50000.
|
||||
The HA Bridge default UPNP listener is started on port 1900 on the upnp multicast address of 239.255.255.250. All ethernet interfaces that are active are bound to and the response port is set to the one given on the command line above or the default of 50000.
|
||||
|
||||
The listener will respond to the following body packet that contain the following minimal information:
|
||||
|
||||
@@ -898,7 +900,7 @@ 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
|
||||
```
|
||||
### UPNP description service
|
||||
The bridge provides the description service which is used by the calling app to interogate access details after it has decided the upnp multicast repsonse is the correct device.
|
||||
The bridge provides the description service which is used by the calling app to interogate access details after it has decided the upnp multicast response is the correct device.
|
||||
#### Get Description
|
||||
```
|
||||
GET http://host:8080/description.xml
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>2.0.4</version>
|
||||
<version>2.0.5</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -317,12 +317,15 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String lightId = request.params(":id");
|
||||
String responseString = null;
|
||||
DeviceState state = null;
|
||||
boolean stateHasOn = false;
|
||||
log.debug("Update state requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
try {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
if(request.body().contains("\"on\""))
|
||||
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.\"}}]";
|
||||
@@ -335,7 +338,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
return responseString;
|
||||
}
|
||||
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), stateHasOn, lightId);
|
||||
device.setDeviceState(state);
|
||||
|
||||
return responseString;
|
||||
@@ -362,6 +365,8 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String url = null;
|
||||
NameValue[] theHeaders = null;
|
||||
DeviceState state = null;
|
||||
boolean stateHasBri = false;
|
||||
boolean stateHasOn = false;
|
||||
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
@@ -369,6 +374,10 @@ public class HueMulator implements HueErrorStringSet {
|
||||
|
||||
try {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
if(request.body().contains("\"bri\""))
|
||||
stateHasBri = true;
|
||||
if(request.body().contains("\"on\""))
|
||||
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.\"}}]";
|
||||
@@ -384,7 +393,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
state.fillIn();
|
||||
|
||||
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), stateHasOn, lightId);
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||
{
|
||||
@@ -422,8 +431,11 @@ public class HueMulator implements HueErrorStringSet {
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if(request.body().contains("bri"))
|
||||
if(stateHasBri)
|
||||
{
|
||||
if(state.getBri() > 0 && !state.isOn())
|
||||
state.setOn(true);
|
||||
|
||||
url = device.getDimUrl();
|
||||
|
||||
if(url == null || url.length() == 0)
|
||||
@@ -433,8 +445,9 @@ public class HueMulator implements HueErrorStringSet {
|
||||
{
|
||||
if (state.isOn()) {
|
||||
url = device.getOnUrl();
|
||||
state.setBri(255);
|
||||
} else if (request.body().contains("false")) {
|
||||
if(state.getBri() <= 0)
|
||||
state.setBri(255);
|
||||
} else {
|
||||
url = device.getOffUrl();
|
||||
state.setBri(0);
|
||||
}
|
||||
@@ -759,9 +772,9 @@ public class HueMulator implements HueErrorStringSet {
|
||||
} catch(Exception e) {
|
||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "+ e.getMessage(), e);
|
||||
}
|
||||
if(theContent == null)
|
||||
theContent = "";
|
||||
}
|
||||
if(theContent == null)
|
||||
theContent = "";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||
@@ -769,73 +782,75 @@ public class HueMulator implements HueErrorStringSet {
|
||||
return theContent;
|
||||
}
|
||||
|
||||
private String formatSuccessHueResponse(DeviceState state, String body, String lightId) {
|
||||
private String formatSuccessHueResponse(DeviceState state, String body, boolean stateHasOn, String lightId) {
|
||||
|
||||
String responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
boolean justState = true;
|
||||
String responseString = "[";
|
||||
boolean justState = false;
|
||||
if(stateHasOn)
|
||||
{
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
if (state.isOn()) {
|
||||
responseString = responseString + "true}}";
|
||||
if(state.getBri() <= 0)
|
||||
state.setBri(255);
|
||||
} else {
|
||||
responseString = responseString + "false}}";
|
||||
state.setBri(0);
|
||||
}
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("bri"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}";
|
||||
justState = false;
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("ct"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/ct\":" + state.getCt() + "}}";
|
||||
justState = false;
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct\":" + state.getCt() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("xy"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/xy\":" + state.getXy() + "}}";
|
||||
justState = false;
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/xy\":" + state.getXy() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("hue"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/hue\":" + state.getHue() + "}}";
|
||||
justState = false;
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue\":" + state.getHue() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("sat"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/sat\":" + state.getSat() + "}}";
|
||||
justState = false;
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat\":" + state.getSat() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
if(body.contains("colormode"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/colormode\":" + state.getColormode() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(justState)
|
||||
{
|
||||
if (state.isOn()) {
|
||||
responseString = responseString + "true}}";
|
||||
state.setBri(255);
|
||||
} else if (body.contains("false")) {
|
||||
responseString = responseString + "false}}";
|
||||
state.setBri(0);
|
||||
}
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/colormode\":" + state.getColormode() + "}}";
|
||||
justState = true;
|
||||
}
|
||||
|
||||
responseString = responseString + "]";
|
||||
|
||||
return responseString;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user