mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c1d6e40b8 | ||
|
|
c5fbd5d1f0 | ||
|
|
aebde7ee48 | ||
|
|
c8fb93eeb6 | ||
|
|
1602ed004a | ||
|
|
7514e36edb | ||
|
|
2789d8c180 | ||
|
|
af1777aeb3 | ||
|
|
fc2d587e1a | ||
|
|
416b4d3fda | ||
|
|
9666273840 | ||
|
|
774bc8a36b | ||
|
|
74d4548beb | ||
|
|
eecf0f9875 | ||
|
|
ed96b5ad81 | ||
|
|
9f7d3ea331 | ||
|
|
68de92bb74 | ||
|
|
392a46c3d8 | ||
|
|
568569248a | ||
|
|
d61d10b5b6 | ||
|
|
7294dbf175 | ||
|
|
6c99358f95 | ||
|
|
eee0394f20 | ||
|
|
d87f3bc541 | ||
|
|
e38374f749 | ||
|
|
937fb5d32d | ||
|
|
bd60d63d0f | ||
|
|
439b081bd5 | ||
|
|
41f68f58b0 | ||
|
|
fa15cf3952 | ||
|
|
3ea7f2903f | ||
|
|
7746938c62 | ||
|
|
96074628fb | ||
|
|
9dc8d8f8bc | ||
|
|
8de39a8bee | ||
|
|
626f0641cc | ||
|
|
020da99e1c |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@ buildNumber.properties
|
|||||||
data
|
data
|
||||||
.idea
|
.idea
|
||||||
/target/
|
/target/
|
||||||
|
/.settings/
|
||||||
|
/start.bat
|
||||||
|
/.classpath
|
||||||
|
|||||||
23
.project
Normal file
23
.project
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ha-bridge</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
104
README.md
104
README.md
@@ -1,31 +1,40 @@
|
|||||||
# ha-bridge
|
# ha-bridge
|
||||||
Emulates philips hue api to other home automation gateways. The Amazon echo now supports wemo and philip hue.
|
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo. The Bridge has helpers to build devices for the gateway for the Vera, Vera Lite or Vera Edge. Alternatively the Bridge supports custom calls as well. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol.
|
||||||
Build
|
## Build
|
||||||
-----
|
To customize and build it yourself, build a new jar with maven:
|
||||||
|
|
||||||
To customize and build it yourself, build a new jar with maven:
|
|
||||||
```
|
```
|
||||||
mvn install
|
mvn install
|
||||||
```
|
```
|
||||||
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
|
java -jar -Dvera.address=X.Y.Z.A ha-bridge-0.X.Y.jar
|
||||||
```
|
```
|
||||||
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.
|
## Available Arguments
|
||||||
|
### -Dvera.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.
|
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. If a vera is not used, do not set it.
|
||||||
|
### -Dupnp.config.address=`<ip address>`
|
||||||
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.
|
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 as the address that any upnp device will call after discovery.
|
||||||
|
### -Dserver.port=`<port>`
|
||||||
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 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.device.db=`<filepath>`
|
||||||
The default upnp response port will be 50000 otherwise it can be set with -Dupnp.response.port=<port>.
|
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.
|
||||||
|
### -Dupnp.response.port=`<port>`
|
||||||
Then configure by going to the url for the host you are running on or localhost:
|
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 false.
|
||||||
|
## 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>
|
||||||
```
|
```
|
||||||
or Register a device, via REST by binding some sort of on/off (vera style) url
|
## Command line configure
|
||||||
|
Register a device via REST by by using a tool and the url, for example:
|
||||||
```
|
```
|
||||||
POST http://host:8080/api/devices
|
POST http://host:8080/api/devices
|
||||||
{
|
{
|
||||||
@@ -35,9 +44,58 @@ 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"
|
"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 and value passing control
|
||||||
|
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 or custom values using ${intensity.math(<your expression using "X" as the value to operate on>)} i.e. "{$intensity.math(X/4)}".
|
||||||
|
e.g.
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "entry light",
|
||||||
|
"deviceType": "switch",
|
||||||
|
"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=31",
|
||||||
|
"onUrl": "http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
See the echo's documentation for the dimming phrase.
|
||||||
|
|
||||||
After this Tell Alexa: "Alexa, discover my devices"
|
## POST/PUT support
|
||||||
|
added optional fields
|
||||||
|
* contentType (currently un-validated)
|
||||||
|
* httpVerb (POST/PUT/GET only supported)
|
||||||
|
* contentBody your post/put body for onUrl here
|
||||||
|
* contentBodyOff your post/put body for offUrl here
|
||||||
|
|
||||||
Then you can say "Alexa, Turn on the office light" or whatever name you have given your configured devices.
|
This will allow control of any other application that may need more then GET. You can also use the dimming and value control commands within the URLs as well.
|
||||||
|
e.g:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "test device",
|
||||||
|
"deviceType": "switch",
|
||||||
|
"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=31",
|
||||||
|
"onUrl": "http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}",
|
||||||
|
"contentType" : "application/json",
|
||||||
|
"httpVerb":"POST",
|
||||||
|
"contentBody" : "{\"fooBar\":\"baz_on\"}"
|
||||||
|
"contentBodyOff" : "{\"fooBar\":\"baz_off\"}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Custom Usage URLs
|
||||||
|
Anything that takes an action as a result of an HTTP request will probably work and you can also use the dimming and value control commands within the URLs as well - like putting Vera in and out of night mode:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "night mode",
|
||||||
|
"deviceType": "switch",
|
||||||
|
"offUrl": "http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=1",
|
||||||
|
"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"
|
||||||
|
|
||||||
To view or remove devices that Alexa knows about, you can use the mobile app Menu / Settings / Connected Home
|
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
|
||||||
|
## Debugging
|
||||||
|
To turn on debugging for the bridge, use the following extra parm in the command line:
|
||||||
|
```
|
||||||
|
-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG
|
||||||
|
```
|
||||||
7
pom.xml
7
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>0.3.0</version>
|
<version>0.4.9</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
@@ -53,6 +53,11 @@
|
|||||||
<artifactId>json-io</artifactId>
|
<artifactId>json-io</artifactId>
|
||||||
<version>4.1.6</version>
|
<version>4.1.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.java.dev.eval</groupId>
|
||||||
|
<artifactId>eval</artifactId>
|
||||||
|
<version>0.5</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ public class BridgeSettings {
|
|||||||
private String upnpresponseport;
|
private String upnpresponseport;
|
||||||
private String upnpdevicedb;
|
private String upnpdevicedb;
|
||||||
private String veraaddress;
|
private String veraaddress;
|
||||||
|
private boolean upnpstrict;
|
||||||
|
private boolean traceupnp;
|
||||||
|
private boolean vtwocompatibility;
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
return upnpconfigaddress;
|
return upnpconfigaddress;
|
||||||
@@ -37,6 +40,30 @@ public class BridgeSettings {
|
|||||||
public void setVeraAddress(String veraAddress) {
|
public void setVeraAddress(String veraAddress) {
|
||||||
this.veraaddress = veraAddress;
|
this.veraaddress = veraAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUpnpStrict() {
|
||||||
|
return upnpstrict;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isValidVera() {
|
||||||
|
if(this.veraaddress.contains(Configuration.DEFAULT_VERA_ADDRESS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
8
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class Configuration {
|
||||||
|
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||||
|
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||||
|
public final static String DEFAULT_VERA_ADDRESS = "1.1.1.1";
|
||||||
|
public final static String DFAULT_WEB_PORT = "8080";
|
||||||
|
}
|
||||||
@@ -12,7 +12,6 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
|
|||||||
import com.bwssystems.HABridge.hue.HueMulator;
|
import com.bwssystems.HABridge.hue.HueMulator;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||||
import com.bwssystems.vera.VeraInfo;
|
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -52,14 +51,17 @@ public class HABridge {
|
|||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings = new BridgeSettings();
|
||||||
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
|
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
|
||||||
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", "data/device.db"));
|
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
|
||||||
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000"));
|
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100"));
|
bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
|
||||||
|
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||||
|
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||||
|
bridgeSettings.setVtwocompatibility(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "false")));
|
||||||
|
|
||||||
// sparkjava config directive to set ip address for the web server to listen on
|
// sparkjava config directive to set ip address for the web server to listen on
|
||||||
// ipAddress("0.0.0.0"); // not used
|
// ipAddress("0.0.0.0"); // not used
|
||||||
// sparkjava config directive to set port for the web server to listen on
|
// sparkjava config directive to set port for the web server to listen on
|
||||||
bridgeSettings.setServerPort(System.getProperty("server.port", "8080"));
|
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
||||||
port(Integer.valueOf(bridgeSettings.getServerPort()));
|
port(Integer.valueOf(bridgeSettings.getServerPort()));
|
||||||
// sparkjava config directive to set html static file location for Jetty
|
// sparkjava config directive to set html static file location for Jetty
|
||||||
staticFileLocation("/public");
|
staticFileLocation("/public");
|
||||||
@@ -68,14 +70,15 @@ public class HABridge {
|
|||||||
theResources = new DeviceResource(bridgeSettings);
|
theResources = new DeviceResource(bridgeSettings);
|
||||||
// setup the class to handle the hue emulator rest api
|
// setup the class to handle the hue emulator rest api
|
||||||
theHueMulator = new HueMulator(theResources.getDeviceRepository());
|
theHueMulator = new HueMulator(theResources.getDeviceRepository());
|
||||||
|
theHueMulator.setupServer();
|
||||||
// setup the class to handle the upnp response rest api
|
// setup the class to handle the upnp response rest api
|
||||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||||
|
theSettingResponder.setupServer();
|
||||||
// wait for the sparkjava initialization of the rest api classes to be complete
|
// wait for the sparkjava initialization of the rest api classes to be complete
|
||||||
awaitInitialization();
|
awaitInitialization();
|
||||||
|
|
||||||
// start the upnp ssdp discovery listener
|
// start the upnp ssdp discovery listener
|
||||||
theUpnpListener = new UpnpListener(bridgeSettings);
|
theUpnpListener = new UpnpListener(bridgeSettings);
|
||||||
log.info("Done setup, application to run....");
|
|
||||||
theUpnpListener.startListening();
|
theUpnpListener.startListening();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package com.bwssystems.HABridge.api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by arm on 4/13/15.
|
|
||||||
*/
|
|
||||||
public class Device {
|
|
||||||
private String name;
|
|
||||||
private String deviceType;
|
|
||||||
private String offUrl;
|
|
||||||
private String onUrl;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceType() {
|
|
||||||
return deviceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceType(String deviceType) {
|
|
||||||
this.deviceType = deviceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffUrl() {
|
|
||||||
return offUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffUrl(String offUrl) {
|
|
||||||
this.offUrl = offUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOnUrl() {
|
|
||||||
return onUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnUrl(String onUrl) {
|
|
||||||
this.onUrl = onUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class UserCreateRequest {
|
||||||
|
private String devicetype;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public String getDevicetype() {
|
||||||
|
return devicetype;
|
||||||
|
}
|
||||||
|
public void setDevicetype(String devicetype) {
|
||||||
|
this.devicetype = devicetype;
|
||||||
|
}
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,17 +75,20 @@ public class DeviceResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getPointsymbol() {
|
public Map<String, String> getPointsymbol() {
|
||||||
Map<String, String> dummyValue = new HashMap<>();
|
if(pointsymbol == null)
|
||||||
dummyValue.put("1", "none");
|
{
|
||||||
dummyValue.put("2", "none");
|
pointsymbol = new HashMap<>();
|
||||||
dummyValue.put("3", "none");
|
pointsymbol.put("1", "none");
|
||||||
dummyValue.put("4", "none");
|
pointsymbol.put("2", "none");
|
||||||
dummyValue.put("5", "none");
|
pointsymbol.put("3", "none");
|
||||||
dummyValue.put("6", "none");
|
pointsymbol.put("4", "none");
|
||||||
dummyValue.put("7", "none");
|
pointsymbol.put("5", "none");
|
||||||
dummyValue.put("8", "none");
|
pointsymbol.put("6", "none");
|
||||||
|
pointsymbol.put("7", "none");
|
||||||
|
pointsymbol.put("8", "none");
|
||||||
|
}
|
||||||
|
|
||||||
return dummyValue;
|
return pointsymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPointsymbol(Map<String, String> pointsymbol) {
|
public void setPointsymbol(Map<String, String> pointsymbol) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
@@ -9,12 +10,46 @@ import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
|||||||
*/
|
*/
|
||||||
public class HueApiResponse {
|
public class HueApiResponse {
|
||||||
private Map<String, DeviceResponse> lights;
|
private Map<String, DeviceResponse> lights;
|
||||||
|
private Map<String, String> scenes;
|
||||||
|
private Map<String, String> groups;
|
||||||
|
private HueConfig config;
|
||||||
|
|
||||||
public Map<String, DeviceResponse> getLights() {
|
public HueApiResponse(String name, String ipaddress, String username, String userid) {
|
||||||
|
super();
|
||||||
|
this.setConfig(HueConfig.createConfig(name, ipaddress, username, userid));
|
||||||
|
this.setGroups(new HashMap<>());
|
||||||
|
this.setScenes(new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, DeviceResponse> getLights() {
|
||||||
return lights;
|
return lights;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLights(Map<String, DeviceResponse> lights) {
|
public void setLights(Map<String, DeviceResponse> lights) {
|
||||||
this.lights = lights;
|
this.lights = lights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getScenes() {
|
||||||
|
return scenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScenes(Map<String, String> scenes) {
|
||||||
|
this.scenes = scenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroups(Map<String, String> groups) {
|
||||||
|
this.groups = groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueConfig getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(HueConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
198
src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java
Normal file
198
src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HueConfig
|
||||||
|
{
|
||||||
|
private Boolean portalservices;
|
||||||
|
private String gateway;
|
||||||
|
private String mac;
|
||||||
|
private String swversion;
|
||||||
|
private String apiversion;
|
||||||
|
private Boolean linkbutton;
|
||||||
|
private String ipaddress;
|
||||||
|
private Integer proxyport;
|
||||||
|
private Swupdate swupdate;
|
||||||
|
private String netmask;
|
||||||
|
private String name;
|
||||||
|
private Boolean dhcp;
|
||||||
|
private String UTC;
|
||||||
|
private String proxyaddress;
|
||||||
|
private String localtime;
|
||||||
|
private String timezone;
|
||||||
|
private String zigbeechannel;
|
||||||
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
|
|
||||||
|
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
|
||||||
|
HueConfig aConfig = new HueConfig();
|
||||||
|
aConfig.setApiversion("1.4.0");
|
||||||
|
aConfig.setPortalservices(false);
|
||||||
|
aConfig.setGateway("192.168.1.1");
|
||||||
|
aConfig.setMac("00:00:88:00:bb:ee");
|
||||||
|
aConfig.setSwversion("01005215");
|
||||||
|
aConfig.setLinkbutton(false);
|
||||||
|
aConfig.setIpaddress(ipaddress);
|
||||||
|
aConfig.setProxyport(0);
|
||||||
|
aConfig.setSwupdate(Swupdate.createSwupdate());
|
||||||
|
aConfig.setNetmask("255.255.255.0");
|
||||||
|
aConfig.setName(name);
|
||||||
|
aConfig.setDhcp(true);
|
||||||
|
aConfig.setUtc("2014-07-17T09:27:35");
|
||||||
|
aConfig.setProxyaddress("0.0.0.0");
|
||||||
|
aConfig.setLocaltime("2014-07-17T11:27:35");
|
||||||
|
aConfig.setTimezone("America/Chicago");
|
||||||
|
aConfig.setZigbeechannel("6");
|
||||||
|
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
|
||||||
|
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype));
|
||||||
|
aConfig.setWhitelist(awhitelist);
|
||||||
|
|
||||||
|
|
||||||
|
return aConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean getPortalservices() {
|
||||||
|
return portalservices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPortalservices(Boolean portalservices) {
|
||||||
|
this.portalservices = portalservices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGateway() {
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGateway(String gateway) {
|
||||||
|
this.gateway = gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMac() {
|
||||||
|
return mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMac(String mac) {
|
||||||
|
this.mac = mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSwversion() {
|
||||||
|
return swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwversion(String swversion) {
|
||||||
|
this.swversion = swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getLinkbutton() {
|
||||||
|
return linkbutton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkbutton(Boolean linkbutton) {
|
||||||
|
this.linkbutton = linkbutton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIpaddress() {
|
||||||
|
return ipaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIpaddress(String ipaddress) {
|
||||||
|
this.ipaddress = ipaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getProxyport() {
|
||||||
|
return proxyport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyport(Integer proxyport) {
|
||||||
|
this.proxyport = proxyport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Swupdate getSwupdate() {
|
||||||
|
return swupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwupdate(Swupdate swupdate) {
|
||||||
|
this.swupdate = swupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNetmask() {
|
||||||
|
return netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetmask(String netmask) {
|
||||||
|
this.netmask = netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDhcp() {
|
||||||
|
return dhcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDhcp(Boolean dhcp) {
|
||||||
|
this.dhcp = dhcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUtc() {
|
||||||
|
return UTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUtc(String utc) {
|
||||||
|
this.UTC = utc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxyaddress() {
|
||||||
|
return proxyaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyaddress(String proxyaddress) {
|
||||||
|
this.proxyaddress = proxyaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, WhitelistEntry> getWhitelist() {
|
||||||
|
return whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiversion() {
|
||||||
|
return apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiversion(String apiversion) {
|
||||||
|
this.apiversion = apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocaltime() {
|
||||||
|
return localtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocaltime(String localtime) {
|
||||||
|
this.localtime = localtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimezone() {
|
||||||
|
return timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimezone(String timezone) {
|
||||||
|
this.timezone = timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZigbeechannel() {
|
||||||
|
return zigbeechannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZigbeechannel(String zigbeechannel) {
|
||||||
|
this.zigbeechannel = zigbeechannel;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/main/java/com/bwssystems/HABridge/api/hue/Swupdate.java
Normal file
52
src/main/java/com/bwssystems/HABridge/api/hue/Swupdate.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
|
||||||
|
public class Swupdate
|
||||||
|
{
|
||||||
|
private String text;
|
||||||
|
private Boolean notify;
|
||||||
|
private Integer updatestate;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public static Swupdate createSwupdate() {
|
||||||
|
Swupdate aSwupdate = new Swupdate();
|
||||||
|
aSwupdate.setNotify(false);
|
||||||
|
aSwupdate.setText("");
|
||||||
|
aSwupdate.setUpdatestate(0);
|
||||||
|
aSwupdate.setUrl("");
|
||||||
|
return aSwupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getNotify() {
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotify(Boolean notify) {
|
||||||
|
this.notify = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUpdatestate() {
|
||||||
|
return updatestate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatestate(Integer updatestate) {
|
||||||
|
this.updatestate = updatestate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class WhitelistEntry
|
||||||
|
{
|
||||||
|
private String lastUseDate;
|
||||||
|
private String createDate;
|
||||||
|
private String name;
|
||||||
|
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
|
||||||
|
public static WhitelistEntry createEntry(String devicetype) {
|
||||||
|
WhitelistEntry anEntry = new WhitelistEntry();
|
||||||
|
anEntry.setName(devicetype);
|
||||||
|
anEntry.setCreateDate(getCurrentDate());
|
||||||
|
anEntry.setLastUseDate(getCurrentDate());
|
||||||
|
return anEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCurrentDate() {
|
||||||
|
return dateFormat.format(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastUseDate() {
|
||||||
|
return lastUseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUseDate(String lastUseDate) {
|
||||||
|
this.lastUseDate = lastUseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateDate() {
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateDate(String createDate) {
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,6 +8,10 @@ public class DeviceDescriptor{
|
|||||||
private String deviceType;
|
private String deviceType;
|
||||||
private String offUrl;
|
private String offUrl;
|
||||||
private String onUrl;
|
private String onUrl;
|
||||||
|
private String httpVerb;
|
||||||
|
private String contentType;
|
||||||
|
private String contentBody;
|
||||||
|
private String contentBodyOff;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@@ -48,4 +52,38 @@ public class DeviceDescriptor{
|
|||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHttpVerb() {
|
||||||
|
return httpVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHttpVerb(String httpVerb) {
|
||||||
|
this.httpVerb = httpVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentBody() {
|
||||||
|
return contentBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentBody(String contentBody) {
|
||||||
|
this.contentBody = contentBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentBodyOff() {
|
||||||
|
return contentBodyOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentBodyOff(String contentBodyOff) {
|
||||||
|
this.contentBodyOff = contentBodyOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.bwssystems.HABridge.dao;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -43,7 +44,7 @@ public class DeviceRepository {
|
|||||||
DeviceDescriptor theDevice = null;
|
DeviceDescriptor theDevice = null;
|
||||||
while (theIterator.hasNext()) {
|
while (theIterator.hasNext()) {
|
||||||
theDevice = theIterator.next();
|
theDevice = theIterator.next();
|
||||||
put(Integer.parseInt(theDevice.getId()), theDevice);
|
put(theDevice.getId(), theDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,20 +63,20 @@ public class DeviceRepository {
|
|||||||
return devices.get(id);
|
return devices.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void put(int id, DeviceDescriptor aDescriptor) {
|
private void put(String id, DeviceDescriptor aDescriptor) {
|
||||||
devices.put(String.valueOf(id), aDescriptor);
|
devices.put(id, aDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(DeviceDescriptor aDescriptor) {
|
public void save(DeviceDescriptor aDescriptor) {
|
||||||
int id = random.nextInt(Integer.MAX_VALUE);
|
|
||||||
if(aDescriptor.getId() != null)
|
if(aDescriptor.getId() != null)
|
||||||
devices.remove(aDescriptor.getId());
|
devices.remove(aDescriptor.getId());
|
||||||
else
|
else
|
||||||
aDescriptor.setId(String.valueOf(id));
|
aDescriptor.setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
|
||||||
put(id, aDescriptor);
|
put(aDescriptor.getId(), aDescriptor);
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
String jsonValue = aRenderer.render(findAll());
|
String jsonValue = aRenderer.render(findAll());
|
||||||
repositoryWriter(jsonValue, repositoryPath);
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
|
log.debug("Save device: " + aDescriptor.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String delete(DeviceDescriptor aDescriptor) {
|
public String delete(DeviceDescriptor aDescriptor) {
|
||||||
@@ -106,7 +107,14 @@ public class DeviceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Path target = null;
|
||||||
|
if(Files.exists(filePath)) {
|
||||||
|
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
|
||||||
|
Files.move(filePath, target);
|
||||||
|
}
|
||||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
|
if(target != null)
|
||||||
|
Files.delete(target);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -116,7 +124,7 @@ public class DeviceRepository {
|
|||||||
|
|
||||||
String content = null;
|
String content = null;
|
||||||
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
||||||
log.error("Error reading the file: " + filePath + " - Does not exist or is not readable. ");
|
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +187,18 @@ public class DeviceRepository {
|
|||||||
} else if (name.equals("onUrl")) {
|
} else if (name.equals("onUrl")) {
|
||||||
deviceEntry.setOnUrl(reader.nextString());
|
deviceEntry.setOnUrl(reader.nextString());
|
||||||
log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl());
|
log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl());
|
||||||
|
} else if (name.equals("httpVerb")) {
|
||||||
|
deviceEntry.setHttpVerb(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json httpVerb:" + deviceEntry.getHttpVerb());
|
||||||
|
} else if (name.equals("contentType")) {
|
||||||
|
deviceEntry.setContentType(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json contentType:" + deviceEntry.getContentType());
|
||||||
|
} else if (name.equals("contentBody")) {
|
||||||
|
deviceEntry.setContentBody(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody());
|
||||||
|
} else if (name.equals("contentBodyOff")) {
|
||||||
|
deviceEntry.setContentBodyOff(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json contentBodyOff:" + deviceEntry.getContentBodyOff());
|
||||||
} else {
|
} else {
|
||||||
reader.skipValue();
|
reader.skipValue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ import static spark.Spark.get;
|
|||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
import static spark.Spark.delete;
|
import static spark.Spark.delete;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -27,12 +31,12 @@ public class DeviceResource {
|
|||||||
|
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
private VeraInfo veraInfo;
|
private VeraInfo veraInfo;
|
||||||
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||||
|
|
||||||
public DeviceResource(BridgeSettings theSettings) {
|
public DeviceResource(BridgeSettings theSettings) {
|
||||||
super();
|
super();
|
||||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
veraInfo = new VeraInfo(theSettings.getVeraAddress());
|
veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,41 +45,52 @@ public class DeviceResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupEndpoints() {
|
private void setupEndpoints() {
|
||||||
log.debug("Setting up endpoints");
|
log.info("HABridge device management service started.... ");
|
||||||
post(API_CONTEXT, "application/json", (request, response) -> {
|
post(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
log.debug("Create a Device - request body: " + request.body());
|
log.debug("Create a Device - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
DeviceDescriptor deviceEntry = new DeviceDescriptor();
|
if(device.getContentBody() != null ) {
|
||||||
deviceEntry.setName(device.getName());
|
if (device.getContentType() == null || device.getHttpVerb() == null || !supportedVerbs.contains(device.getHttpVerb().toLowerCase())) {
|
||||||
log.debug("Create a Device - device json name: " + deviceEntry.getName());
|
device = null;
|
||||||
deviceEntry.setDeviceType(device.getDeviceType());
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
log.debug("Create a Device - device json type:" + deviceEntry.getDeviceType());
|
log.debug("Bad http verb in create a Device: " + request.body());
|
||||||
deviceEntry.setOnUrl(device.getOnUrl());
|
return device;
|
||||||
log.debug("Create a Device - device json on URL:" + deviceEntry.getOnUrl());
|
}
|
||||||
deviceEntry.setOffUrl(device.getOffUrl());
|
}
|
||||||
log.debug("Create a Device - device json off URL:" + deviceEntry.getOffUrl());
|
|
||||||
|
deviceRepository.save(device);
|
||||||
deviceRepository.save(deviceEntry);
|
log.debug("Created a Device: " + request.body());
|
||||||
log.debug("Created a Device");
|
|
||||||
|
response.status(HttpStatus.SC_CREATED);
|
||||||
response.status(201);
|
|
||||||
return deviceEntry;
|
return device;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Saved a Device");
|
log.debug("Edit a Device - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
|
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
|
||||||
if(deviceEntry == null){
|
if(deviceEntry == null){
|
||||||
return null;
|
log.debug("Could not save an edited Device Id: " + request.params(":id"));
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.debug("Saving an edited Device: " + deviceEntry.getName());
|
||||||
|
|
||||||
|
deviceEntry.setName(device.getName());
|
||||||
|
if (device.getDeviceType() != null)
|
||||||
|
deviceEntry.setDeviceType(device.getDeviceType());
|
||||||
|
deviceEntry.setOnUrl(device.getOnUrl());
|
||||||
|
deviceEntry.setOffUrl(device.getOffUrl());
|
||||||
|
deviceEntry.setHttpVerb(device.getHttpVerb());
|
||||||
|
deviceEntry.setContentType(device.getContentType());
|
||||||
|
deviceEntry.setContentBody(device.getContentBody());
|
||||||
|
deviceEntry.setContentBodyOff(device.getContentBodyOff());
|
||||||
|
|
||||||
|
deviceRepository.save(deviceEntry);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceEntry.setName(device.getName());
|
|
||||||
deviceEntry.setDeviceType(device.getDeviceType());
|
|
||||||
deviceEntry.setOnUrl(device.getOnUrl());
|
|
||||||
deviceEntry.setOffUrl(device.getOffUrl());
|
|
||||||
|
|
||||||
deviceRepository.save(deviceEntry);
|
|
||||||
return deviceEntry;
|
return deviceEntry;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
@@ -85,25 +100,30 @@ public class DeviceResource {
|
|||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
String theStream = aRenderer.render(deviceList);
|
String theStream = aRenderer.render(deviceList);
|
||||||
log.debug("The Device List: " + theStream);
|
log.debug("The Device List: " + theStream);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return deviceList;
|
return deviceList;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Get a device");
|
log.debug("Get a device");
|
||||||
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
||||||
if(descriptor == null){
|
if(descriptor == null)
|
||||||
return null;
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
}
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Delete a device");
|
log.debug("Delete a device");
|
||||||
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
|
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
|
||||||
if(deleted == null){
|
if(deleted == null)
|
||||||
return null;
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deviceRepository.delete(deleted);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
}
|
}
|
||||||
deviceRepository.delete(deleted);
|
|
||||||
return null;
|
return null;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
@@ -111,8 +131,11 @@ public class DeviceResource {
|
|||||||
log.debug("Get vera devices");
|
log.debug("Get vera devices");
|
||||||
Sdata sData = veraInfo.getSdata();
|
Sdata sData = veraInfo.getSdata();
|
||||||
if(sData == null){
|
if(sData == null){
|
||||||
return null;
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return sData.getDevices();
|
return sData.getDevices();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
@@ -120,10 +143,12 @@ public class DeviceResource {
|
|||||||
log.debug("Get vera scenes");
|
log.debug("Get vera scenes");
|
||||||
Sdata sData = veraInfo.getSdata();
|
Sdata sData = veraInfo.getSdata();
|
||||||
if(sData == null){
|
if(sData == null){
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return sData.getScenes();
|
return sData.getScenes();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,30 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
import com.bwssystems.HABridge.JsonTransformer;
|
||||||
|
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
import com.bwssystems.HABridge.dao.*;
|
import com.bwssystems.HABridge.dao.*;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import net.java.dev.eval.Expression;
|
||||||
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
@@ -22,6 +32,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -34,6 +45,9 @@ public class HueMulator {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
|
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
|
||||||
private static final String INTENSITY_PERCENT = "${intensity.percent}";
|
private static final String INTENSITY_PERCENT = "${intensity.percent}";
|
||||||
private static final String INTENSITY_BYTE = "${intensity.byte}";
|
private static final String INTENSITY_BYTE = "${intensity.byte}";
|
||||||
|
private static final String INTENSITY_MATH = "${intensity.math(";
|
||||||
|
private static final String INTENSITY_MATH_VALUE = "X";
|
||||||
|
private static final String INTENSITY_MATH_CLOSE = ")}";
|
||||||
private static final String HUE_CONTEXT = "/api";
|
private static final String HUE_CONTEXT = "/api";
|
||||||
|
|
||||||
private DeviceRepository repository;
|
private DeviceRepository repository;
|
||||||
@@ -42,44 +56,87 @@ public class HueMulator {
|
|||||||
|
|
||||||
|
|
||||||
public HueMulator(DeviceRepository aDeviceRepository){
|
public HueMulator(DeviceRepository aDeviceRepository){
|
||||||
httpClient = HttpClients.createMinimal();
|
httpClient = HttpClients.createDefault();
|
||||||
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
repository = aDeviceRepository;
|
repository = aDeviceRepository;
|
||||||
setupEndpoints();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function sets up the sparkjava rest calls for the hue api
|
// This function sets up the sparkjava rest calls for the hue api
|
||||||
private void setupEndpoints() {
|
public void setupServer() {
|
||||||
|
log.info("Hue emulator service started....");
|
||||||
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
|
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
|
||||||
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
|
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
log.info("hue lights list requested: " + userId + " from " + request.ip());
|
log.debug("hue lights list requested: " + userId + " from " + request.ip());
|
||||||
List<DeviceDescriptor> deviceList = repository.findByDeviceType("switch");
|
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
||||||
String theStream = aRenderer.render(deviceList);
|
|
||||||
log.debug("The Device List: " + theStream);
|
|
||||||
Map<String, String> deviceResponseMap = new HashMap<>();
|
|
||||||
for (DeviceDescriptor device : deviceList) {
|
for (DeviceDescriptor device : deviceList) {
|
||||||
deviceResponseMap.put(device.getId(), device.getName());
|
DeviceResponse deviceResponse = DeviceResponse.createResponse(device.getName(), device.getId());
|
||||||
|
deviceResponseMap.put(device.getId(), deviceResponse);
|
||||||
}
|
}
|
||||||
response.status(200);
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return deviceResponseMap;
|
return deviceResponseMap;
|
||||||
} , new JsonTransformer());
|
} , new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api/* returns json object for a test call
|
// http://ip_address:port/api with body of user request returns json object for a success of user add
|
||||||
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
post(HUE_CONTEXT, "application/json", (request, response) -> {
|
||||||
response.status(200);
|
UserCreateRequest aNewUser = null;
|
||||||
return "[{\"success\":{\"username\":\"lights\"}}]";
|
String newUser = null;
|
||||||
|
String aDeviceType = null;
|
||||||
|
|
||||||
|
log.debug("hue api user create requested: " + request.body() + " from " + request.ip());
|
||||||
|
|
||||||
|
if(request.body() != null && !request.body().isEmpty()) {
|
||||||
|
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
|
||||||
|
newUser = aNewUser.getUsername();
|
||||||
|
aDeviceType = aNewUser.getDevicetype();
|
||||||
|
}
|
||||||
|
if(newUser == null)
|
||||||
|
newUser = "lightssystem";
|
||||||
|
|
||||||
|
if(aDeviceType == null)
|
||||||
|
aDeviceType = "<not given>";
|
||||||
|
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
||||||
|
|
||||||
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// http://ip_address:port/api/{userId} returns json objects for the list of names of lights
|
// http://ip_address:port/api/* with body of user request returns json object for a success of user add - This method is for Harmony Hub
|
||||||
|
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
||||||
|
UserCreateRequest aNewUser = null;
|
||||||
|
String newUser = null;
|
||||||
|
String aDeviceType = null;
|
||||||
|
|
||||||
|
log.info("HH trace: hue api user create requested: " + request.body() + " from " + request.ip());
|
||||||
|
|
||||||
|
if(request.body() != null && !request.body().isEmpty()) {
|
||||||
|
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
|
||||||
|
newUser = aNewUser.getUsername();
|
||||||
|
aDeviceType = aNewUser.getDevicetype();
|
||||||
|
}
|
||||||
|
if(newUser == null)
|
||||||
|
newUser = "lightssystem";
|
||||||
|
|
||||||
|
if(aDeviceType == null)
|
||||||
|
aDeviceType = "<not given>";
|
||||||
|
log.debug("HH trace: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
||||||
|
|
||||||
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||||
|
} );
|
||||||
|
|
||||||
|
// http://ip_address:port/api/{userId} returns json objects for the full state
|
||||||
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
|
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
log.info("hue api root requested: " + userId + " from " + request.ip());
|
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
||||||
List<DeviceDescriptor> descriptorList = repository.findByDeviceType("switch");
|
List<DeviceDescriptor> descriptorList = repository.findAll();
|
||||||
if (descriptorList == null) {
|
if (descriptorList == null) {
|
||||||
response.status(404);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, DeviceResponse> deviceList = new HashMap<>();
|
Map<String, DeviceResponse> deviceList = new HashMap<>();
|
||||||
@@ -89,10 +146,11 @@ public class HueMulator {
|
|||||||
deviceList.put(descriptor.getId(), deviceResponse);
|
deviceList.put(descriptor.getId(), deviceResponse);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
HueApiResponse apiResponse = new HueApiResponse();
|
HueApiResponse apiResponse = new HueApiResponse("Philips hue", request.ip(), "My App", userId);
|
||||||
apiResponse.setLights(deviceList);
|
apiResponse.setLights(deviceList);
|
||||||
|
|
||||||
response.status(200);
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return apiResponse;
|
return apiResponse;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
@@ -100,17 +158,18 @@ public class HueMulator {
|
|||||||
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
|
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
String lightId = request.params(":id");
|
String lightId = request.params(":id");
|
||||||
log.info("hue light requested: " + lightId + "for user: " + userId + " from " + request.ip());
|
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + request.ip());
|
||||||
DeviceDescriptor device = repository.findOne(lightId);
|
DeviceDescriptor device = repository.findOne(lightId);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
response.status(404);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
log.info("found device named: " + device.getName());
|
log.debug("found device named: " + device.getName());
|
||||||
}
|
}
|
||||||
DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId());
|
DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId());
|
||||||
|
|
||||||
response.status(200);
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return lightResponse;
|
return lightResponse;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
@@ -122,21 +181,21 @@ public class HueMulator {
|
|||||||
*/
|
*/
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
String lightId = request.params(":id");
|
String lightId = request.params(":id");
|
||||||
log.info("hue state change requested: " + userId + " from " + request.ip());
|
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
log.info("hue stage change body: " + request.body() );
|
|
||||||
|
|
||||||
DeviceState state = null;
|
DeviceState state = null;
|
||||||
try {
|
try {
|
||||||
state = mapper.readValue(request.body(), DeviceState.class);
|
state = mapper.readValue(request.body(), DeviceState.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.info("object mapper barfed on input", e);
|
log.error("Object mapper barfed on input of body.", e);
|
||||||
response.status(400);
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceDescriptor device = repository.findOne(lightId);
|
DeviceDescriptor device = repository.findOne(lightId);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
response.status(404);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
log.error("Could not find devcie: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,41 +209,86 @@ public class HueMulator {
|
|||||||
url = device.getOffUrl();
|
url = device.getOffUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* light weight templating here, was going to use free marker but it was a bit too
|
//quick template
|
||||||
* heavy for what we were trying to do.
|
String body;
|
||||||
*
|
url = replaceIntensityValue(url, state.getBri());
|
||||||
* currently provides only two variables:
|
if (state.isOn())
|
||||||
* intensity.byte : 0-255 brightness. this is raw from the echo
|
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||||
* intensity.percent : 0-100, adjusted for the vera
|
else
|
||||||
*/
|
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||||
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
|
//make call
|
||||||
if(!doHttpGETRequest(url)){
|
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
|
||||||
response.status(503);
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||||
|
log.error("Error on calling url to change device state: " + url);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.status(200);
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return responseString;
|
return responseString;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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:
|
||||||
|
* intensity.byte : 0-255 brightness. this is raw from the echo
|
||||||
|
* intensity.percent : 0-100, adjusted for the vera
|
||||||
|
* intensity.math(X*1) : where X is the value from the interface call and can use net.java.dev.eval math
|
||||||
|
*/
|
||||||
|
protected String replaceIntensityValue(String request, int intensity){
|
||||||
|
if(request == null){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if(request.contains(INTENSITY_BYTE)){
|
||||||
|
String intensityByte = String.valueOf(intensity);
|
||||||
|
request = request.replace(INTENSITY_BYTE, intensityByte);
|
||||||
|
}else if(request.contains(INTENSITY_PERCENT)){
|
||||||
|
int percentBrightness = (int) Math.round(intensity/255.0*100);
|
||||||
|
String intensityPercent = String.valueOf(percentBrightness);
|
||||||
|
request = request.replace(INTENSITY_PERCENT, intensityPercent);
|
||||||
|
} else if(request.contains(INTENSITY_MATH)){
|
||||||
|
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
||||||
|
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
|
||||||
|
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: " + String.valueOf(intensity));
|
||||||
|
Expression exp = new Expression(mathDescriptor);
|
||||||
|
BigDecimal result = exp.eval(variables);
|
||||||
|
Integer endResult = Math.round(result.floatValue());
|
||||||
|
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Could not execute Math: " + mathDescriptor, e);
|
||||||
|
} }
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This function executes the url from the device repository against the vera
|
// This function executes the url from the device repository against the vera
|
||||||
protected boolean doHttpGETRequest(String url) {
|
protected boolean doHttpRequest(String url, String httpVerb, String contentType, String body) {
|
||||||
log.info("calling GET on URL: " + url);
|
HttpUriRequest request = null;
|
||||||
HttpGet httpGet = new HttpGet(url);
|
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
|
||||||
|
request = new HttpGet(url);
|
||||||
|
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||||
|
HttpPost postRequest = new HttpPost(url);
|
||||||
|
ContentType parsedContentType = ContentType.parse(contentType);
|
||||||
|
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||||
|
postRequest.setEntity(requestBody);
|
||||||
|
request = postRequest;
|
||||||
|
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||||
|
HttpPut putRequest = new HttpPut(url);
|
||||||
|
ContentType parsedContentType = ContentType.parse(contentType);
|
||||||
|
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||||
|
putRequest.setEntity(requestBody);
|
||||||
|
request = putRequest;
|
||||||
|
}
|
||||||
|
log.debug("Making outbound call in doHttpRequest: " + request);
|
||||||
try {
|
try {
|
||||||
HttpResponse response = httpClient.execute(httpGet);
|
HttpResponse response = httpClient.execute(request);
|
||||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
log.info("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
log.debug("Execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
if(response.getStatusLine().getStatusCode() == 200){
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,16 +22,25 @@ public class UpnpListener {
|
|||||||
private int httpServerPort;
|
private int httpServerPort;
|
||||||
|
|
||||||
private String responseAddress;
|
private String responseAddress;
|
||||||
|
|
||||||
|
private boolean strict;
|
||||||
|
|
||||||
|
private boolean traceupnp;
|
||||||
|
|
||||||
|
private boolean vTwoCompatibility;
|
||||||
|
|
||||||
public UpnpListener(BridgeSettings theSettings) {
|
public UpnpListener(BridgeSettings theSettings) {
|
||||||
super();
|
super();
|
||||||
upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort());
|
upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort());
|
||||||
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
||||||
responseAddress = theSettings.getUpnpConfigAddress();
|
responseAddress = theSettings.getUpnpConfigAddress();
|
||||||
|
strict = theSettings.isUpnpStrict();
|
||||||
|
traceupnp = theSettings.isTraceupnp();
|
||||||
|
vTwoCompatibility = theSettings.isVtwocompatibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startListening(){
|
public void startListening(){
|
||||||
log.info("Starting UPNP Discovery Listener");
|
log.info("UPNP Discovery Listener starting....");
|
||||||
|
|
||||||
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
|
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
|
||||||
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
|
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
|
||||||
@@ -46,7 +55,10 @@ public class UpnpListener {
|
|||||||
|
|
||||||
while (addrs.hasMoreElements()) {
|
while (addrs.hasMoreElements()) {
|
||||||
InetAddress addr = addrs.nextElement();
|
InetAddress addr = addrs.nextElement();
|
||||||
log.debug(name + " ... has addr " + addr);
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: " + name + " ... has addr " + addr);
|
||||||
|
else
|
||||||
|
log.debug(name + " ... has addr " + addr);
|
||||||
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
||||||
IPsPerNic++;
|
IPsPerNic++;
|
||||||
}
|
}
|
||||||
@@ -54,23 +66,33 @@ public class UpnpListener {
|
|||||||
log.debug("Checking " + name + " to our interface set");
|
log.debug("Checking " + name + " to our interface set");
|
||||||
if (IPsPerNic > 0) {
|
if (IPsPerNic > 0) {
|
||||||
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
||||||
log.debug("Adding " + name + " to our interface set");
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: Adding " + name + " to our interface set");
|
||||||
|
else
|
||||||
|
log.debug("Adding " + name + " to our interface set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("UPNP Discovery Listener running and ready....");
|
||||||
|
|
||||||
while(true){ //trigger shutdown here
|
while(true){ //trigger shutdown here
|
||||||
byte[] buf = new byte[1024];
|
byte[] buf = new byte[1024];
|
||||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
upnpMulticastSocket.receive(packet);
|
upnpMulticastSocket.receive(packet);
|
||||||
String packetString = new String(packet.getData());
|
String packetString = new String(packet.getData());
|
||||||
|
if(packetString != null && packetString.contains("M-SEARCH")) {
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: 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)){
|
if(isSSDPDiscovery(packetString)){
|
||||||
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
|
||||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("UpnpListener encountered an error. Shutting down", e);
|
log.error("UpnpListener encountered an error opening sockets. Shutting down", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
log.info("UPNP Discovery Listener Stopped");
|
log.info("UPNP Discovery Listener Stopped");
|
||||||
@@ -83,23 +105,54 @@ public class UpnpListener {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected boolean isSSDPDiscovery(String body){
|
protected boolean isSSDPDiscovery(String body){
|
||||||
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){
|
// log.debug("Check if this is a MAN ssdp-discover packet for a upnp basic device: " + body);
|
||||||
return true;
|
//Only respond to discover request for upnp basic device from echo, the others are for the wemo
|
||||||
|
if(body != null && body.contains("M-SEARCH") && body.contains("\"ssdp:discover\"")){
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message.");
|
||||||
|
if(strict && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"") && (body.contains("ST: urn:schemas-upnp-org:device:basic:1") || body.contains("ST: upnp:rootdevice") || body.contains("ST: ssdp:all")))
|
||||||
|
{
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!strict || vTwoCompatibility)
|
||||||
|
{
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to not be valid - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||||
"EXT:\r\n" +
|
"EXT:\r\n" +
|
||||||
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" +
|
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||||
|
"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" +
|
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
|
||||||
"01-NLS: %s\r\n" +
|
"01-NLS: %s\r\n" +
|
||||||
"ST: urn:schemas-upnp-org:device:basic:1\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";
|
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
|
||||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||||
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
String discoveryResponse = null;
|
||||||
log.debug("sndUpnpResponse: " + discoveryResponse);
|
if(vTwoCompatibility)
|
||||||
|
discoveryResponse = String.format(discoveryTemplateVTwo, responseAddress, httpServerPort, getRandomUUIDString());
|
||||||
|
else
|
||||||
|
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
||||||
|
else
|
||||||
|
log.debug("sendUpnpResponse: " + discoveryResponse);
|
||||||
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
||||||
socket.send(response);
|
socket.send(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ public class UpnpSettingsResource {
|
|||||||
private static final String UPNP_CONTEXT = "/upnp";
|
private static final String UPNP_CONTEXT = "/upnp";
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
|
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
|
||||||
|
|
||||||
|
private BridgeSettings theSettings;
|
||||||
|
|
||||||
private String hueTemplate = "<?xml version=\"1.0\"?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
|
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
|
||||||
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
|
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
|
||||||
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
|
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
|
||||||
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
||||||
@@ -25,8 +27,8 @@ public class UpnpSettingsResource {
|
|||||||
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n"
|
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n"
|
||||||
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n"
|
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n"
|
||||||
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
|
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
|
||||||
+ "<modelURL>http://www.bwssystems.com/ha-bridge</modelURL>\n"
|
+ "<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n"
|
||||||
+ "<serialNumber>01189998819991197253</serialNumber>\n"
|
+ "<serialNumber>0017880ae670</serialNumber>\n"
|
||||||
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
|
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
|
||||||
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
|
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
|
||||||
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
|
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
|
||||||
@@ -38,28 +40,97 @@ public class UpnpSettingsResource {
|
|||||||
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
|
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
|
||||||
+ "</root>\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) {
|
public UpnpSettingsResource(BridgeSettings theSettings) {
|
||||||
super();
|
super();
|
||||||
setupListener(theSettings);
|
this.theSettings = theSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupListener (BridgeSettings theSettings) {
|
public void setupServer() {
|
||||||
// http://ip_address:port/upnp/:id/setup.xml which returns the xml configuration for the location of the hue emulator
|
log.info("Hue description service started....");
|
||||||
get(UPNP_CONTEXT + "/:id/setup.xml", "application/xml", (request, response) -> {
|
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
|
||||||
log.info("upnp device settings requested: " + request.params(":id") + " from " + request.ip());
|
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
|
if(theSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
||||||
|
else
|
||||||
|
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
||||||
String portNumber = Integer.toString(request.port());
|
String portNumber = Integer.toString(request.port());
|
||||||
String filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
String filledTemplate = null;
|
||||||
log.debug("upnp device settings response: " + filledTemplate);
|
if(theSettings.isVtwocompatibility())
|
||||||
response.status(201);
|
filledTemplate = String.format(hueTemplateVTwo, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||||
|
else
|
||||||
|
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||||
|
if(theSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: upnp device settings response: " + filledTemplate);
|
||||||
|
else
|
||||||
|
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");
|
||||||
|
// response.header("Expires", "Mon, 1 Aug 2011 09:00:00 GMT");
|
||||||
|
// response.header("Connection", "close"); // Not sure if the server will actually close the connections by just setting the header
|
||||||
|
// response.header("Access-Control-Max-Age", "0");
|
||||||
|
// response.header("Access-Control-Allow-Origin", "*");
|
||||||
|
// response.header("Access-Control-Allow-Credentials", "true");
|
||||||
|
// response.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
|
||||||
|
// response.header("Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
// response.header("Content-Type", "application/xml; charset=utf-8");
|
||||||
|
response.type("application/xml; charset=utf-8");
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
return filledTemplate;
|
return filledTemplate;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// http://ip_address:port/upnp/settings which returns the bridge configuration settings
|
// http://ip_address:port/upnp/settings which returns the bridge configuration settings
|
||||||
get(UPNP_CONTEXT + "/settings", "application/xml", (request, response) -> {
|
get(UPNP_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||||
log.debug("bridge settings requested from " + request.ip());
|
log.debug("bridge settings requested from " + request.ip());
|
||||||
|
|
||||||
response.status(201);
|
response.status(200);
|
||||||
|
|
||||||
return theSettings;
|
return theSettings;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|||||||
@@ -26,14 +26,19 @@ public class VeraInfo {
|
|||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
||||||
private String veraAddressString;
|
private String veraAddressString;
|
||||||
|
private Boolean validVera;
|
||||||
|
|
||||||
public VeraInfo(String addressString) {
|
public VeraInfo(String addressString, Boolean isValidVera) {
|
||||||
super();
|
super();
|
||||||
httpClient = HttpClients.createMinimal();
|
httpClient = HttpClients.createMinimal();
|
||||||
veraAddressString = addressString;
|
veraAddressString = addressString;
|
||||||
|
validVera = isValidVera;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sdata getSdata() {
|
public Sdata getSdata() {
|
||||||
|
if(!validVera)
|
||||||
|
return new Sdata();
|
||||||
|
|
||||||
String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
|
String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
|
||||||
String theData;
|
String theData;
|
||||||
|
|
||||||
@@ -57,27 +62,37 @@ public class VeraInfo {
|
|||||||
Device theDevice = null;
|
Device theDevice = null;
|
||||||
while (theIterator.hasNext()) {
|
while (theIterator.hasNext()) {
|
||||||
theDevice = theIterator.next();
|
theDevice = theIterator.next();
|
||||||
theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName());
|
if(theDevice.getRoom() != null && roomMap.get(theDevice.getRoom()) != null)
|
||||||
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName());
|
||||||
|
else
|
||||||
|
theDevice.setRoom("no room");
|
||||||
|
|
||||||
|
if(theDevice.getCategory() != null && categoryMap.get(theDevice.getCategory()) != null)
|
||||||
|
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
||||||
|
else
|
||||||
|
theDevice.setCategory("<unknown>");
|
||||||
}
|
}
|
||||||
|
|
||||||
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
||||||
Scene theScene = null;
|
Scene theScene = null;
|
||||||
while (theSecneIter.hasNext()) {
|
while (theSecneIter.hasNext()) {
|
||||||
theScene = theSecneIter.next();
|
theScene = theSecneIter.next();
|
||||||
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
if(theScene.getRoom() != null && roomMap.get(theScene.getRoom()) != null)
|
||||||
|
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
||||||
|
else
|
||||||
|
theScene.setRoom("no room");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function executes the url against the vera
|
// This function executes the url against the vera
|
||||||
protected String doHttpGETRequest(String url) {
|
protected String doHttpGETRequest(String url) {
|
||||||
log.info("calling GET on URL: " + url);
|
log.debug("calling GET on URL: " + url);
|
||||||
HttpGet httpGet = new HttpGet(url);
|
HttpGet httpGet = new HttpGet(url);
|
||||||
try {
|
try {
|
||||||
HttpResponse response = httpClient.execute(httpGet);
|
HttpResponse response = httpClient.execute(httpGet);
|
||||||
String theContent = EntityUtils.toString(response.getEntity()); //read content for data
|
String theContent = EntityUtils.toString(response.getEntity()); //read content for data
|
||||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
log.info("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
if(response.getStatusLine().getStatusCode() == 200){
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
return theContent;
|
return theContent;
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/main/resources/public/css/main.css
Normal file
11
src/main/resources/public/css/main.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
body {
|
||||||
|
padding-top: 60px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortorder:after {
|
||||||
|
content: '\25b2';
|
||||||
|
}
|
||||||
|
.sortorder.reverse:after {
|
||||||
|
content: '\25bc';
|
||||||
|
}
|
||||||
@@ -5,12 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>HA Bridge</title>
|
<title>HA Bridge</title>
|
||||||
<style>
|
<link href="css/main.css" rel="stylesheet">
|
||||||
body {
|
|
||||||
padding-top: 60px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
@@ -35,13 +30,13 @@
|
|||||||
<li class="active"><a href="#">Home</a></li>
|
<li class="active"><a href="#">Home</a></li>
|
||||||
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
|
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a id="dropdownMenu1" href="#" class="dropdown-toggle"
|
<a id="dropdownMenu1" href="" class="dropdown-toggle"
|
||||||
data-toggle="dropdown" role="button" aria-haspopup="true"
|
data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||||
aria-expanded="false">About <span class="caret"></span></a>
|
aria-expanded="false">About <span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<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.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="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
||||||
<li><a href="#">HA Bridge Version 0.3.0</a></li>
|
<li><a href="">HA Bridge Version 0.4.9</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ app.config(function ($routeProvider) {
|
|||||||
|
|
||||||
app.run( function (bridgeService) {
|
app.run( function (bridgeService) {
|
||||||
bridgeService.loadBridgeSettings();
|
bridgeService.loadBridgeSettings();
|
||||||
|
bridgeService.updateShowVera();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.factory('BridgeSettings', function() {
|
app.factory('BridgeSettings', function() {
|
||||||
@@ -36,6 +37,9 @@ app.factory('BridgeSettings', function() {
|
|||||||
BridgeSettings.upnpdevicedb = "";
|
BridgeSettings.upnpdevicedb = "";
|
||||||
BridgeSettings.upnpresponseport = "";
|
BridgeSettings.upnpresponseport = "";
|
||||||
BridgeSettings.veraaddress = "";
|
BridgeSettings.veraaddress = "";
|
||||||
|
BridgeSettings.upnpstrict = "";
|
||||||
|
BridgeSettings.traceupnp = "";
|
||||||
|
BridgeSettings.vtwocompatibility = "";
|
||||||
|
|
||||||
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
|
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
|
||||||
BridgeSettings.upnpconfigaddress = aconfigaddress;
|
BridgeSettings.upnpconfigaddress = aconfigaddress;
|
||||||
@@ -56,14 +60,23 @@ app.factory('BridgeSettings', function() {
|
|||||||
BridgeSettings.setveraaddress = function(averaaddress){
|
BridgeSettings.setveraaddress = function(averaaddress){
|
||||||
BridgeSettings.veraaddress = averaaddress;
|
BridgeSettings.veraaddress = averaaddress;
|
||||||
};
|
};
|
||||||
|
BridgeSettings.setupnpstrict = function(aupnpstrict){
|
||||||
|
BridgeSettings.upnpstrict = aupnpstrict;
|
||||||
|
};
|
||||||
|
BridgeSettings.settraceupnp = function(atraceupnp){
|
||||||
|
BridgeSettings.traceupnp = atraceupnp;
|
||||||
|
};
|
||||||
|
BridgeSettings.setvtwocompatibility = function(avtwocompatibility){
|
||||||
|
BridgeSettings.vtwocompatibility = avtwocompatibility;
|
||||||
|
};
|
||||||
|
|
||||||
return BridgeSettings;
|
return BridgeSettings;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.service('bridgeService', function ($http, BridgeSettings) {
|
app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.BridgeSettings = BridgeSettings;
|
self.BridgeSettings = BridgeSettings;
|
||||||
this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", devices: [], device: [], error: ""};
|
this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", devices: [], device: [], error: "", showVera: false};
|
||||||
|
|
||||||
this.viewDevices = function () {
|
this.viewDevices = function () {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
@@ -92,20 +105,37 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
self.BridgeSettings.setupnpdevicedb(response.data.upnpdevicedb);
|
self.BridgeSettings.setupnpdevicedb(response.data.upnpdevicedb);
|
||||||
self.BridgeSettings.setupnpresponseport(response.data.upnpresponseport);
|
self.BridgeSettings.setupnpresponseport(response.data.upnpresponseport);
|
||||||
self.BridgeSettings.setveraaddress(response.data.veraaddress);
|
self.BridgeSettings.setveraaddress(response.data.veraaddress);
|
||||||
|
self.BridgeSettings.settraceupnp(response.data.traceupnp);
|
||||||
|
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
|
||||||
|
self.BridgeSettings.setvtwocompatibility(response.data.vtwocompatibility);
|
||||||
|
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
|
||||||
|
self.state.showVera = false;
|
||||||
|
else
|
||||||
|
self.state.showVera = true;
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
$window.alert("Load Bridge Settings Error: " + error.data.message);
|
||||||
} else {
|
} else {
|
||||||
self.state.error = "If you're not seeing any settings, you may be running into problems with CORS. " +
|
$window.alert("Load Bridge Settings Error: unknown");
|
||||||
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
|
|
||||||
}
|
}
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.updateShowVera = function () {
|
||||||
|
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
|
||||||
|
this.state.showVera = false;
|
||||||
|
else
|
||||||
|
this.state.showVera = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.viewVeraDevices = function () {
|
this.viewVeraDevices = function () {
|
||||||
|
this.state.error = "";
|
||||||
|
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||||
|
return;
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
return $http.get(this.state.base + "/vera/devices").then(
|
return $http.get(this.state.base + "/vera/devices").then(
|
||||||
function (response) {
|
function (response) {
|
||||||
@@ -113,70 +143,78 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
$window.alert("Get Vera Devices Error: " + error.data.message);
|
||||||
} else {
|
} else {
|
||||||
self.state.error = "If you're not seeing any address, you may be running into problems with CORS. " +
|
$window.alert("Get Vera Devices Error: unknown");
|
||||||
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
|
|
||||||
}
|
}
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.viewVeraScenes = function () {
|
this.viewVeraScenes = function () {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
|
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||||
|
return;
|
||||||
return $http.get(this.state.base + "/vera/scenes").then(
|
return $http.get(this.state.base + "/vera/scenes").then(
|
||||||
function (response) {
|
function (response) {
|
||||||
self.state.verascenes = response.data;
|
self.state.verascenes = response.data;
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
$window.alert("Get Vera Scenes Error: " + error.data.message);
|
||||||
} else {
|
} else {
|
||||||
self.state.error = "If you're not seeing any address, you may be running into problems with CORS. " +
|
$window.alert("Get Vera Scenes Error: unknown");
|
||||||
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
|
|
||||||
}
|
}
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addDevice = function (id, name, type, onUrl, offUrl) {
|
this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
if (id) {
|
if (id) {
|
||||||
var putUrl = this.state.base + "/" + id;
|
var putUrl = this.state.base + "/" + id;
|
||||||
return $http.put(putUrl, {
|
return $http.put(putUrl, {
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
deviceType: "switch",
|
deviceType: type,
|
||||||
onUrl: onUrl,
|
onUrl: onUrl,
|
||||||
offUrl: offUrl
|
offUrl: offUrl,
|
||||||
|
httpVerb: httpVerb,
|
||||||
|
contentType: contentType,
|
||||||
|
contentBody: contentBody,
|
||||||
|
contentBodyOff: contentBodyOff
|
||||||
}).then(
|
}).then(
|
||||||
function (response) {
|
function (response) {
|
||||||
self.viewDevices();
|
self.viewDevices();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
$window.alert("Edit Device Error: " + error.data.message);
|
||||||
}
|
}
|
||||||
console.log(error);
|
$window.alert("Edit Device Error: unknown");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if(type == null || type == "")
|
||||||
|
type = "switch";
|
||||||
return $http.post(this.state.base, {
|
return $http.post(this.state.base, {
|
||||||
name: name,
|
name: name,
|
||||||
deviceType: "switch",
|
deviceType: type,
|
||||||
onUrl: onUrl,
|
onUrl: onUrl,
|
||||||
offUrl: offUrl
|
offUrl: offUrl,
|
||||||
|
httpVerb: httpVerb,
|
||||||
|
contentType: contentType,
|
||||||
|
contentBody: contentBody,
|
||||||
|
contentBodyOff: contentBodyOff
|
||||||
}).then(
|
}).then(
|
||||||
function (response) {
|
function (response) {
|
||||||
self.viewDevices();
|
self.viewDevices();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
$window.alert("Add new Device Error: " + error.data.message);
|
||||||
}
|
}
|
||||||
console.log(error);
|
$window.alert("Add new Device Error: unknown");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -192,55 +230,120 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
if (error.data) {
|
if (error.data) {
|
||||||
self.state.error = error.data.message;
|
self.state.error = error.data.message;
|
||||||
}
|
}
|
||||||
console.log(error);
|
$window.alert("Delete Device Error: unknown");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.editDevice = function (id, name, onUrl, offUrl) {
|
this.editDevice = function (id, name, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||||
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl};
|
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl, httpVerb: httpVerb, contentType: contentType, contentBody: contentBody, contentBodyOff: contentBodyOff};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller('ViewingController', function ($scope, $location, bridgeService, BridgeSettings) {
|
app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, BridgeSettings) {
|
||||||
|
|
||||||
$scope.BridgeSettings = bridgeService.BridgeSettings;
|
$scope.BridgeSettings = bridgeService.BridgeSettings;
|
||||||
bridgeService.viewDevices();
|
bridgeService.viewDevices();
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
|
bridgeService.updateShowVera();
|
||||||
|
$scope.predicate = '';
|
||||||
|
$scope.reverse = true;
|
||||||
|
$scope.order = function(predicate) {
|
||||||
|
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
||||||
|
$scope.predicate = predicate;
|
||||||
|
};
|
||||||
$scope.deleteDevice = function (device) {
|
$scope.deleteDevice = function (device) {
|
||||||
bridgeService.deleteDevice(device.id);
|
bridgeService.deleteDevice(device.id);
|
||||||
};
|
};
|
||||||
$scope.testUrl = function (url) {
|
$scope.testUrl = function (device, type) {
|
||||||
window.open(url, "_blank");
|
if(type == "on") {
|
||||||
|
if(device.httpVerb == "PUT")
|
||||||
|
$http.put(device.onUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else if(device.httpVerb == "POST")
|
||||||
|
$http.post(device.onUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else
|
||||||
|
window.open(device.onUrl, "_blank");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(device.httpVerb == "PUT")
|
||||||
|
$http.put(device.offUrl, device.contentBodyOff).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else if(device.httpVerb == "POST")
|
||||||
|
$http.post(device.offUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else
|
||||||
|
window.open(device.offUrl, "_blank");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
$scope.setBridgeUrl = function (url) {
|
$scope.setBridgeUrl = function (url) {
|
||||||
bridgeService.state.base = url;
|
bridgeService.state.base = url;
|
||||||
bridgeService.viewDevices();
|
bridgeService.viewDevices();
|
||||||
};
|
};
|
||||||
$scope.editDevice = function (device) {
|
$scope.editDevice = function (device) {
|
||||||
bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl);
|
bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl, device.httpVerb, device.contentType, device.contentBody, device.contentBodyOff);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller('AddingController', function ($scope, bridgeService, BridgeSettings) {
|
app.controller('AddingController', function ($scope, $location, $http, bridgeService, BridgeSettings) {
|
||||||
|
|
||||||
$scope.device = {id: "", name: "", type: "switch", onUrl: "", offUrl: ""};
|
$scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
|
||||||
$scope.vera = {base: "", port: "3480", id: ""};
|
$scope.vera = {base: "", port: "3480", id: ""};
|
||||||
$scope.vera.base = "http://" + BridgeSettings.veraaddress;
|
$scope.vera.base = "http://" + BridgeSettings.veraaddress;
|
||||||
bridgeService.device = $scope.device;
|
bridgeService.device = $scope.device;
|
||||||
bridgeService.viewVeraDevices();
|
bridgeService.viewVeraDevices();
|
||||||
bridgeService.viewVeraScenes();
|
bridgeService.viewVeraScenes();
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
|
bridgeService.updateShowVera();
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
$scope.predicate = '';
|
||||||
$scope.buildUrlsUsingDevice = function () {
|
$scope.reverse = true;
|
||||||
|
$scope.device_dim_control = "";
|
||||||
|
$scope.order = function(predicate) {
|
||||||
|
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
||||||
|
$scope.predicate = predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.buildUrlsUsingDevice = function (dim_control) {
|
||||||
if ($scope.vera.base.indexOf("http") < 0) {
|
if ($scope.vera.base.indexOf("http") < 0) {
|
||||||
$scope.vera.base = "http://" + $scope.vera.base;
|
$scope.vera.base = "http://" + $scope.vera.base;
|
||||||
}
|
}
|
||||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ $scope.vera.id;
|
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||||
|
+ $scope.vera.id
|
||||||
|
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
|
||||||
|
+ dim_control;
|
||||||
|
else
|
||||||
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
|
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||||
|
+ $scope.vera.id;
|
||||||
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
||||||
+ $scope.vera.id;
|
+ $scope.vera.id;
|
||||||
@@ -250,6 +353,7 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
|
|||||||
if ($scope.vera.base.indexOf("http") < 0) {
|
if ($scope.vera.base.indexOf("http") < 0) {
|
||||||
$scope.vera.base = "http://" + $scope.vera.base;
|
$scope.vera.base = "http://" + $scope.vera.base;
|
||||||
}
|
}
|
||||||
|
$scope.device.deviceType = "scene";
|
||||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||||
+ $scope.vera.id;
|
+ $scope.vera.id;
|
||||||
@@ -258,14 +362,22 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
|
|||||||
+ $scope.vera.id;
|
+ $scope.vera.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildDeviceUrls = function (veradevice) {
|
$scope.buildDeviceUrls = function (veradevice, dim_control) {
|
||||||
if ($scope.vera.base.indexOf("http") < 0) {
|
if ($scope.vera.base.indexOf("http") < 0) {
|
||||||
$scope.vera.base = "http://" + $scope.vera.base;
|
$scope.vera.base = "http://" + $scope.vera.base;
|
||||||
}
|
}
|
||||||
|
$scope.device.deviceType = "switch";
|
||||||
$scope.device.name = veradevice.name;
|
$scope.device.name = veradevice.name;
|
||||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ veradevice.id;
|
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||||
|
+ veradevice.id
|
||||||
|
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
|
||||||
|
+ dim_control;
|
||||||
|
else
|
||||||
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
|
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||||
|
+ veradevice.id;
|
||||||
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
||||||
+ veradevice.id;
|
+ veradevice.id;
|
||||||
@@ -275,6 +387,7 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
|
|||||||
if ($scope.vera.base.indexOf("http") < 0) {
|
if ($scope.vera.base.indexOf("http") < 0) {
|
||||||
$scope.vera.base = "http://" + $scope.vera.base;
|
$scope.vera.base = "http://" + $scope.vera.base;
|
||||||
}
|
}
|
||||||
|
$scope.device.deviceType = "scene";
|
||||||
$scope.device.name = verascene.name;
|
$scope.device.name = verascene.name;
|
||||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||||
@@ -285,17 +398,65 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.testUrl = function (url) {
|
$scope.testUrl = function (url) {
|
||||||
window.open(url, "_blank");
|
if(type == "on") {
|
||||||
|
if(device.httpVerb == "PUT")
|
||||||
|
$http.put(device.onUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else if(device.httpVerb == "POST")
|
||||||
|
$http.post(device.onUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else
|
||||||
|
window.open(device.onUrl, "_blank");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(device.httpVerb == "PUT")
|
||||||
|
$http.put(device.offUrl, device.contentBodyOff).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else if(device.httpVerb == "POST")
|
||||||
|
$http.post(device.offUrl, device.contentBody).then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else
|
||||||
|
window.open(device.offUrl, "_blank");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.addDevice = function () {
|
$scope.addDevice = function () {
|
||||||
bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl).then(
|
bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl, $scope.device.httpVerb, $scope.device.contentType, $scope.device.contentBody, $scope.device.contentBodyOff).then(
|
||||||
function () {
|
function () {
|
||||||
$scope.device.id = "";
|
$scope.device.id = "";
|
||||||
$scope.device.name = "";
|
$scope.device.name = "";
|
||||||
$scope.device.onUrl = "";
|
$scope.device.onUrl = "";
|
||||||
$scope.device.deviceType = "switch";
|
$scope.device.deviceType = "switch";
|
||||||
$scope.device.offUrl = "";
|
$scope.device.offUrl = "";
|
||||||
|
$scope.device.httpVerb = null;
|
||||||
|
$scope.device.contentType = null;
|
||||||
|
$scope.device.contentBody = null;
|
||||||
|
$scope.device.contentBodyOff = null;
|
||||||
|
$location.path('/#');
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<h2>Configuration <a class="btn btn-primary pull-right" href="#/editor"><i
|
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
||||||
class="icon-plis-sign icon-white"></i> Manual Add</a>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<a class="btn btn-primary pull-right" href="#/verascenes"><i
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
class="icon-plis-sign icon-white"></i> Vera Scenes</a>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
<a class="btn btn-primary pull-right" href="#/veradevices"><i
|
</ul>
|
||||||
class="icon-plis-sign icon-white"></i> Vera Devices</a>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -55,6 +53,18 @@
|
|||||||
<td>vera.address</td>
|
<td>vera.address</td>
|
||||||
<td>{{BridgeSettings.veraaddress}}</td>
|
<td>{{BridgeSettings.veraaddress}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>upnp.strict</td>
|
||||||
|
<td>{{BridgeSettings.upnpstrict}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>trace.upnp</td>
|
||||||
|
<td>{{BridgeSettings.traceupnp}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>vtwo.compatibility</td>
|
||||||
|
<td>{{BridgeSettings.vtwocompatibility}}</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +82,6 @@
|
|||||||
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Current devices</h2>
|
<h2 class="panel-title">Current devices</h2>
|
||||||
@@ -80,21 +89,27 @@
|
|||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>
|
||||||
<th>Name</th>
|
<a href="" ng-click="order('id')">ID</a>
|
||||||
<th>Type</th>
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span></th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('name')">Name</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span></th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('deviceType')">Type</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="device in bridge.devices">
|
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
||||||
<td>{{device.id}}</td>
|
<td>{{device.id}}</td>
|
||||||
<td>{{device.name}}</td>
|
<td>{{device.name}}</td>
|
||||||
<td>{{device.deviceType}}</td>
|
<td>{{device.deviceType}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-info" type="submit"
|
<button class="btn btn-info" type="submit"
|
||||||
ng-click="testUrl(device.onUrl)">Test ON</button>
|
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||||
<button class="btn btn-info" type="submit"
|
<button class="btn btn-info" type="submit"
|
||||||
ng-click="testUrl(device.offUrl)">Test OFF</button>
|
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||||
<button class="btn btn-warning" type="submit"
|
<button class="btn btn-warning" type="submit"
|
||||||
ng-click="editDevice(device)">Edit</button>
|
ng-click="editDevice(device)">Edit</button>
|
||||||
<button class="btn btn-danger" type="submit"
|
<button class="btn btn-danger" type="submit"
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<h2>
|
<ul class="nav nav-pills" role="tablist">
|
||||||
Device Editor <a class="btn btn-primary pull-right" href="/">
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
Configuration</a>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
</h2>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -22,26 +25,96 @@
|
|||||||
Update Device</button>
|
Update Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
URL </label>
|
URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
ng-click="testUrl(device, 'on')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
for="device-off-url">Off URL </label>
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
ng-click="testUrl(device, 'off')">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">
|
||||||
|
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
|
||||||
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
|
||||||
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="application/atom+xml">application/atom+xml</option>
|
||||||
|
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||||
|
<option value="application/json">application/json</option>
|
||||||
|
<option value="application/octet-stream">application/octet-stream</option>
|
||||||
|
<option value="application/svg+xml">application/svg+xml</option>
|
||||||
|
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||||
|
<option value="application/xml">application/xml</option>
|
||||||
|
<option value="*">*</option>
|
||||||
|
<option value="multipart/form-data">multipart/form-data</option>
|
||||||
|
<option value="text/html">text/html</option>
|
||||||
|
<option value="text/plain">text/plain</option>
|
||||||
|
<option value="text/xml">text/xml</option>
|
||||||
|
<option value="*/*">*/*</option>
|
||||||
|
</select>
|
||||||
|
</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 On</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 On for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-content-body-off"
|
||||||
|
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<h2>
|
<ul class="nav nav-pills" role="tablist">
|
||||||
Manual Add <a class="btn btn-primary pull-right" href="/">
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
Configuration</a>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
</h2>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -40,11 +42,25 @@
|
|||||||
<input type="text" class="form-control" id="vera-id"
|
<input type="text" class="form-control" id="vera-id"
|
||||||
ng-model="vera.id" placeholder="ID">
|
ng-model="vera.id" placeholder="ID">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" ng-click="buildUrlsUsingDevice()"
|
</div>
|
||||||
class="col-xs-4 col-sm-2 btn btn-success">Generate Device
|
<div class="form-group">
|
||||||
|
<label class="col-xs-2 col-sm-2 control-label" for="device-dim-control">Device Dim Control</label>
|
||||||
|
|
||||||
|
<div class="col-xs-10 col-sm-2">
|
||||||
|
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
||||||
|
<option value="">none</option>
|
||||||
|
<option value="${intensity..byte}">Pass-thru Value</option>
|
||||||
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" ng-click="buildUrlsUsingDevice(device_dim_control)"
|
||||||
|
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device
|
||||||
URLs</button>
|
URLs</button>
|
||||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||||
class="col-xs-4 col-sm-2 btn btn-success">Generate Scene
|
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Scene
|
||||||
URLs</button>
|
URLs</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -59,6 +75,7 @@
|
|||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
<form class="form-horizontal" ng-submit="addDevice()">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -68,28 +85,99 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||||
Add Device</button>
|
Add Device</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
URL </label>
|
URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
ng-click="testUrl(device, 'on')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
for="device-off-url">Off URL </label>
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
ng-click="testUrl(device, 'off')">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">
|
||||||
|
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
|
||||||
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
|
||||||
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="application/atom+xml">application/atom+xml</option>
|
||||||
|
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||||
|
<option value="application/json">application/json</option>
|
||||||
|
<option value="application/octet-stream">application/octet-stream</option>
|
||||||
|
<option value="application/svg+xml">application/svg+xml</option>
|
||||||
|
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||||
|
<option value="application/xml">application/xml</option>
|
||||||
|
<option value="*">*</option>
|
||||||
|
<option value="multipart/form-data">multipart/form-data</option>
|
||||||
|
<option value="text/html">text/html</option>
|
||||||
|
<option value="text/plain">text/plain</option>
|
||||||
|
<option value="text/xml">text/xml</option>
|
||||||
|
<option value="*/*">*/*</option>
|
||||||
|
</select>
|
||||||
|
</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 On</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 On for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-content-body-off"
|
||||||
|
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<h2>
|
<ul class="nav nav-pills" role="tablist">
|
||||||
Vera Device <a class="btn btn-primary pull-right" href="/">
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
Configuration</a>
|
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
</h2>
|
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -10,26 +12,45 @@
|
|||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<p class="text-muted">You can select a Vera device and generate
|
<p class="text-muted">You can select a Vera device and generate
|
||||||
the add device box selections automatically.</p>
|
the add device box selections automatically.</p><p>Also, use this select menu for which type of dim
|
||||||
|
control you would like to be generated:
|
||||||
|
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
||||||
|
<option value="">none</option>
|
||||||
|
<option value="${intensity..byte}">Pass-thru Value</option>
|
||||||
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>
|
||||||
<th>Id</th>
|
<a href="" ng-click="order('name')">Name</a>
|
||||||
<th>Category</th>
|
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||||
<th>Room</th>
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('id')">Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('category')">Category</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'category'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="veradevice in bridge.veradevices">
|
<tr ng-repeat="veradevice in bridge.veradevices | orderBy:predicate:reverse">
|
||||||
<td>{{veradevice.name}}</td>
|
<td>{{veradevice.name}}</td>
|
||||||
<td>{{veradevice.id}}</td>
|
<td>{{veradevice.id}}</td>
|
||||||
<td>{{veradevice.category}}</td>
|
<td>{{veradevice.category}}</td>
|
||||||
<td>{{veradevice.room}}</td>
|
<td>{{veradevice.room}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(veradevice)">Generate
|
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
|
||||||
Device URLs</button>
|
Device URLs</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -56,26 +77,32 @@
|
|||||||
Add Device</button>
|
Add Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
URL </label>
|
URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
ng-click="testUrl(device, 'on')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
for="device-off-url">Off URL </label>
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
ng-click="testUrl(device, 'off')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<h2>
|
<ul class="nav nav-pills" role="tablist">
|
||||||
Vera Scene <a class="btn btn-primary pull-right" href="/">
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
Configuration</a>
|
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
</h2>
|
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -15,13 +17,22 @@
|
|||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>
|
||||||
<th>Id</th>
|
<a href="" ng-click="order('name')">Name</a>
|
||||||
<th>Room</th>
|
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('id')">Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="verascene in bridge.verascenes">
|
<tr ng-repeat="verascene in bridge.verascenes | orderBy:predicate:reverse">
|
||||||
<td>{{verascene.name}}</td>
|
<td>{{verascene.name}}</td>
|
||||||
<td>{{verascene.id}}</td>
|
<td>{{verascene.id}}</td>
|
||||||
<td>{{verascene.room}}</td>
|
<td>{{verascene.room}}</td>
|
||||||
@@ -54,26 +65,32 @@
|
|||||||
Add Scene</button>
|
Add Scene</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
URL </label>
|
URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
ng-click="testUrl(device, 'on')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
for="device-off-url">Off URL </label>
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
ng-click="testUrl(device, 'off')">Test</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.test;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class TestBean {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
InetAddress address = InetAddress.getLocalHost();
|
|
||||||
System.out.println("Using InetAddress");
|
|
||||||
System.out.println("Host Address: "+ address.getHostAddress());
|
|
||||||
System.out.println("Host Name: "+ address.getHostName());
|
|
||||||
System.out.println("Address List: "+ Arrays.toString(InetAddress.getAllByName(address.getHostName())));
|
|
||||||
System.out.println("CanonicalHostName: "+ address.getCanonicalHostName());
|
|
||||||
System.out.println("Address: "+ address.getAddress());
|
|
||||||
System.out.println("LocalHost: "+ address.getLocalHost());
|
|
||||||
System.out.println("LoopbackAddress: "+ address.getLoopbackAddress());
|
|
||||||
|
|
||||||
String os = "os.name";
|
|
||||||
String version = "os.version";
|
|
||||||
String arch = "os.arch";
|
|
||||||
System.out.println("Name of the OS: "+ System.getProperty(os));
|
|
||||||
System.out.println("Version of the OS: "+ System.getProperty(version));
|
|
||||||
System.out.println("Architecture of the OS: "+ System.getProperty(arch));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package demo;
|
|
||||||
|
|
||||||
import com.bwssystems.HABridge.HABridge;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dummy test holder
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DemoApplicationTests {
|
|
||||||
|
|
||||||
public void contextLoads() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user