mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Updtated bridge to be able to emulate the armzilla upnp responses.
Adding optional field edits - in progress.
This commit is contained in:
73
README.md
73
README.md
@@ -1,42 +1,40 @@
|
||||
# ha-bridge
|
||||
Emulates philips hue api to other home automation gateways. The Amazon echo now supports wemo and philips hue.
|
||||
Build
|
||||
-----
|
||||
|
||||
To customize and build it yourself, build a new jar with maven:
|
||||
Emulates philips hue api to other home automation gateways. The Amazon echo now supports wemo and philips hue.
|
||||
## Build
|
||||
To customize and build it yourself, build a new jar with maven:
|
||||
```
|
||||
mvn install
|
||||
```
|
||||
|
||||
Otherwise go to http://www.bwssystems.com/apps.html to download the latest jar file.
|
||||
|
||||
Run
|
||||
----
|
||||
|
||||
Then locate the jar and start the server with:
|
||||
Otherwise go to http://www.bwssystems.com/apps.html to download the latest jar file.
|
||||
## Run
|
||||
Then locate the jar and start the server with:
|
||||
```
|
||||
java -jar -Dvera.address=192.168.X.Y ha-bridge-0.X.Y.jar
|
||||
```
|
||||
``'
|
||||
## Available Arguments
|
||||
### -Dvera.address=<ip address>
|
||||
The argument for the vera address should be given as it the system does not have a way to find the address. Supply -Dvera.address=X.Y.Z.A on the command line to provide it.
|
||||
|
||||
### -Dupnp.config.address=<ip address>
|
||||
The server defaults to the first available address on the host. Replace the -Dupnp.config.address=<ip address> value with the server ipv4 address you would like to use.
|
||||
|
||||
### -Dserver.port=<port>
|
||||
The server defaults to running on port 8080. If you're already running a server (like openHAB) on 8080, -Dserver.port=<port> on the command line.
|
||||
|
||||
### -Dupnp.devices.db=<filepath>
|
||||
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify -Dupnp.devices.db=<directory>/<filename> or <filename> if it is the same directory.
|
||||
|
||||
The default upnp response port will be 50000 otherwise it can be set with -Dupnp.response.port=<port>.
|
||||
|
||||
Upnp has been very closed on this platform to try and respond as a hue and there is now a setting to control if it is more open or strict, Add -Dupnp.strict=<true|false> to your command line to have the emulator respond to what it thinks is an echo to a hue or any other device. The default is upnp.strict=true.
|
||||
|
||||
Then configure by going to the url for the host you are running on or localhost:
|
||||
### -Dupnp.resonse.port=<port>
|
||||
The upnp response port that will be used. The default is 50000.
|
||||
### -Dupnp.strict=<true|false>
|
||||
Upnp has been very closed on this platform to try and respond as a hue and there is now a setting to control if it is more open or strict, Add -Dupnp.strict=<true|false> to your command line to have the emulator respond to what it thinks is an echo to a hue or any other device. The default is upnp.strict=true.
|
||||
### -Dtrace.upnp=<true|false>
|
||||
Turn on tracing for upnp discovery messages. The default is false.
|
||||
### -Dvtwo.compatibility=<true|false>
|
||||
Turns on compatibility for upnp detection and response as it was in the original version of amazon-echo-ha-bridge. The default is true.
|
||||
## Web Config
|
||||
Configure by going to the url for the host you are running on or localhost with port you have assigned:
|
||||
```
|
||||
http://192.168.1.240:8080
|
||||
http://<ip address>:<port>
|
||||
```
|
||||
|
||||
Command line configure
|
||||
----
|
||||
Register a device via REST by by using a tool and the url, for example:
|
||||
## Command line configure
|
||||
Register a device via REST by by using a tool and the url, for example:
|
||||
```
|
||||
POST http://host:8080/api/devices
|
||||
{
|
||||
@@ -46,9 +44,8 @@ POST http://host:8080/api/devices
|
||||
"offUrl" : "http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41"
|
||||
}
|
||||
```
|
||||
Dimming
|
||||
----
|
||||
Dimming is also supported by using the expessions ${intensity.percent} or ${intensity.byte} for 0-100 and 0-255 respectively.
|
||||
## Dimming
|
||||
Dimming is also supported by using the expessions ${intensity.percent} or ${intensity.byte} for 0-100 and 0-255 respectively.
|
||||
e.g.
|
||||
```
|
||||
{
|
||||
@@ -60,14 +57,13 @@ e.g.
|
||||
```
|
||||
See the echo's documentation for the dimming phrase.
|
||||
|
||||
POST/PUT support
|
||||
-----
|
||||
## POST/PUT support
|
||||
added optional fields
|
||||
* contentType (currently un-validated)
|
||||
* httpVerb (POST/PUT/GET only supported)
|
||||
* contentBody your post/put body here
|
||||
|
||||
This will allow control of any other application that may need mroe then GET.
|
||||
This will allow control of any other application that may need more then GET.
|
||||
e.g:
|
||||
```
|
||||
{
|
||||
@@ -80,7 +76,7 @@ e.g:
|
||||
"contentBody" : "{\"fooBar\":\"baz\"}"
|
||||
}
|
||||
```
|
||||
Anything that takes an action as a result of an HTTP request will probably work - like putting Vera in and out of night mode:
|
||||
Anything that takes an action as a result of an HTTP request will probably work - like putting Vera in and out of night mode:
|
||||
```
|
||||
{
|
||||
"name": "night mode",
|
||||
@@ -89,10 +85,9 @@ Anything that takes an action as a result of an HTTP request will probably work
|
||||
"onUrl": "http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=3"
|
||||
}
|
||||
```
|
||||
Ask Alexa
|
||||
----
|
||||
After this Tell Alexa: "Alexa, discover my devices"
|
||||
## Ask Alexa
|
||||
After this Tell Alexa: "Alexa, discover my devices"
|
||||
|
||||
Then you can say "Alexa, Turn on the office light" or whatever name you have given your configured devices.
|
||||
Then you can say "Alexa, Turn on the office light" or whatever name you have given your configured devices.
|
||||
|
||||
To view or remove devices that Alexa knows about, you can use the mobile app Menu / Settings / Connected Home
|
||||
To view or remove devices that Alexa knows about, you can use the mobile app Menu / Settings / Connected Home
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>0.4.0</version>
|
||||
<version>0.4.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -7,6 +7,8 @@ public class BridgeSettings {
|
||||
private String upnpdevicedb;
|
||||
private String veraaddress;
|
||||
private boolean upnpStrict;
|
||||
private boolean traceupnp;
|
||||
private boolean vtwocompatibility;
|
||||
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
@@ -45,4 +47,18 @@ public class BridgeSettings {
|
||||
public void setUpnpStrict(boolean upnpStrict) {
|
||||
this.upnpStrict = upnpStrict;
|
||||
}
|
||||
public boolean isTraceupnp() {
|
||||
return traceupnp;
|
||||
}
|
||||
public void setTraceupnp(boolean traceupnp) {
|
||||
this.traceupnp = traceupnp;
|
||||
}
|
||||
|
||||
public boolean isVtwocompatibility() {
|
||||
return vtwocompatibility;
|
||||
}
|
||||
public void setVtwocompatibility(boolean vtwocompatibility) {
|
||||
this.vtwocompatibility = vtwocompatibility;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ public class HABridge {
|
||||
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000"));
|
||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100"));
|
||||
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "true")));
|
||||
|
||||
// sparkjava config directive to set ip address for the web server to listen on
|
||||
// ipAddress("0.0.0.0"); // not used
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DeviceResource {
|
||||
deviceRepository.save(device);
|
||||
log.debug("Created a Device: " + request.body());
|
||||
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.status(HttpStatus.SC_CREATED);
|
||||
}
|
||||
return device;
|
||||
}, new JsonTransformer());
|
||||
|
||||
@@ -24,6 +24,10 @@ public class UpnpListener {
|
||||
private String responseAddress;
|
||||
|
||||
private boolean strict;
|
||||
|
||||
private boolean traceupnp;
|
||||
|
||||
private boolean vTwoCompatibility;
|
||||
|
||||
public UpnpListener(BridgeSettings theSettings) {
|
||||
super();
|
||||
@@ -31,6 +35,8 @@ public class UpnpListener {
|
||||
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
||||
responseAddress = theSettings.getUpnpConfigAddress();
|
||||
strict = theSettings.isUpnpStrict();
|
||||
traceupnp = theSettings.isTraceupnp();
|
||||
vTwoCompatibility = theSettings.isVtwocompatibility();
|
||||
}
|
||||
|
||||
public void startListening(){
|
||||
@@ -66,8 +72,12 @@ public class UpnpListener {
|
||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||
upnpMulticastSocket.receive(packet);
|
||||
String packetString = new String(packet.getData());
|
||||
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1"))
|
||||
log.debug("Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + " body : " + packetString);
|
||||
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1")) {
|
||||
if(traceupnp)
|
||||
log.info("Trace SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + " body : " + packetString);
|
||||
else
|
||||
log.debug("Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + " body : " + packetString);
|
||||
}
|
||||
if(isSSDPDiscovery(packetString)){
|
||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||
}
|
||||
@@ -92,7 +102,7 @@ public class UpnpListener {
|
||||
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){
|
||||
if(strict && body.contains("ST: urn:schemas-upnp-org:device:basic:1"))
|
||||
return true;
|
||||
else if (!strict)
|
||||
else if (!strict || vTwoCompatibility)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -105,8 +115,20 @@ public class UpnpListener {
|
||||
"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";
|
||||
String discoveryTemplateVTwo = "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" +
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
|
||||
"01-NLS: %s\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
|
||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
||||
String discoveryResponse = null;
|
||||
if(vTwoCompatibility)
|
||||
discoveryResponse = String.format(discoveryTemplateVTwo, responseAddress, httpServerPort, getRandomUUIDString());
|
||||
else
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
||||
log.debug("sndUpnpResponse: " + discoveryResponse);
|
||||
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
||||
socket.send(response);
|
||||
|
||||
@@ -38,6 +38,53 @@ public class UpnpSettingsResource {
|
||||
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
|
||||
+ "</root>\n";
|
||||
|
||||
private String hueTemplateVTwo = "<?xml version=\"1.0\"?>\n" +
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n" +
|
||||
"<specVersion>\n" +
|
||||
"<major>1</major>\n" +
|
||||
"<minor>0</minor>\n" +
|
||||
"</specVersion>\n" +
|
||||
"<URLBase>http://%s:%s/</URLBase>\n" + //hostname string
|
||||
"<device>\n" +
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n" +
|
||||
"<friendlyName>Amazon-Echo-HA-Bridge (%s)</friendlyName>\n" +
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>\n" +
|
||||
"<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n" +
|
||||
"<modelDescription>Hue Emulator for Amazon Echo bridge</modelDescription>\n" +
|
||||
"<modelName>Philips hue bridge 2012</modelName>\n" +
|
||||
"<modelNumber>929000226503</modelNumber>\n" +
|
||||
"<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n" +
|
||||
"<serialNumber>01189998819991197253</serialNumber>\n" +
|
||||
"<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" +
|
||||
"<serviceList>\n" +
|
||||
"<service>\n" +
|
||||
"<serviceType>(null)</serviceType>\n" +
|
||||
"<serviceId>(null)</serviceId>\n" +
|
||||
"<controlURL>(null)</controlURL>\n" +
|
||||
"<eventSubURL>(null)</eventSubURL>\n" +
|
||||
"<SCPDURL>(null)</SCPDURL>\n" +
|
||||
"</service>\n" +
|
||||
"</serviceList>\n" +
|
||||
"<presentationURL>index.html</presentationURL>\n" +
|
||||
"<iconList>\n" +
|
||||
"<icon>\n" +
|
||||
"<mimetype>image/png</mimetype>\n" +
|
||||
"<height>48</height>\n" +
|
||||
"<width>48</width>\n" +
|
||||
"<depth>24</depth>\n" +
|
||||
"<url>hue_logo_0.png</url>\n" +
|
||||
"</icon>\n" +
|
||||
"<icon>\n" +
|
||||
"<mimetype>image/png</mimetype>\n" +
|
||||
"<height>120</height>\n" +
|
||||
"<width>120</width>\n" +
|
||||
"<depth>24</depth>\n" +
|
||||
"<url>hue_logo_3.png</url>\n" +
|
||||
"</icon>\n" +
|
||||
"</iconList>\n" +
|
||||
"</device>\n" +
|
||||
"</root>\n";
|
||||
|
||||
public UpnpSettingsResource(BridgeSettings theSettings) {
|
||||
super();
|
||||
setupListener(theSettings);
|
||||
@@ -49,7 +96,11 @@ public class UpnpSettingsResource {
|
||||
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
|
||||
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip());
|
||||
String portNumber = Integer.toString(request.port());
|
||||
String filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
String filledTemplate = null;
|
||||
if(theSettings.isVtwocompatibility())
|
||||
filledTemplate = String.format(hueTemplateVTwo, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
else
|
||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
log.debug("upnp device settings response: " + filledTemplate);
|
||||
// response.header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
|
||||
// response.header("Pragma", "no-cache");
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
|
||||
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
||||
<li><a href="#">HA Bridge Version 0.4.0</a></li>
|
||||
<li><a href="#">HA Bridge Version 0.4.1</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -103,6 +103,40 @@
|
||||
ng-click="testUrl(device.offUrl)">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-http-verb"
|
||||
ng-model="device.httpVerb" placeholder="Http Verb, i.e. GET/PUT/POST">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-content-type"
|
||||
ng-model="device.contentType" placeholder="Content type, i.e. application/json">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-content-body"
|
||||
ng-model="device.contentBody" placeholder="Content Body for specific GET/PUT/POST type"></textarea>
|
||||
</div>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user