mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e29f12905d | ||
|
|
408b79d5d8 | ||
|
|
bf5ad2e23c | ||
|
|
59f1db285d | ||
|
|
203ed0b5d3 | ||
|
|
b443d16a11 | ||
|
|
295b1e1a30 | ||
|
|
c872f3543d | ||
|
|
23f2d2716d | ||
|
|
7c1d6e40b8 | ||
|
|
c5fbd5d1f0 | ||
|
|
aebde7ee48 | ||
|
|
c8fb93eeb6 | ||
|
|
1602ed004a | ||
|
|
7514e36edb | ||
|
|
2789d8c180 | ||
|
|
af1777aeb3 | ||
|
|
fc2d587e1a |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@ data
|
|||||||
.idea
|
.idea
|
||||||
/target/
|
/target/
|
||||||
/.settings/
|
/.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>
|
||||||
40
README.md
40
README.md
@@ -1,33 +1,37 @@
|
|||||||
# ha-bridge
|
# ha-bridge
|
||||||
Emulates philips hue api to other home automation gateways. The Amazon echo now supports wemo and philips 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 Logitech Harmony Hub, 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
|
||||||
```
|
```
|
||||||
Otherwise go to http://www.bwssystems.com/apps.html to download the latest jar file.
|
Otherwise, downloads are available at https://github.com/bwssytems/ha-bridge/releases.
|
||||||
## Run
|
## Run
|
||||||
Then locate the jar and start the server with:
|
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 -Dharmony.address=X.Y.Z.A -Dharmony.user=myself -Dharmony.pwd=passwd ha-bridge-0.X.Y.jar
|
||||||
```
|
```
|
||||||
## Available Arguments
|
## Available Arguments
|
||||||
### -Dvera.address=`<ip address>`
|
### -Dvera.address=`<ip address>`
|
||||||
The argument for the vera address should be given as it the system does not have a way to find the address. Supply -Dvera.address=X.Y.Z.A on the command line to provide it.
|
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>`
|
### -Dupnp.config.address=`<ip address>`
|
||||||
The server defaults to the first available address on the host. Replace the -Dupnp.config.address=`<ip address>` value with the server ipv4 address you would like to use.
|
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>`
|
### -Dserver.port=`<port>`
|
||||||
The server defaults to running on port 8080. If you're already running a server (like openHAB) on 8080, -Dserver.port=`<port>` on the command line.
|
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>`
|
### -Dupnp.device.db=`<filepath>`
|
||||||
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify -Dupnp.devices.db=`<directory>/<filename> or <filename>` if it is the same directory.
|
The default 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>`
|
### -Dupnp.response.port=`<port>`
|
||||||
The upnp response port that will be used. The default is 50000.
|
The upnp response port that will be used. The default is 50000.
|
||||||
|
### -Dharmony.address=`<ip address>`
|
||||||
|
The argument for the Harmony Hub address should be given as the system does not have a way to find the address. Supply -Dharmony.address=X.Y.Z.A on the command line to provide it. If a Harmony Hub is not used, do not set it.
|
||||||
|
### -Dharmony.user=`<username>`
|
||||||
|
The user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub Features, provide -Dharmony.user=`<username>` on the command line.
|
||||||
|
### -Dharmony.pwd=`<password>`
|
||||||
|
The password for the user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub Features, provide -Dharmony.pwd=`<password>` on the command line.
|
||||||
### -Dupnp.strict=`<true|false>`
|
### -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=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>`
|
### -Dtrace.upnp=`<true|false>`
|
||||||
Turn on tracing for upnp discovery messages. The default is false.
|
Turn on tracing for upnp discovery messages. The default is false.
|
||||||
### -Dvtwo.compatibility=`<true|false>`
|
|
||||||
Turns on compatibility for upnp detection and response as it was in the original version of amazon-echo-ha-bridge. The default is true.
|
|
||||||
## Web Config
|
## Web Config
|
||||||
Configure by going to the url for the host you are running on or localhost with port you have assigned:
|
Configure by going to the url for the host you are running on or localhost with port you have assigned:
|
||||||
```
|
```
|
||||||
@@ -44,8 +48,8 @@ POST http://host:8080/api/devices
|
|||||||
"offUrl" : "http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41"
|
"offUrl" : "http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Dimming
|
## Dimming and value passing control
|
||||||
Dimming is also supported by using the expessions ${intensity.percent} or ${intensity.byte} for 0-100 and 0-255 respectively.
|
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.
|
e.g.
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
@@ -61,9 +65,10 @@ See the echo's documentation for the dimming phrase.
|
|||||||
added optional fields
|
added optional fields
|
||||||
* contentType (currently un-validated)
|
* contentType (currently un-validated)
|
||||||
* httpVerb (POST/PUT/GET only supported)
|
* httpVerb (POST/PUT/GET only supported)
|
||||||
* contentBody your post/put body here
|
* contentBody your post/put body for onUrl here
|
||||||
|
* contentBodyOff your post/put body for offUrl here
|
||||||
|
|
||||||
This will allow control of any other application that may need more then GET.
|
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:
|
e.g:
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
@@ -73,10 +78,12 @@ e.g:
|
|||||||
"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}",
|
"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",
|
"contentType" : "application/json",
|
||||||
"httpVerb":"POST",
|
"httpVerb":"POST",
|
||||||
"contentBody" : "{\"fooBar\":\"baz\"}"
|
"contentBody" : "{\"fooBar\":\"baz_on\"}"
|
||||||
|
"contentBodyOff" : "{\"fooBar\":\"baz_off\"}"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Anything that takes an action as a result of an HTTP request will probably work - like putting Vera in and out of night mode:
|
## 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",
|
"name": "night mode",
|
||||||
@@ -95,4 +102,9 @@ To view or remove devices that Alexa knows about, you can use the mobile app Men
|
|||||||
To turn on debugging for the bridge, use the following extra parm in the command line:
|
To turn on debugging for the bridge, use the following extra parm in the command line:
|
||||||
```
|
```
|
||||||
-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG
|
-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG
|
||||||
|
```
|
||||||
|
## Development Mode
|
||||||
|
To turn on development mode so that it will not need an Harmony Hub for testing, use the following extra parm in the command line and the harmony ip and login info will not be needed:
|
||||||
|
```
|
||||||
|
java -jar -Ddev.mode=true ha-bridge-0.X.Y.jar
|
||||||
```
|
```
|
||||||
77
pom.xml
77
pom.xml
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>0.4.4</version>
|
<version>1.0.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera, using lightweight frameworks</description>
|
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub, using lightweight frameworks</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
@@ -17,7 +17,19 @@
|
|||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.bwssytems</groupId>
|
||||||
|
<artifactId>harmony-java-client</artifactId>
|
||||||
|
<version>1.0.8</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sparkjava</groupId>
|
<groupId>com.sparkjava</groupId>
|
||||||
<artifactId>spark-core</artifactId>
|
<artifactId>spark-core</artifactId>
|
||||||
@@ -53,9 +65,45 @@
|
|||||||
<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>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject</groupId>
|
||||||
|
<artifactId>guice</artifactId>
|
||||||
|
<version>4.0-beta4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.igniterealtime.smack</groupId>
|
||||||
|
<artifactId>smack-core</artifactId>
|
||||||
|
<version>4.0.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.igniterealtime.smack</groupId>
|
||||||
|
<artifactId>smack-debug</artifactId>
|
||||||
|
<version>4.0.7</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<includes>
|
||||||
|
<include>version.properties</include>
|
||||||
|
</includes>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>version.properties</exclude>
|
||||||
|
</excludes>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@@ -81,21 +129,20 @@
|
|||||||
<exclude>META-INF/services/**</exclude>
|
<exclude>META-INF/services/**</exclude>
|
||||||
<exclude>META-INF/DEPENDENCIES</exclude>
|
<exclude>META-INF/DEPENDENCIES</exclude>
|
||||||
<exclude>about_files/**</exclude>
|
<exclude>about_files/**</exclude>
|
||||||
<exclude>*.properties</exclude>
|
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>org.slf4j:*</artifact>
|
<artifact>org.slf4j:*</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>commons-logging:commons-logging</artifact>
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer
|
<transformer
|
||||||
|
|||||||
@@ -6,9 +6,12 @@ public class BridgeSettings {
|
|||||||
private String upnpresponseport;
|
private String upnpresponseport;
|
||||||
private String upnpdevicedb;
|
private String upnpdevicedb;
|
||||||
private String veraaddress;
|
private String veraaddress;
|
||||||
|
private String harmonyaddress;
|
||||||
|
private String harmonyuser;
|
||||||
|
private String harmonypwd;
|
||||||
private boolean upnpstrict;
|
private boolean upnpstrict;
|
||||||
private boolean traceupnp;
|
private boolean traceupnp;
|
||||||
private boolean vtwocompatibility;
|
private boolean devmode;
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
return upnpconfigaddress;
|
return upnpconfigaddress;
|
||||||
@@ -40,7 +43,24 @@ public class BridgeSettings {
|
|||||||
public void setVeraAddress(String veraAddress) {
|
public void setVeraAddress(String veraAddress) {
|
||||||
this.veraaddress = veraAddress;
|
this.veraaddress = veraAddress;
|
||||||
}
|
}
|
||||||
|
public String getHarmonyAddress() {
|
||||||
|
return harmonyaddress;
|
||||||
|
}
|
||||||
|
public void setHarmonyAddress(String harmonyaddress) {
|
||||||
|
this.harmonyaddress = harmonyaddress;
|
||||||
|
}
|
||||||
|
public String getHarmonyUser() {
|
||||||
|
return harmonyuser;
|
||||||
|
}
|
||||||
|
public void setHarmonyUser(String harmonyuser) {
|
||||||
|
this.harmonyuser = harmonyuser;
|
||||||
|
}
|
||||||
|
public String getHarmonyPwd() {
|
||||||
|
return harmonypwd;
|
||||||
|
}
|
||||||
|
public void setHarmonyPwd(String harmonypwd) {
|
||||||
|
this.harmonypwd = harmonypwd;
|
||||||
|
}
|
||||||
public boolean isUpnpStrict() {
|
public boolean isUpnpStrict() {
|
||||||
return upnpstrict;
|
return upnpstrict;
|
||||||
}
|
}
|
||||||
@@ -53,12 +73,24 @@ public class BridgeSettings {
|
|||||||
public void setTraceupnp(boolean traceupnp) {
|
public void setTraceupnp(boolean traceupnp) {
|
||||||
this.traceupnp = traceupnp;
|
this.traceupnp = traceupnp;
|
||||||
}
|
}
|
||||||
|
public boolean isDevMode() {
|
||||||
public boolean isVtwocompatibility() {
|
return devmode;
|
||||||
return vtwocompatibility;
|
|
||||||
}
|
}
|
||||||
public void setVtwocompatibility(boolean vtwocompatibility) {
|
public void setDevMode(boolean devmode) {
|
||||||
this.vtwocompatibility = vtwocompatibility;
|
this.devmode = devmode;
|
||||||
|
}
|
||||||
|
public Boolean isValidVera() {
|
||||||
|
if(this.veraaddress.contains(Configuration.DEFAULT_VERA_ADDRESS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidHarmony() {
|
||||||
|
if(this.harmonyaddress.contains(Configuration.DEFAULT_HARMONY_ADDRESS))
|
||||||
|
return false;
|
||||||
|
if(this.harmonypwd == null || this.harmonypwd == "")
|
||||||
|
return false;
|
||||||
|
if(this.harmonyuser == null || this.harmonyuser == "")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
11
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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 DEFAULT_HARMONY_ADDRESS = "1.1.1.1";
|
||||||
|
public final static String DEFAULT_HARMONY_USER = "";
|
||||||
|
public final static String DEFAULT_HARMONY_PWD = "";
|
||||||
|
public final static String DFAULT_WEB_PORT = "8080";
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ 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.harmony.HarmonyServer;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -33,13 +34,18 @@ public class HABridge {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||||
DeviceResource theResources;
|
DeviceResource theResources;
|
||||||
|
HarmonyServer myHarmonyServer;
|
||||||
HueMulator theHueMulator;
|
HueMulator theHueMulator;
|
||||||
UpnpSettingsResource theSettingResponder;
|
UpnpSettingsResource theSettingResponder;
|
||||||
UpnpListener theUpnpListener;
|
UpnpListener theUpnpListener;
|
||||||
InetAddress address;
|
InetAddress address;
|
||||||
String addressString;
|
String addressString;
|
||||||
BridgeSettings bridgeSettings;
|
BridgeSettings bridgeSettings;
|
||||||
|
Version theVersion;
|
||||||
|
|
||||||
|
theVersion = new Version();
|
||||||
|
|
||||||
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
|
||||||
//get ip address for upnp requests
|
//get ip address for upnp requests
|
||||||
try {
|
try {
|
||||||
address = InetAddress.getLocalHost();
|
address = InetAddress.getLocalHost();
|
||||||
@@ -50,28 +56,39 @@ public class HABridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings = new BridgeSettings();
|
||||||
|
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
||||||
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", "false")));
|
bridgeSettings.setHarmonyAddress(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS));
|
||||||
|
bridgeSettings.setHarmonyUser(System.getProperty("harmony.user", Configuration.DEFAULT_HARMONY_USER));
|
||||||
|
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_HARMONY_PWD));
|
||||||
|
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||||
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||||
bridgeSettings.setVtwocompatibility(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "true")));
|
bridgeSettings.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "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"));
|
|
||||||
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");
|
||||||
log.info("Starting setup....");
|
//setup the harmony connection if available
|
||||||
|
try {
|
||||||
|
myHarmonyServer = HarmonyServer.setup(bridgeSettings);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get harmony client setup, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// setup the class to handle the resource setup rest api
|
// setup the class to handle the resource setup rest api
|
||||||
theResources = new DeviceResource(bridgeSettings);
|
theResources = new DeviceResource(bridgeSettings, theVersion, myHarmonyServer.getMyHarmony());
|
||||||
// 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(), myHarmonyServer.getMyHarmony());
|
||||||
|
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();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,17 +73,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) {
|
||||||
@@ -101,20 +102,13 @@ public class DeviceResponse {
|
|||||||
deviceState.setEffect("none");
|
deviceState.setEffect("none");
|
||||||
deviceState.setAlert("none");
|
deviceState.setAlert("none");
|
||||||
deviceState.setBri(254);
|
deviceState.setBri(254);
|
||||||
deviceState.setHue(15823);
|
deviceState.setSat(254);
|
||||||
deviceState.setSat(88);
|
|
||||||
deviceState.setCt(313);
|
|
||||||
|
|
||||||
List<Double> xv = new LinkedList<>();
|
|
||||||
xv.add(Double.valueOf("0.4255"));
|
|
||||||
xv.add(Double.valueOf("0.3998"));
|
|
||||||
deviceState.setXy(xv);
|
|
||||||
deviceState.setColormode("ct");
|
|
||||||
response.setName(name);
|
response.setName(name);
|
||||||
response.setUniqueid(id);
|
response.setUniqueid(id);
|
||||||
response.setManufacturername("Philips");
|
response.setManufacturername("Philips");
|
||||||
response.setType("Extended color light");
|
response.setType("Dimmable light");
|
||||||
response.setModelid("LCT001");
|
response.setModelid("LWB004");
|
||||||
response.setSwversion("65003148");
|
response.setSwversion("65003148");
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class DeviceDescriptor{
|
|||||||
private String httpVerb;
|
private String httpVerb;
|
||||||
private String contentType;
|
private String contentType;
|
||||||
private String contentBody;
|
private String contentBody;
|
||||||
|
private String contentBodyOff;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@@ -75,6 +76,14 @@ public class DeviceDescriptor{
|
|||||||
public void setContentBody(String contentBody) {
|
public void setContentBody(String contentBody) {
|
||||||
this.contentBody = 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;
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +196,9 @@ public class DeviceRepository {
|
|||||||
} else if (name.equals("contentBody")) {
|
} else if (name.equals("contentBody")) {
|
||||||
deviceEntry.setContentBody(reader.nextString());
|
deviceEntry.setContentBody(reader.nextString());
|
||||||
log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody());
|
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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettings;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
import com.bwssystems.HABridge.JsonTransformer;
|
||||||
|
import com.bwssystems.HABridge.Version;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||||
|
import com.bwssystems.harmony.HarmonyHandler;
|
||||||
import com.bwssystems.luupRequests.Sdata;
|
import com.bwssystems.luupRequests.Sdata;
|
||||||
import com.bwssystems.vera.VeraInfo;
|
import com.bwssystems.vera.VeraInfo;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -31,12 +33,16 @@ public class DeviceResource {
|
|||||||
|
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
private VeraInfo veraInfo;
|
private VeraInfo veraInfo;
|
||||||
|
private Version version;
|
||||||
|
private HarmonyHandler myHarmonyHandler;
|
||||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||||
|
|
||||||
public DeviceResource(BridgeSettings theSettings) {
|
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHandler myHarmony) {
|
||||||
super();
|
super();
|
||||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
veraInfo = new VeraInfo(theSettings.getVeraAddress());
|
this.veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
||||||
|
this.myHarmonyHandler = myHarmony;
|
||||||
|
this.version = theVersion;
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +92,7 @@ public class DeviceResource {
|
|||||||
deviceEntry.setHttpVerb(device.getHttpVerb());
|
deviceEntry.setHttpVerb(device.getHttpVerb());
|
||||||
deviceEntry.setContentType(device.getContentType());
|
deviceEntry.setContentType(device.getContentType());
|
||||||
deviceEntry.setContentBody(device.getContentBody());
|
deviceEntry.setContentBody(device.getContentBody());
|
||||||
|
deviceEntry.setContentBodyOff(device.getContentBodyOff());
|
||||||
|
|
||||||
deviceRepository.save(deviceEntry);
|
deviceRepository.save(deviceEntry);
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -126,6 +133,12 @@ public class DeviceResource {
|
|||||||
return null;
|
return null;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get HA Bridge version: v" + version.getVersion());
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return "{\"version\":\"" + version.getVersion() + "\"}";
|
||||||
|
});
|
||||||
|
|
||||||
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
||||||
log.debug("Get vera devices");
|
log.debug("Get vera devices");
|
||||||
Sdata sData = veraInfo.getSdata();
|
Sdata sData = veraInfo.getSdata();
|
||||||
@@ -149,5 +162,35 @@ public class DeviceResource {
|
|||||||
return sData.getScenes();
|
return sData.getScenes();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony activities");
|
||||||
|
if(myHarmonyHandler == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHandler.getActivities();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony current activity");
|
||||||
|
if(myHarmonyHandler == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHandler.getCurrentActivity();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony devices");
|
||||||
|
if(myHarmonyHandler == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHandler.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,15 @@ 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.bwssystems.harmony.ButtonPress;
|
||||||
|
import com.bwssystems.harmony.HarmonyHandler;
|
||||||
|
import com.bwssystems.harmony.RunActivity;
|
||||||
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 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;
|
||||||
@@ -30,6 +35,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;
|
||||||
@@ -42,23 +48,27 @@ 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;
|
||||||
|
private HarmonyHandler myHarmony;
|
||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private ObjectMapper mapper;
|
private ObjectMapper mapper;
|
||||||
|
|
||||||
|
|
||||||
public HueMulator(DeviceRepository aDeviceRepository){
|
public HueMulator(DeviceRepository aDeviceRepository, HarmonyHandler theHandler){
|
||||||
httpClient = HttpClients.createDefault();
|
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();
|
myHarmony = theHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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....");
|
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) -> {
|
||||||
@@ -203,15 +213,35 @@ public class HueMulator {
|
|||||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
|
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
|
||||||
url = device.getOffUrl();
|
url = device.getOffUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
//quick template
|
if(device.getDeviceType().contains("activity"))
|
||||||
url = replaceIntensityValue(url, state.getBri());
|
{
|
||||||
String body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
log.debug("executing activity to Harmony: " + url);
|
||||||
//make call
|
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
|
||||||
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
|
myHarmony.startActivity(anActivity);
|
||||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
}
|
||||||
log.error("Error on calling url to change device state: " + url);
|
else if(device.getDeviceType().contains("button"))
|
||||||
return null;
|
{
|
||||||
|
log.debug("executing button press to Harmony: " + url);
|
||||||
|
ButtonPress aDeviceButton = new Gson().fromJson(url, ButtonPress.class);
|
||||||
|
myHarmony.pressButton(aDeviceButton);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.debug("executing activity to Http: " + url);
|
||||||
|
// quick template
|
||||||
|
String body;
|
||||||
|
url = replaceIntensityValue(url, state.getBri());
|
||||||
|
if (state.isOn())
|
||||||
|
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||||
|
else
|
||||||
|
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||||
|
// make call
|
||||||
|
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
||||||
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||||
|
log.error("Error on calling url to change device state: " + url);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.type("application/json; charset=utf-8");
|
response.type("application/json; charset=utf-8");
|
||||||
@@ -223,9 +253,10 @@ public class HueMulator {
|
|||||||
/* light weight templating here, was going to use free marker but it was a bit too
|
/* light weight templating here, was going to use free marker but it was a bit too
|
||||||
* heavy for what we were trying to do.
|
* heavy for what we were trying to do.
|
||||||
*
|
*
|
||||||
* currently provides only two variables:
|
* currently provides:
|
||||||
* intensity.byte : 0-255 brightness. this is raw from the echo
|
* intensity.byte : 0-255 brightness. this is raw from the echo
|
||||||
* intensity.percent : 0-100, adjusted for the vera
|
* 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){
|
protected String replaceIntensityValue(String request, int intensity){
|
||||||
if(request == null){
|
if(request == null){
|
||||||
@@ -238,7 +269,20 @@ public class HueMulator {
|
|||||||
int percentBrightness = (int) Math.round(intensity/255.0*100);
|
int percentBrightness = (int) Math.round(intensity/255.0*100);
|
||||||
String intensityPercent = String.valueOf(percentBrightness);
|
String intensityPercent = String.valueOf(percentBrightness);
|
||||||
request = request.replace(INTENSITY_PERCENT, intensityPercent);
|
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;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ public class UpnpListener {
|
|||||||
|
|
||||||
private boolean traceupnp;
|
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());
|
||||||
@@ -36,7 +34,6 @@ public class UpnpListener {
|
|||||||
responseAddress = theSettings.getUpnpConfigAddress();
|
responseAddress = theSettings.getUpnpConfigAddress();
|
||||||
strict = theSettings.isUpnpStrict();
|
strict = theSettings.isUpnpStrict();
|
||||||
traceupnp = theSettings.isTraceupnp();
|
traceupnp = theSettings.isTraceupnp();
|
||||||
vTwoCompatibility = theSettings.isVtwocompatibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startListening(){
|
public void startListening(){
|
||||||
@@ -113,18 +110,18 @@ public class UpnpListener {
|
|||||||
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(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)
|
if(traceupnp)
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (!strict || vTwoCompatibility)
|
else if (!strict)
|
||||||
{
|
{
|
||||||
if(traceupnp)
|
if(traceupnp)
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(traceupnp)
|
if(traceupnp)
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to not be valid - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
log.info("Traceupnp: isSSDPDiscovery found message to not be valid - strict: " + strict);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,20 +132,9 @@ public class UpnpListener {
|
|||||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\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" +
|
"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";
|
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||||
String discoveryTemplateVTwo = "HTTP/1.1 200 OK\r\n" +
|
|
||||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
|
||||||
"EXT:\r\n" +
|
|
||||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
|
||||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
|
|
||||||
"01-NLS: %s\r\n" +
|
|
||||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
|
||||||
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
|
|
||||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||||
String discoveryResponse = null;
|
String discoveryResponse = null;
|
||||||
if(vTwoCompatibility)
|
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
||||||
discoveryResponse = String.format(discoveryTemplateVTwo, responseAddress, httpServerPort, getRandomUUIDString());
|
|
||||||
else
|
|
||||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
|
||||||
if(traceupnp)
|
if(traceupnp)
|
||||||
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -40,60 +40,12 @@ 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();
|
||||||
this.theSettings = theSettings;
|
this.theSettings = theSettings;
|
||||||
setupListener(this.theSettings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupListener (BridgeSettings theSettings) {
|
public void setupServer() {
|
||||||
log.info("Hue description service started....");
|
log.info("Hue description service started....");
|
||||||
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
|
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
|
||||||
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
|
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
@@ -103,10 +55,7 @@ public class UpnpSettingsResource {
|
|||||||
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
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 = null;
|
String filledTemplate = null;
|
||||||
if(theSettings.isVtwocompatibility())
|
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||||
filledTemplate = String.format(hueTemplateVTwo, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
|
||||||
else
|
|
||||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
|
||||||
if(theSettings.isTraceupnp())
|
if(theSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: upnp device settings response: " + filledTemplate);
|
log.info("Traceupnp: upnp device settings response: " + filledTemplate);
|
||||||
else
|
else
|
||||||
|
|||||||
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
public class ButtonPress {
|
||||||
|
private String device;
|
||||||
|
private String button;
|
||||||
|
public String getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(String device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
public String getButton() {
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
public void setButton(String button) {
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
public Boolean isValid() {
|
||||||
|
if (device != null && !device.isEmpty()){
|
||||||
|
if (button != null && !button.isEmpty())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||||
|
|
||||||
|
public class DevModeResponse {
|
||||||
|
final Logger log = LoggerFactory.getLogger(DevModeResponse.class);
|
||||||
|
|
||||||
|
private final static String powerOff = "PowerOff";
|
||||||
|
private HarmonyConfig harmonyConfig;
|
||||||
|
private Activity currentActivity;
|
||||||
|
|
||||||
|
public DevModeResponse() {
|
||||||
|
super();
|
||||||
|
harmonyConfig = HarmonyConfig.parse(dataReader("/config.data"));
|
||||||
|
this.currentActivity = harmonyConfig.getActivityByName(powerOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity getCurrentActivity() {
|
||||||
|
return currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentActivity(Activity currentActivity) {
|
||||||
|
this.currentActivity = currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Activity> getActivities() {
|
||||||
|
return harmonyConfig.getActivities();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
return harmonyConfig.getDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyConfig getConfig() {
|
||||||
|
return harmonyConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String dataReader(String filePath) {
|
||||||
|
|
||||||
|
String content = null;
|
||||||
|
try {
|
||||||
|
InputStream input = getClass().getResourceAsStream(filePath);
|
||||||
|
OutputStream out = new ByteArrayOutputStream();
|
||||||
|
int read;
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
|
||||||
|
while ((read = input.read(bytes)) != -1) {
|
||||||
|
out.write(bytes, 0, read);
|
||||||
|
}
|
||||||
|
content = out.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
122
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.HarmonyClient;
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||||
|
|
||||||
|
public class HarmonyHandler {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||||
|
private HarmonyClient harmonyClient;
|
||||||
|
private Boolean noopCalls;
|
||||||
|
private Boolean devMode;
|
||||||
|
private DevModeResponse devResponse;
|
||||||
|
|
||||||
|
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
|
||||||
|
super();
|
||||||
|
noopCalls = noopCallsSetting;
|
||||||
|
devMode = Boolean.TRUE;
|
||||||
|
devResponse = null;
|
||||||
|
if(devResponseSetting == null)
|
||||||
|
devMode = Boolean.FALSE;
|
||||||
|
else
|
||||||
|
devResponse = devResponseSetting;
|
||||||
|
harmonyClient = theClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Activity> getActivities() {
|
||||||
|
log.debug("Harmony api activities list requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getActivities();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig().getActivities();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
log.debug("Harmony api device list requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getDevices();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig().getDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyConfig getConfig() {
|
||||||
|
log.debug("Harmony api config requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getConfig();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity getCurrentActivity() {
|
||||||
|
log.debug("Harmony api current sctivity requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getCurrentActivity();
|
||||||
|
|
||||||
|
return harmonyClient.getCurrentActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean startActivity(RunActivity anActivity) {
|
||||||
|
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls);
|
||||||
|
if (anActivity.isValid()) {
|
||||||
|
try {
|
||||||
|
if (noopCalls || devMode) {
|
||||||
|
if(devMode)
|
||||||
|
{
|
||||||
|
if(anActivity != null)
|
||||||
|
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
if (!noopCalls)
|
||||||
|
harmonyClient.startActivityByName(anActivity.getName());
|
||||||
|
} catch (IllegalArgumentException ei) {
|
||||||
|
log.error("Error in finding activity: " + anActivity.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Error in finding activity: " + anActivity.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean pressButton(ButtonPress aDeviceButton) {
|
||||||
|
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls);
|
||||||
|
if (aDeviceButton.isValid()) {
|
||||||
|
try {
|
||||||
|
if (noopCalls || devMode) {
|
||||||
|
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
if (!noopCalls)
|
||||||
|
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||||
|
} catch (IllegalArgumentException ei) {
|
||||||
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
76
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.ActivityChangeListener;
|
||||||
|
import net.whistlingfish.harmony.HarmonyClient;
|
||||||
|
import net.whistlingfish.harmony.HarmonyClientModule;
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
|
||||||
|
public class HarmonyServer {
|
||||||
|
@Inject
|
||||||
|
private HarmonyClient harmonyClient;
|
||||||
|
|
||||||
|
private HarmonyHandler myHarmony;
|
||||||
|
private DevModeResponse devResponse;
|
||||||
|
|
||||||
|
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||||
|
|
||||||
|
public HarmonyServer() {
|
||||||
|
super();
|
||||||
|
myHarmony = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HarmonyServer setup(BridgeSettings bridgeSettings) throws Exception {
|
||||||
|
if(!bridgeSettings.isValidHarmony()) {
|
||||||
|
return new HarmonyServer();
|
||||||
|
}
|
||||||
|
Injector injector = null;
|
||||||
|
if(!bridgeSettings.isDevMode())
|
||||||
|
injector = Guice.createInjector(new HarmonyClientModule());
|
||||||
|
HarmonyServer mainObject = new HarmonyServer();
|
||||||
|
if(!bridgeSettings.isDevMode())
|
||||||
|
injector.injectMembers(mainObject);
|
||||||
|
mainObject.execute(bridgeSettings);
|
||||||
|
return mainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(BridgeSettings mySettings) throws Exception {
|
||||||
|
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||||
|
String modeString = "";
|
||||||
|
if(mySettings.isDevMode())
|
||||||
|
modeString = " (development mode)";
|
||||||
|
if(noopCalls)
|
||||||
|
modeString = " (no op calls to harmony)";
|
||||||
|
log.info("setup initiated " + modeString + "....");
|
||||||
|
if(mySettings.isDevMode())
|
||||||
|
{
|
||||||
|
harmonyClient = null;
|
||||||
|
devResponse = new DevModeResponse();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
devResponse = null;
|
||||||
|
harmonyClient.addListener(new ActivityChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void activityStarted(Activity activity) {
|
||||||
|
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
harmonyClient.connect(mySettings.getHarmonyAddress(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||||
|
}
|
||||||
|
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyHandler getMyHarmony() {
|
||||||
|
return myHarmony;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
public class RunActivity {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Boolean isValid() {
|
||||||
|
if (name != null && !name.isEmpty())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
1
src/main/resources/config.data
Normal file
1
src/main/resources/config.data
Normal file
File diff suppressed because one or more lines are too long
@@ -16,7 +16,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||||
<div class="container">
|
<div class="container" ng-controller="VersionController">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle">
|
<button type="button" class="navbar-toggle">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
@@ -30,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.4.4</a></li>
|
<li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ var app = angular.module('habridge', [
|
|||||||
|
|
||||||
app.config(function ($routeProvider) {
|
app.config(function ($routeProvider) {
|
||||||
$routeProvider.when('/#', {
|
$routeProvider.when('/#', {
|
||||||
templateUrl: 'views/configuration.html',
|
templateUrl: 'views/nonconfiguration.html',
|
||||||
controller: 'ViewingController'
|
controller: 'ViewingController'
|
||||||
|
}).when('/show', {
|
||||||
|
templateUrl: 'views/configuration.html',
|
||||||
|
controller: 'ViewingController'
|
||||||
}).when('/editor', {
|
}).when('/editor', {
|
||||||
templateUrl: 'views/editor.html',
|
templateUrl: 'views/editor.html',
|
||||||
controller: 'AddingController'
|
controller: 'AddingController'
|
||||||
@@ -18,14 +21,23 @@ app.config(function ($routeProvider) {
|
|||||||
}).when('/verascenes', {
|
}).when('/verascenes', {
|
||||||
templateUrl: 'views/verascene.html',
|
templateUrl: 'views/verascene.html',
|
||||||
controller: 'AddingController'
|
controller: 'AddingController'
|
||||||
|
}).when('/harmonydevices', {
|
||||||
|
templateUrl: 'views/harmonydevice.html',
|
||||||
|
controller: 'AddingController'
|
||||||
|
}).when('/harmonyactivities', {
|
||||||
|
templateUrl: 'views/harmonyactivity.html',
|
||||||
|
controller: 'AddingController'
|
||||||
}).otherwise({
|
}).otherwise({
|
||||||
templateUrl: 'views/configuration.html',
|
templateUrl: 'views/nonconfiguration.html',
|
||||||
controller: 'ViewingController'
|
controller: 'ViewingController'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
app.run( function (bridgeService) {
|
app.run( function (bridgeService) {
|
||||||
bridgeService.loadBridgeSettings();
|
bridgeService.loadBridgeSettings();
|
||||||
|
bridgeService.updateShowVera();
|
||||||
|
bridgeService.updateShowHarmony();
|
||||||
|
bridgeService.getHABridgeVersion();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.factory('BridgeSettings', function() {
|
app.factory('BridgeSettings', function() {
|
||||||
@@ -36,9 +48,10 @@ app.factory('BridgeSettings', function() {
|
|||||||
BridgeSettings.upnpdevicedb = "";
|
BridgeSettings.upnpdevicedb = "";
|
||||||
BridgeSettings.upnpresponseport = "";
|
BridgeSettings.upnpresponseport = "";
|
||||||
BridgeSettings.veraaddress = "";
|
BridgeSettings.veraaddress = "";
|
||||||
|
BridgeSettings.harmonyaddress = "";
|
||||||
BridgeSettings.upnpstrict = "";
|
BridgeSettings.upnpstrict = "";
|
||||||
BridgeSettings.traceupnp = "";
|
BridgeSettings.traceupnp = "";
|
||||||
BridgeSettings.vtwocompatibility = "";
|
BridgeSettings.devmode = "";
|
||||||
|
|
||||||
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
|
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
|
||||||
BridgeSettings.upnpconfigaddress = aconfigaddress;
|
BridgeSettings.upnpconfigaddress = aconfigaddress;
|
||||||
@@ -59,23 +72,26 @@ app.factory('BridgeSettings', function() {
|
|||||||
BridgeSettings.setveraaddress = function(averaaddress){
|
BridgeSettings.setveraaddress = function(averaaddress){
|
||||||
BridgeSettings.veraaddress = averaaddress;
|
BridgeSettings.veraaddress = averaaddress;
|
||||||
};
|
};
|
||||||
|
BridgeSettings.setharmonyaddress = function(aharmonyaddress){
|
||||||
|
BridgeSettings.harmonyaddress = aharmonyaddress;
|
||||||
|
};
|
||||||
BridgeSettings.setupnpstrict = function(aupnpstrict){
|
BridgeSettings.setupnpstrict = function(aupnpstrict){
|
||||||
BridgeSettings.upnpstrict = aupnpstrict;
|
BridgeSettings.upnpstrict = aupnpstrict;
|
||||||
};
|
};
|
||||||
BridgeSettings.settraceupnp = function(atraceupnp){
|
BridgeSettings.settraceupnp = function(atraceupnp){
|
||||||
BridgeSettings.traceupnp = atraceupnp;
|
BridgeSettings.traceupnp = atraceupnp;
|
||||||
};
|
};
|
||||||
BridgeSettings.setvtwocompatibility = function(avtwocompatibility){
|
BridgeSettings.setdevmode = function(adevmode){
|
||||||
BridgeSettings.vtwocompatibility = avtwocompatibility;
|
BridgeSettings.devmode = adevmode;
|
||||||
};
|
};
|
||||||
|
|
||||||
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", huebase: window.location.origin + "/api", devices: [], device: [], error: "", showVera: false, showHarmony: false, habridgeversion: ""};
|
||||||
|
|
||||||
this.viewDevices = function () {
|
this.viewDevices = function () {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
@@ -95,6 +111,23 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getHABridgeVersion = function () {
|
||||||
|
this.state.error = "";
|
||||||
|
return $http.get(this.state.base + "/habridge/version").then(
|
||||||
|
function (response) {
|
||||||
|
self.state.habridgeversion = response.data.version;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
if (error.data) {
|
||||||
|
self.state.error = error.data.message;
|
||||||
|
} else {
|
||||||
|
self.state.error = "cannot get version";
|
||||||
|
}
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
this.loadBridgeSettings = function () {
|
this.loadBridgeSettings = function () {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
return $http.get(this.state.upnpbase).then(
|
return $http.get(this.state.upnpbase).then(
|
||||||
@@ -104,23 +137,50 @@ 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.setharmonyaddress(response.data.harmonyaddress);
|
||||||
self.BridgeSettings.settraceupnp(response.data.traceupnp);
|
self.BridgeSettings.settraceupnp(response.data.traceupnp);
|
||||||
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
|
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
|
||||||
self.BridgeSettings.setvtwocompatibility(response.data.vtwocompatibility);
|
self.BridgeSettings.setdevmode(response.data.devmode);
|
||||||
|
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
|
||||||
|
self.state.showVera = false;
|
||||||
|
else
|
||||||
|
self.state.showVera = true;
|
||||||
|
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
|
||||||
|
self.state.showHarmony = false;
|
||||||
|
else
|
||||||
|
self.state.showHarmony = 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.updateShowHarmony = function () {
|
||||||
|
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
|
||||||
|
this.state.showHarmony = false;
|
||||||
|
else
|
||||||
|
this.state.showHarmony = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.viewVeraDevices = function () {
|
this.viewVeraDevices = function () {
|
||||||
|
this.state.error = "";
|
||||||
|
if(!this.state.showVera)
|
||||||
|
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) {
|
||||||
@@ -128,36 +188,72 @@ 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(!this.state.showVera)
|
||||||
|
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, httpVerb, contentType, contentBody) {
|
this.viewHarmonyActivities = function () {
|
||||||
this.state.error = "";
|
this.state.error = "";
|
||||||
|
if(!this.state.showHarmony)
|
||||||
|
return;
|
||||||
|
return $http.get(this.state.base + "/harmony/activities").then(
|
||||||
|
function (response) {
|
||||||
|
self.state.harmonyactivities = response.data;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
if (error.data) {
|
||||||
|
$window.alert("Get Harmony Activities Error: " + error.data.message);
|
||||||
|
} else {
|
||||||
|
$window.alert("Get Harmony Activities Error: unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.viewHarmonyDevices = function () {
|
||||||
|
this.state.error = "";
|
||||||
|
if(!this.state.showHarmony)
|
||||||
|
return;
|
||||||
|
return $http.get(this.state.base + "/harmony/devices").then(
|
||||||
|
function (response) {
|
||||||
|
self.state.harmonydevices = response.data;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
if (error.data) {
|
||||||
|
$window.alert("Get Harmony Devices Error: " + error.data.message);
|
||||||
|
} else {
|
||||||
|
$window.alert("Get Harmony Devices Error: unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||||
|
this.state.error = "";
|
||||||
|
if(httpVerb != null && httpVerb != "")
|
||||||
|
type = "custom";
|
||||||
if (id) {
|
if (id) {
|
||||||
var putUrl = this.state.base + "/" + id;
|
var putUrl = this.state.base + "/" + id;
|
||||||
return $http.put(putUrl, {
|
return $http.put(putUrl, {
|
||||||
@@ -168,19 +264,24 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
offUrl: offUrl,
|
offUrl: offUrl,
|
||||||
httpVerb: httpVerb,
|
httpVerb: httpVerb,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
contentBody: contentBody
|
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";
|
||||||
|
if(httpVerb != null && httpVerb != "")
|
||||||
|
type = "custom";
|
||||||
return $http.post(this.state.base, {
|
return $http.post(this.state.base, {
|
||||||
name: name,
|
name: name,
|
||||||
deviceType: type,
|
deviceType: type,
|
||||||
@@ -188,16 +289,17 @@ app.service('bridgeService', function ($http, BridgeSettings) {
|
|||||||
offUrl: offUrl,
|
offUrl: offUrl,
|
||||||
httpVerb: httpVerb,
|
httpVerb: httpVerb,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
contentBody: contentBody
|
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");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -213,21 +315,23 @@ 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, httpVerb, contentType, contentBody) {
|
this.editDevice = function (id, name, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||||
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl, httpVerb: httpVerb, contentType: contentType, contentBody: contentBody};
|
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();
|
||||||
|
bridgeService.updateShowHarmony();
|
||||||
$scope.predicate = '';
|
$scope.predicate = '';
|
||||||
$scope.reverse = true;
|
$scope.reverse = true;
|
||||||
$scope.order = function(predicate) {
|
$scope.order = function(predicate) {
|
||||||
@@ -237,20 +341,87 @@ app.controller('ViewingController', function ($scope, $location, bridgeService,
|
|||||||
$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.deviceType == "activity" || device.deviceType == "button") {
|
||||||
|
$http.put($scope.bridge.huebase + "/test/lights/" + device.id + "/state", "{\"on\":true}").then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.deviceType == "activity" || device.deviceType == "button") {
|
||||||
|
$http.put($scope.bridge.huebase + "/test/lights/" + device.id + "/state", "{\"on\":false}").then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, device.httpVerb, device.contentType, device.contentBody);
|
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, $location, bridgeService, BridgeSettings) {
|
app.controller('AddingController', function ($scope, $location, $http, bridgeService, BridgeSettings) {
|
||||||
|
|
||||||
$scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
|
$scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
|
||||||
$scope.vera = {base: "", port: "3480", id: ""};
|
$scope.vera = {base: "", port: "3480", id: ""};
|
||||||
@@ -258,22 +429,34 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
|
|||||||
bridgeService.device = $scope.device;
|
bridgeService.device = $scope.device;
|
||||||
bridgeService.viewVeraDevices();
|
bridgeService.viewVeraDevices();
|
||||||
bridgeService.viewVeraScenes();
|
bridgeService.viewVeraScenes();
|
||||||
|
bridgeService.viewHarmonyActivities();
|
||||||
|
bridgeService.viewHarmonyDevices();
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
|
bridgeService.updateShowVera();
|
||||||
|
bridgeService.updateShowHarmony();
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
$scope.predicate = '';
|
$scope.predicate = '';
|
||||||
$scope.reverse = true;
|
$scope.reverse = true;
|
||||||
|
$scope.device_dim_control = "";
|
||||||
$scope.order = function(predicate) {
|
$scope.order = function(predicate) {
|
||||||
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
||||||
$scope.predicate = predicate;
|
$scope.predicate = predicate;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildUrlsUsingDevice = function () {
|
$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;
|
||||||
@@ -292,15 +475,22 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
|
|||||||
+ $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.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;
|
||||||
@@ -320,12 +510,93 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
|
|||||||
+ verascene.id;
|
+ verascene.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.testUrl = function (url) {
|
$scope.buildActivityUrls = function (harmonyactivity) {
|
||||||
window.open(url, "_blank");
|
$scope.device.deviceType = "activity";
|
||||||
|
$scope.device.name = harmonyactivity.label;
|
||||||
|
$scope.device.onUrl = "{\"name\":\"" + harmonyactivity.id + "\"}";
|
||||||
|
$scope.device.offUrl = "{\"name\":\"-1\"}";
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
|
||||||
|
$scope.device.deviceType = "button";
|
||||||
|
$scope.device.name = harmonydevice.label;
|
||||||
|
$scope.device.onUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + onbutton + "\"}";
|
||||||
|
$scope.device.offUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + offbutton + "\"}";
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.testUrl = function (device, type) {
|
||||||
|
if(type == "on") {
|
||||||
|
if(device.deviceType == "activity" || device.deviceType == "button") {
|
||||||
|
$http.put($scope.bridge.huebase + "/test/lights/" + device.id + "/state", "{\"on\":true}").then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.deviceType == "activity" || device.deviceType == "button") {
|
||||||
|
$http.put($scope.bridge.huebase + "/test/lights/" + device.id + "/state", "{\"on\":false}").then(
|
||||||
|
function (response) {
|
||||||
|
$window.alert("Request Exceuted: " + response.statusText);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$window.alert("Request Error: " + error.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, $scope.device.httpVerb, $scope.device.contentType, $scope.device.contentBody).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 = "";
|
||||||
@@ -335,6 +606,7 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
|
|||||||
$scope.device.httpVerb = null;
|
$scope.device.httpVerb = null;
|
||||||
$scope.device.contentType = null;
|
$scope.device.contentType = null;
|
||||||
$scope.device.contentBody = null;
|
$scope.device.contentBody = null;
|
||||||
|
$scope.device.contentBodyOff = null;
|
||||||
$location.path('/#');
|
$location.path('/#');
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
@@ -346,4 +618,8 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
|
|||||||
|
|
||||||
app.controller('ErrorsController', function ($scope, bridgeService) {
|
app.controller('ErrorsController', function ($scope, bridgeService) {
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.controller('VersionController', function ($scope, bridgeService) {
|
||||||
|
$scope.bridge = bridgeService.state;
|
||||||
|
});
|
||||||
@@ -1,12 +1,66 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<div ng-controller="ErrorsController">
|
||||||
|
<div ng-if="bridge.error"
|
||||||
|
class="alert alert-warning alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert"
|
||||||
|
aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 ng-show='bridge.error != ""'>ERROR</h2>
|
||||||
|
|
||||||
|
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Current devices</h2>
|
||||||
|
</div>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<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('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>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.deviceType}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="editDevice(device)">Edit</button>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDevice(device)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
|
<a href="#/"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></a>
|
||||||
<h1 class="panel-title">Bridge settings</h1>
|
<h1 class="panel-title">Bridge settings</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@@ -53,6 +107,10 @@
|
|||||||
<td>vera.address</td>
|
<td>vera.address</td>
|
||||||
<td>{{BridgeSettings.veraaddress}}</td>
|
<td>{{BridgeSettings.veraaddress}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>harmony.address</td>
|
||||||
|
<td>{{BridgeSettings.harmonyaddress}}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>upnp.strict</td>
|
<td>upnp.strict</td>
|
||||||
<td>{{BridgeSettings.upnpstrict}}</td>
|
<td>{{BridgeSettings.upnpstrict}}</td>
|
||||||
@@ -62,59 +120,9 @@
|
|||||||
<td>{{BridgeSettings.traceupnp}}</td>
|
<td>{{BridgeSettings.traceupnp}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>vtwo.compatibility</td>
|
<td>dev.mode</td>
|
||||||
<td>{{BridgeSettings.vtwocompatibility}}</td>
|
<td>{{BridgeSettings.devmode}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-controller="ErrorsController">
|
|
||||||
<div ng-if="bridge.error"
|
|
||||||
class="alert alert-warning alert-dismissible" role="alert">
|
|
||||||
<button type="button" class="close" data-dismiss="alert"
|
|
||||||
aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h2 ng-show='bridge.error != ""'>ERROR</h2>
|
|
||||||
|
|
||||||
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">Current devices</h2>
|
|
||||||
</div>
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<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('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>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
|
||||||
<td>{{device.id}}</td>
|
|
||||||
<td>{{device.name}}</td>
|
|
||||||
<td>{{device.deviceType}}</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device.onUrl)">Test ON</button>
|
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device.offUrl)">Test OFF</button>
|
|
||||||
<button class="btn btn-warning" type="submit"
|
|
||||||
ng-click="editDevice(device)">Edit</button>
|
|
||||||
<button class="btn btn-danger" type="submit"
|
|
||||||
ng-click="deleteDevice(device)">Delete</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -35,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -58,30 +60,60 @@
|
|||||||
</label>
|
</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-http-verb"
|
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
|
||||||
ng-model="device.httpVerb" placeholder="Http Verb, i.e. GET/PUT/POST">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
</label>
|
</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-content-type"
|
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
|
||||||
ng-model="device.contentType" placeholder="Content type, i.e. application/json">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<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-content-body">Content Body </label>
|
for="device-content-body">Content Body On</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<textarea rows="3" class="form-control" id="device-content-body"
|
<textarea rows="3" class="form-control" id="device-content-body"
|
||||||
ng-model="device.contentBody" placeholder="Content Body for specific GET/PUT/POST type"></textarea>
|
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>
|
||||||
<div class="clearfix visible-xs"></div>
|
<div class="clearfix visible-xs"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="bridge.showVera">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,7 +46,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button type="submit" ng-click="buildUrlsUsingDevice()"
|
<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
|
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()"
|
||||||
@@ -86,7 +100,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -100,7 +114,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -109,30 +123,60 @@
|
|||||||
</label>
|
</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-http-verb"
|
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
|
||||||
ng-model="device.httpVerb" placeholder="Http Verb, i.e. GET/PUT/POST">
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
</div>
|
<option value="GET">GET</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
</label>
|
</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-content-type"
|
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
|
||||||
ng-model="device.contentType" placeholder="Content type, i.e. application/json">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<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-content-body">Content Body </label>
|
for="device-content-body">Content Body On</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<textarea rows="3" class="form-control" id="device-content-body"
|
<textarea rows="3" class="form-control" id="device-content-body"
|
||||||
ng-model="device.contentBody" placeholder="Content Body for specific GET/PUT/POST type"></textarea>
|
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>
|
||||||
<div class="clearfix visible-xs"></div>
|
<div class="clearfix visible-xs"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
89
src/main/resources/public/views/harmonyactivity.html
Normal file
89
src/main/resources/public/views/harmonyactivity.html
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</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-heading">
|
||||||
|
<h2 class="panel-title">Harmony Activity List</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p class="text-muted">You can select a Harmony Activity and generate
|
||||||
|
the add activity box selections automatically.</p>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('label')">Name</a>
|
||||||
|
<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>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | orderBy:predicate:reverse">
|
||||||
|
<td>{{harmonyactivity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.id}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||||
|
Activity URLs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add a Harmony Activity</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal" ng-submit="addDevice()">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||||
|
Add Activity</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
105
src/main/resources/public/views/harmonydevice.html
Normal file
105
src/main/resources/public/views/harmonydevice.html
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</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-heading">
|
||||||
|
<h2 class="panel-title">Harmony Device List</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p class="text-muted">You can select a Harmony Device and Button and generate
|
||||||
|
the add button box selections automatically.</p>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('label')">Name</a>
|
||||||
|
<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>On Button</th>
|
||||||
|
<th>Off Button</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
|
||||||
|
<td>{{harmonydevice.label}}</td>
|
||||||
|
<td>{{harmonydevice.id}}</td>
|
||||||
|
<td>
|
||||||
|
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
||||||
|
<optgroup ng-repeat="ctrlon in harmonydevice.controlGroup" label="{{ctrlon.name}}">
|
||||||
|
<option ng-repeat="funcon in ctrlon.function">{{funcon.name}}</option>
|
||||||
|
</optgroup >
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
||||||
|
<optgroup ng-repeat="ctrloff in harmonydevice.controlGroup" label="{{ctrloff.name}}">
|
||||||
|
<option ng-repeat="funcoff in ctrloff.function">{{funcoff.name}}</option>
|
||||||
|
</optgroup >
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Generate
|
||||||
|
Button URLs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add a Harmony Button</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal" ng-submit="addDevice()">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||||
|
Add Button</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
64
src/main/resources/public/views/nonconfiguration.html
Normal file
64
src/main/resources/public/views/nonconfiguration.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div ng-controller="ErrorsController">
|
||||||
|
<div ng-if="bridge.error"
|
||||||
|
class="alert alert-warning alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert"
|
||||||
|
aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 ng-show='bridge.error != ""'>ERROR</h2>
|
||||||
|
|
||||||
|
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Current devices</h2>
|
||||||
|
</div>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<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('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>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.deviceType}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="editDevice(device)">Edit</button>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDevice(device)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default bridgeServer">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<a href="#/show"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a>
|
||||||
|
<h1 class="panel-title">Bridge settings</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
|
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -12,8 +14,15 @@
|
|||||||
<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>
|
||||||
@@ -43,7 +52,7 @@
|
|||||||
<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>
|
||||||
@@ -80,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -94,7 +103,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Configuration</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
|
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
<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 scene and generate
|
<p class="text-muted">You can select a Vera scene and generate
|
||||||
the add device box selections automatically.</p>
|
the add scene box selections automatically.</p>
|
||||||
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -75,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -89,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
3
src/main/resources/version.properties
Normal file
3
src/main/resources/version.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
version=${project.version}
|
||||||
|
groupId=${project.groupId}
|
||||||
|
artifactId=${project.artifactId}
|
||||||
@@ -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