mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1708f2a88 | ||
|
|
49c3b85894 | ||
|
|
f9f5a3a878 | ||
|
|
2565183ee9 | ||
|
|
a6bb1ae3aa | ||
|
|
4bc91be88b | ||
|
|
315fd31270 | ||
|
|
09787fe08d | ||
|
|
37d346f558 | ||
|
|
ac59398aa0 | ||
|
|
87073435fc | ||
|
|
8687f3482a | ||
|
|
32a5f26ddd | ||
|
|
c28f07d628 | ||
|
|
d3cc961dfb | ||
|
|
1b3d826f28 | ||
|
|
c8f4d89a45 | ||
|
|
2b335d6b9b | ||
|
|
b27bb5eef8 | ||
|
|
3c54ccd56d | ||
|
|
cf772334c4 | ||
|
|
5a843f7569 | ||
|
|
2a52783bb1 | ||
|
|
195f1854ec | ||
|
|
2e5596a6e4 | ||
|
|
9fc13c6c45 | ||
|
|
4b4d4e36c7 | ||
|
|
1e7bdc560b | ||
|
|
aff0f8d64c | ||
|
|
7a812d6e6b | ||
|
|
26f2105801 | ||
|
|
feef345a3b | ||
|
|
314ae58ebd | ||
|
|
d8b6232ac1 | ||
|
|
41e22ee64d | ||
|
|
be2fbcd4cb | ||
|
|
14e7f37522 | ||
|
|
e3f5946c9d | ||
|
|
12eab16f21 | ||
|
|
3df68047a9 | ||
|
|
0dd652f82a | ||
|
|
53af1a4dfd | ||
|
|
816a0025b1 | ||
|
|
405562809a | ||
|
|
4c87c6fce8 | ||
|
|
2fd0f7748b | ||
|
|
ed5f3b4b3c | ||
|
|
aad09b7527 | ||
|
|
0ae66da085 | ||
|
|
d344b764da | ||
|
|
c85b67fb9f | ||
|
|
a23d662444 | ||
|
|
4b98f799c2 | ||
|
|
acba2b5cae | ||
|
|
4dc818296a | ||
|
|
40123ed858 | ||
|
|
718ba5a5c2 | ||
|
|
2e6944d840 | ||
|
|
e29f12905d | ||
|
|
408b79d5d8 | ||
|
|
bf5ad2e23c | ||
|
|
59f1db285d | ||
|
|
203ed0b5d3 | ||
|
|
b443d16a11 | ||
|
|
295b1e1a30 | ||
|
|
c872f3543d | ||
|
|
23f2d2716d | ||
|
|
7c1d6e40b8 | ||
|
|
c5fbd5d1f0 |
109
pom.xml
109
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.8</version>
|
<version>1.3.7</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 or Nest, using lightweight frameworks</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
@@ -17,17 +17,39 @@
|
|||||||
<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>
|
||||||
|
<groupId>com.github.bwssytems</groupId>
|
||||||
|
<artifactId>nest-controller</artifactId>
|
||||||
|
<version>1.0.3</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sparkjava</groupId>
|
<groupId>com.sparkjava</groupId>
|
||||||
<artifactId>spark-core</artifactId>
|
<artifactId>spark-core</artifactId>
|
||||||
<version>2.2</version>
|
<version>2.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
<version>4.3.6</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpcore</artifactId>
|
||||||
|
<version>4.4.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
@@ -53,9 +75,40 @@
|
|||||||
<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>
|
||||||
</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>
|
||||||
@@ -78,24 +131,42 @@
|
|||||||
<exclude>META-INF/*.RSA</exclude>
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
<exclude>META-INF/*.txt</exclude>
|
<exclude>META-INF/*.txt</exclude>
|
||||||
<exclude>META-INF/maven/**</exclude>
|
<exclude>META-INF/maven/**</exclude>
|
||||||
<exclude>META-INF/services/**</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>*:*</artifact>
|
||||||
<includes>
|
</filter>
|
||||||
<include>**</include>
|
<filter>
|
||||||
</includes>
|
<artifact>org.slf4j:*</artifact>
|
||||||
</filter>
|
<includes>
|
||||||
<filter>
|
<include>**</include>
|
||||||
<artifact>commons-logging:commons-logging</artifact>
|
</includes>
|
||||||
<includes>
|
</filter>
|
||||||
<include>**</include>
|
<filter>
|
||||||
</includes>
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
</filter>
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>xpp3:xpp3</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>org.igniterealtime.smack:*</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.github.bwssytems:harmony-java-client</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer
|
<transformer
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class BridgeSettings {
|
public class BridgeSettings {
|
||||||
private String upnpconfigaddress;
|
private String upnpconfigaddress;
|
||||||
private String serverport;
|
private String serverport;
|
||||||
private String upnpresponseport;
|
private String upnpresponseport;
|
||||||
private String upnpdevicedb;
|
private String upnpdevicedb;
|
||||||
private String veraaddress;
|
private IpList veraaddress;
|
||||||
|
private IpList harmonyaddress;
|
||||||
|
private String harmonyuser;
|
||||||
|
private String harmonypwd;
|
||||||
|
private Integer upnpresponsedevices;
|
||||||
private boolean upnpstrict;
|
private boolean upnpstrict;
|
||||||
private boolean traceupnp;
|
private boolean traceupnp;
|
||||||
private boolean vtwocompatibility;
|
private boolean devmode;
|
||||||
|
private String nestuser;
|
||||||
|
private String nestpwd;
|
||||||
|
private boolean nestconfigured;
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
return upnpconfigaddress;
|
return upnpconfigaddress;
|
||||||
@@ -34,13 +43,36 @@ public class BridgeSettings {
|
|||||||
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
||||||
this.upnpdevicedb = upnpDeviceDb;
|
this.upnpdevicedb = upnpDeviceDb;
|
||||||
}
|
}
|
||||||
public String getVeraAddress() {
|
public IpList getVeraAddress() {
|
||||||
return veraaddress;
|
return veraaddress;
|
||||||
}
|
}
|
||||||
public void setVeraAddress(String veraAddress) {
|
public void setVeraAddress(IpList veraAddress) {
|
||||||
this.veraaddress = veraAddress;
|
this.veraaddress = veraAddress;
|
||||||
}
|
}
|
||||||
|
public IpList getHarmonyAddress() {
|
||||||
|
return harmonyaddress;
|
||||||
|
}
|
||||||
|
public void setHarmonyAddress(IpList 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 Integer getUpnpResponseDevices() {
|
||||||
|
return upnpresponsedevices;
|
||||||
|
}
|
||||||
|
public void setUpnpResponseDevices(Integer upnpresponsedevices) {
|
||||||
|
this.upnpresponsedevices = upnpresponsedevices;
|
||||||
|
}
|
||||||
public boolean isUpnpStrict() {
|
public boolean isUpnpStrict() {
|
||||||
return upnpstrict;
|
return upnpstrict;
|
||||||
}
|
}
|
||||||
@@ -53,12 +85,51 @@ 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 String getNestuser() {
|
||||||
|
return nestuser;
|
||||||
|
}
|
||||||
|
public void setNestuser(String nestuser) {
|
||||||
|
this.nestuser = nestuser;
|
||||||
|
}
|
||||||
|
public String getNestpwd() {
|
||||||
|
return nestpwd;
|
||||||
|
}
|
||||||
|
public void setNestpwd(String nestpwd) {
|
||||||
|
this.nestpwd = nestpwd;
|
||||||
|
}
|
||||||
|
public boolean isNestConfigured() {
|
||||||
|
return nestconfigured;
|
||||||
|
}
|
||||||
|
public void setNestConfigured(boolean isNestConfigured) {
|
||||||
|
this.nestconfigured = isNestConfigured;
|
||||||
|
}
|
||||||
|
public Boolean isValidVera() {
|
||||||
|
List<NamedIP> devicesList = this.veraaddress.getDevices();
|
||||||
|
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidHarmony() {
|
||||||
|
List<NamedIP> devicesList = this.harmonyaddress.getDevices();
|
||||||
|
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
if(this.harmonypwd == null || this.harmonypwd == "")
|
||||||
|
return false;
|
||||||
|
if(this.harmonyuser == null || this.harmonyuser == "")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidNest() {
|
||||||
|
if(this.nestpwd == null || this.nestpwd == "")
|
||||||
|
return false;
|
||||||
|
if(this.nestuser == null || this.nestuser == "")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
14
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
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 UPNP_RESPONSE_DEVICES = "30";
|
||||||
|
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
||||||
|
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
||||||
|
public final static String LOOP_BACK_INTERFACE = "lo";
|
||||||
|
public final static String DEFAULT_HARMONY_ADDRESS_LIST = "{devices:[{name:default,ip:1.1.1.1}]}";
|
||||||
|
public final static String DEFAULT_USER = "";
|
||||||
|
public final static String DEFAULT_PWD = "";
|
||||||
|
public final static String DFAULT_WEB_PORT = "8080";
|
||||||
|
}
|
||||||
@@ -3,8 +3,11 @@ package com.bwssystems.HABridge;
|
|||||||
import static spark.Spark.*;
|
import static spark.Spark.*;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import org.apache.http.conn.util.InetAddressUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -12,6 +15,9 @@ 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.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -33,43 +39,105 @@ 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;
|
||||||
|
HarmonyHome harmonyHome;
|
||||||
|
NestHome nestHome;
|
||||||
HueMulator theHueMulator;
|
HueMulator theHueMulator;
|
||||||
UpnpSettingsResource theSettingResponder;
|
UpnpSettingsResource theSettingResponder;
|
||||||
UpnpListener theUpnpListener;
|
UpnpListener theUpnpListener;
|
||||||
InetAddress address;
|
InetAddress address = null;
|
||||||
String addressString;
|
String addressString = null;
|
||||||
BridgeSettings bridgeSettings;
|
BridgeSettings bridgeSettings;
|
||||||
|
Version theVersion;
|
||||||
|
|
||||||
//get ip address for upnp requests
|
theVersion = new Version();
|
||||||
try {
|
|
||||||
address = InetAddress.getLocalHost();
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
|
||||||
addressString = address.getHostAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings = new BridgeSettings();
|
||||||
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
|
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
||||||
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", "data/device.db"));
|
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", Configuration.DEFAULT_ADDRESS));
|
||||||
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000"));
|
if(bridgeSettings.getUpnpConfigAddress().equalsIgnoreCase(Configuration.DEFAULT_ADDRESS)) {
|
||||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100"));
|
try {
|
||||||
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "false")));
|
log.info("Getting an IP address for this host....");
|
||||||
|
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
|
||||||
|
|
||||||
|
while (ifs.hasMoreElements() && addressString == null) {
|
||||||
|
NetworkInterface xface = ifs.nextElement();
|
||||||
|
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
||||||
|
String name = xface.getName();
|
||||||
|
int IPsPerNic = 0;
|
||||||
|
|
||||||
|
while (addrs.hasMoreElements() && IPsPerNic == 0) {
|
||||||
|
address = addrs.nextElement();
|
||||||
|
if (InetAddressUtils.isIPv4Address(address.getHostAddress())) {
|
||||||
|
log.debug(name + " ... has IPV4 addr " + address);
|
||||||
|
if(!name.equalsIgnoreCase(Configuration.LOOP_BACK_INTERFACE)|| !address.getHostAddress().equalsIgnoreCase(Configuration.LOOP_BACK_ADDRESS)) {
|
||||||
|
IPsPerNic++;
|
||||||
|
addressString = address.getHostAddress();
|
||||||
|
log.info("Adding " + addressString + " from interface " + name + " as our default upnp config address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bridgeSettings.setUpnpConfigAddress(addressString);
|
||||||
|
}
|
||||||
|
|
||||||
|
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
|
||||||
|
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||||
|
IpList theVeraList;
|
||||||
|
|
||||||
|
try {
|
||||||
|
theVeraList = new Gson().fromJson(System.getProperty("vera.address", Configuration.DEFAULT_HARMONY_ADDRESS_LIST), IpList.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
theVeraList = new Gson().fromJson("{devices:[{name:default,ip:" + System.getProperty("vera.address", Configuration.DEFAULT_ADDRESS) + "}]}", IpList.class);
|
||||||
|
} catch (Exception et) {
|
||||||
|
log.error("Cannot parse vera.address, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bridgeSettings.setVeraAddress(theVeraList);
|
||||||
|
IpList theHarmonyList;
|
||||||
|
|
||||||
|
try {
|
||||||
|
theHarmonyList = new Gson().fromJson(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS_LIST), IpList.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
theHarmonyList = new Gson().fromJson("{devices:[{name:default,ip:" + System.getProperty("harmony.address", Configuration.DEFAULT_ADDRESS) + "}]}", IpList.class);
|
||||||
|
} catch (Exception et) {
|
||||||
|
log.error("Cannot parse harmony.address, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bridgeSettings.setHarmonyAddress(theHarmonyList);
|
||||||
|
bridgeSettings.setHarmonyUser(System.getProperty("harmony.user", Configuration.DEFAULT_USER));
|
||||||
|
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_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")));
|
||||||
|
bridgeSettings.setUpnpResponseDevices(Integer.parseInt(System.getProperty("upnp.response.devices", Configuration.UPNP_RESPONSE_DEVICES)));
|
||||||
|
bridgeSettings.setNestuser(System.getProperty("nest.user", Configuration.DEFAULT_USER));
|
||||||
|
bridgeSettings.setNestpwd(System.getProperty("nest.pwd", Configuration.DEFAULT_PWD));
|
||||||
|
|
||||||
// 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
|
||||||
|
harmonyHome = new HarmonyHome(bridgeSettings);
|
||||||
|
//setup the nest connection if available
|
||||||
|
nestHome = new NestHome(bridgeSettings);
|
||||||
// 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, harmonyHome, nestHome);
|
||||||
// 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(bridgeSettings, theResources.getDeviceRepository(), harmonyHome, nestHome);
|
||||||
theHueMulator.setupServer();
|
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);
|
||||||
|
|||||||
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IpList {
|
||||||
|
private List<NamedIP> devices;
|
||||||
|
|
||||||
|
public List<NamedIP> getDevices() {
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevices(List<NamedIP> devices) {
|
||||||
|
this.devices = devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class NamedIP {
|
||||||
|
private String name;
|
||||||
|
private String ip;
|
||||||
|
private String port;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getIp() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
public void setIp(String ip) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
public String getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
public void setPort(String port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
public final class Version {
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
private String groupId;
|
||||||
|
private String artifactId;
|
||||||
|
private Properties prop;
|
||||||
|
|
||||||
|
public Version()
|
||||||
|
{
|
||||||
|
InputStream resourceAsStream =
|
||||||
|
(InputStream) this.getClass().getResourceAsStream(
|
||||||
|
"/version.properties"
|
||||||
|
);
|
||||||
|
this.prop = new Properties();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.prop.load( resourceAsStream );
|
||||||
|
this.version = this.prop.getProperty("version");
|
||||||
|
this.groupId = this.prop.getProperty("groupId");
|
||||||
|
this.artifactId = this.prop.getProperty("artifactId");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
this.version = "0.0.0";
|
||||||
|
this.groupId = "no group";
|
||||||
|
this.artifactId = "no artifact";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArtifactId() {
|
||||||
|
return artifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
*/
|
*/
|
||||||
@@ -16,7 +11,6 @@ public class DeviceResponse {
|
|||||||
private String manufacturername;
|
private String manufacturername;
|
||||||
private String uniqueid;
|
private String uniqueid;
|
||||||
private String swversion;
|
private String swversion;
|
||||||
private Map<String, String> pointsymbol;
|
|
||||||
|
|
||||||
public DeviceState getState() {
|
public DeviceState getState() {
|
||||||
return state;
|
return state;
|
||||||
@@ -74,27 +68,6 @@ public class DeviceResponse {
|
|||||||
this.swversion = swversion;
|
this.swversion = swversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getPointsymbol() {
|
|
||||||
if(pointsymbol == null)
|
|
||||||
{
|
|
||||||
pointsymbol = new HashMap<>();
|
|
||||||
pointsymbol.put("1", "none");
|
|
||||||
pointsymbol.put("2", "none");
|
|
||||||
pointsymbol.put("3", "none");
|
|
||||||
pointsymbol.put("4", "none");
|
|
||||||
pointsymbol.put("5", "none");
|
|
||||||
pointsymbol.put("6", "none");
|
|
||||||
pointsymbol.put("7", "none");
|
|
||||||
pointsymbol.put("8", "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
return pointsymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPointsymbol(Map<String, String> pointsymbol) {
|
|
||||||
this.pointsymbol = pointsymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceResponse createResponse(String name, String id){
|
public static DeviceResponse createResponse(String name, String id){
|
||||||
DeviceState deviceState = new DeviceState();
|
DeviceState deviceState = new DeviceState();
|
||||||
DeviceResponse response = new DeviceResponse();
|
DeviceResponse response = new DeviceResponse();
|
||||||
@@ -104,21 +77,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(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("66012040");
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
@@ -8,14 +7,9 @@ import java.util.List;
|
|||||||
public class DeviceState {
|
public class DeviceState {
|
||||||
private boolean on;
|
private boolean on;
|
||||||
private int bri = 255;
|
private int bri = 255;
|
||||||
private int hue;
|
|
||||||
private int sat;
|
|
||||||
private String effect;
|
private String effect;
|
||||||
private int ct;
|
|
||||||
private String alert;
|
private String alert;
|
||||||
private String colormode;
|
|
||||||
private boolean reachable;
|
private boolean reachable;
|
||||||
private List<Double> xy;
|
|
||||||
|
|
||||||
public boolean isOn() {
|
public boolean isOn() {
|
||||||
return on;
|
return on;
|
||||||
@@ -33,22 +27,6 @@ public class DeviceState {
|
|||||||
this.bri = bri;
|
this.bri = bri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHue() {
|
|
||||||
return hue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHue(int hue) {
|
|
||||||
this.hue = hue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSat() {
|
|
||||||
return sat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSat(int sat) {
|
|
||||||
this.sat = sat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEffect() {
|
public String getEffect() {
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
@@ -57,14 +35,6 @@ public class DeviceState {
|
|||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCt() {
|
|
||||||
return ct;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCt(int ct) {
|
|
||||||
this.ct = ct;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlert() {
|
public String getAlert() {
|
||||||
return alert;
|
return alert;
|
||||||
}
|
}
|
||||||
@@ -73,14 +43,6 @@ public class DeviceState {
|
|||||||
this.alert = alert;
|
this.alert = alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getColormode() {
|
|
||||||
return colormode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColormode(String colormode) {
|
|
||||||
this.colormode = colormode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReachable() {
|
public boolean isReachable() {
|
||||||
return reachable;
|
return reachable;
|
||||||
}
|
}
|
||||||
@@ -89,14 +51,6 @@ public class DeviceState {
|
|||||||
this.reachable = reachable;
|
this.reachable = reachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Double> getXy() {
|
|
||||||
return xy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXy(List<Double> xy) {
|
|
||||||
this.xy = xy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DeviceState{" +
|
return "DeviceState{" +
|
||||||
|
|||||||
@@ -12,11 +12,17 @@ public class HueApiResponse {
|
|||||||
private Map<String, DeviceResponse> lights;
|
private Map<String, DeviceResponse> lights;
|
||||||
private Map<String, String> scenes;
|
private Map<String, String> scenes;
|
||||||
private Map<String, String> groups;
|
private Map<String, String> groups;
|
||||||
|
private Map<String, String> schedules;
|
||||||
|
private Map<String, String> sensors;
|
||||||
|
private Map<String, String> rules;
|
||||||
private HueConfig config;
|
private HueConfig config;
|
||||||
|
|
||||||
public HueApiResponse(String name, String ipaddress, String username, String userid) {
|
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
||||||
super();
|
super();
|
||||||
this.setConfig(HueConfig.createConfig(name, ipaddress, username, userid));
|
this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid));
|
||||||
|
this.setRules(new HashMap<>());
|
||||||
|
this.setSensors(new HashMap<>());
|
||||||
|
this.setSchedules(new HashMap<>());
|
||||||
this.setGroups(new HashMap<>());
|
this.setGroups(new HashMap<>());
|
||||||
this.setScenes(new HashMap<>());
|
this.setScenes(new HashMap<>());
|
||||||
}
|
}
|
||||||
@@ -45,6 +51,30 @@ public class HueApiResponse {
|
|||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getSchedules() {
|
||||||
|
return schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchedules(Map<String, String> schedules) {
|
||||||
|
this.schedules = schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getSensors() {
|
||||||
|
return sensors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSensors(Map<String, String> sensors) {
|
||||||
|
this.sensors = sensors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getRules() {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRules(Map<String, String> rules) {
|
||||||
|
this.rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
public HueConfig getConfig() {
|
public HueConfig getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
public class HueConfig
|
public class HueConfig
|
||||||
{
|
{
|
||||||
@@ -26,10 +33,13 @@ public class HueConfig
|
|||||||
|
|
||||||
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
|
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
|
||||||
HueConfig aConfig = new HueConfig();
|
HueConfig aConfig = new HueConfig();
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
aConfig.setMac(HueConfig.getMacAddress(ipaddress));
|
||||||
aConfig.setApiversion("1.4.0");
|
aConfig.setApiversion("1.4.0");
|
||||||
aConfig.setPortalservices(false);
|
aConfig.setPortalservices(false);
|
||||||
aConfig.setGateway("192.168.1.1");
|
aConfig.setGateway(ipaddress);
|
||||||
aConfig.setMac("00:00:88:00:bb:ee");
|
|
||||||
aConfig.setSwversion("01005215");
|
aConfig.setSwversion("01005215");
|
||||||
aConfig.setLinkbutton(false);
|
aConfig.setLinkbutton(false);
|
||||||
aConfig.setIpaddress(ipaddress);
|
aConfig.setIpaddress(ipaddress);
|
||||||
@@ -38,20 +48,50 @@ public class HueConfig
|
|||||||
aConfig.setNetmask("255.255.255.0");
|
aConfig.setNetmask("255.255.255.0");
|
||||||
aConfig.setName(name);
|
aConfig.setName(name);
|
||||||
aConfig.setDhcp(true);
|
aConfig.setDhcp(true);
|
||||||
aConfig.setUtc("2014-07-17T09:27:35");
|
aConfig.setUtc(dateFormatGmt.format(new Date()));
|
||||||
aConfig.setProxyaddress("0.0.0.0");
|
aConfig.setProxyaddress("none");
|
||||||
aConfig.setLocaltime("2014-07-17T11:27:35");
|
aConfig.setLocaltime(dateFormat.format(new Date()));
|
||||||
aConfig.setTimezone("America/Chicago");
|
aConfig.setTimezone(TimeZone.getDefault().getID());
|
||||||
aConfig.setZigbeechannel("6");
|
aConfig.setZigbeechannel("6");
|
||||||
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
|
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
|
||||||
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype));
|
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype));
|
||||||
aConfig.setWhitelist(awhitelist);
|
aConfig.setWhitelist(awhitelist);
|
||||||
|
|
||||||
|
|
||||||
return aConfig;
|
return aConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getMacAddress(String addr)
|
||||||
|
{
|
||||||
|
InetAddress ip;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ip = InetAddress.getByName(addr);
|
||||||
|
|
||||||
|
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||||
|
|
||||||
|
byte[] mac = network.getHardwareAddress();
|
||||||
|
|
||||||
|
for (int i = 0; i < mac.length; i++) {
|
||||||
|
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (SocketException e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
public Boolean getPortalservices() {
|
public Boolean getPortalservices() {
|
||||||
return portalservices;
|
return portalservices;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
public class BackupFilename {
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,10 @@ package com.bwssystems.HABridge.dao;
|
|||||||
public class DeviceDescriptor{
|
public class DeviceDescriptor{
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private String mapId;
|
||||||
|
private String mapType;
|
||||||
private String deviceType;
|
private String deviceType;
|
||||||
|
private String targetDevice;
|
||||||
private String offUrl;
|
private String offUrl;
|
||||||
private String onUrl;
|
private String onUrl;
|
||||||
private String httpVerb;
|
private String httpVerb;
|
||||||
@@ -21,7 +24,23 @@ public class DeviceDescriptor{
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDeviceType() {
|
public String getMapId() {
|
||||||
|
return mapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapId(String mapId) {
|
||||||
|
this.mapId = mapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMapType() {
|
||||||
|
return mapType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapType(String mapType) {
|
||||||
|
this.mapType = mapType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceType() {
|
||||||
return deviceType;
|
return deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +48,15 @@ public class DeviceDescriptor{
|
|||||||
this.deviceType = deviceType;
|
this.deviceType = deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOffUrl() {
|
public String getTargetDevice() {
|
||||||
|
return targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetDevice(String targetDevice) {
|
||||||
|
this.targetDevice = targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOffUrl() {
|
||||||
return offUrl;
|
return offUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ 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.FileSystem;
|
import java.nio.file.DirectoryStream;
|
||||||
import java.nio.file.FileSystems;
|
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;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -34,8 +38,16 @@ public class DeviceRepository {
|
|||||||
|
|
||||||
public DeviceRepository(String deviceDb) {
|
public DeviceRepository(String deviceDb) {
|
||||||
super();
|
super();
|
||||||
repositoryPath = Paths.get(deviceDb);
|
_loadRepository(deviceDb);
|
||||||
String jsonContent = repositoryReader(repositoryPath);
|
}
|
||||||
|
|
||||||
|
private void _loadRepository(String aFilePath){
|
||||||
|
repositoryPath = Paths.get(aFilePath);
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _loadRepository(Path aPath){
|
||||||
|
String jsonContent = repositoryReader(aPath);
|
||||||
devices = new HashMap<String, DeviceDescriptor>();
|
devices = new HashMap<String, DeviceDescriptor>();
|
||||||
|
|
||||||
if(jsonContent != null)
|
if(jsonContent != null)
|
||||||
@@ -48,7 +60,8 @@ public class DeviceRepository {
|
|||||||
put(theDevice.getId(), theDevice);
|
put(theDevice.getId(), theDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
||||||
public List<DeviceDescriptor> findAll() {
|
public List<DeviceDescriptor> findAll() {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||||
@@ -80,6 +93,66 @@ public class DeviceRepository {
|
|||||||
log.debug("Save device: " + aDescriptor.getName());
|
log.debug("Save device: " + aDescriptor.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String backup(String aFilename) {
|
||||||
|
if(aFilename == null || aFilename.equalsIgnoreCase("")) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||||
|
aFilename = "devicedb-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aFilename = aFilename + ".bk";
|
||||||
|
try {
|
||||||
|
Files.copy(repositoryPath, FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), StandardCopyOption.COPY_ATTRIBUTES);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not backup to file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
log.debug("Backup repository: " + aFilename);
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String deleteBackup(String aFilename) {
|
||||||
|
log.debug("Delete backup repository: " + aFilename);
|
||||||
|
try {
|
||||||
|
Files.delete(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not delete file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String restoreBackup(String aFilename) {
|
||||||
|
log.debug("Restore backup repository: " + aFilename);
|
||||||
|
try {
|
||||||
|
Path target = null;
|
||||||
|
if(Files.exists(repositoryPath)) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||||
|
target = FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), "devicedb-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk");
|
||||||
|
Files.move(repositoryPath, target);
|
||||||
|
}
|
||||||
|
Files.copy(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), repositoryPath, StandardCopyOption.COPY_ATTRIBUTES);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error restoring the file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getBackups() {
|
||||||
|
List<String> theFilenames = new ArrayList<String>();
|
||||||
|
Path dir = repositoryPath.getParent();
|
||||||
|
try (DirectoryStream<Path> stream =
|
||||||
|
Files.newDirectoryStream(dir, "*.{bk}")) {
|
||||||
|
for (Path entry: stream) {
|
||||||
|
theFilenames.add(entry.getFileName().toString());
|
||||||
|
}
|
||||||
|
} catch (IOException x) {
|
||||||
|
// IOException can never be thrown by the iteration.
|
||||||
|
// In this snippet, it can // only be thrown by newDirectoryStream.
|
||||||
|
log.error("Issue getting direcotyr listing for backups - " + x.getMessage());
|
||||||
|
}
|
||||||
|
return theFilenames;
|
||||||
|
}
|
||||||
|
|
||||||
public String delete(DeviceDescriptor aDescriptor) {
|
public String delete(DeviceDescriptor aDescriptor) {
|
||||||
if (aDescriptor != null) {
|
if (aDescriptor != null) {
|
||||||
devices.remove(aDescriptor.getId());
|
devices.remove(aDescriptor.getId());
|
||||||
@@ -108,10 +181,14 @@ public class DeviceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path target = FileSystems.getDefault().getPath("data", "device.db.old");
|
Path target = null;
|
||||||
Files.move(filePath, target);
|
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);
|
||||||
Files.delete(target);
|
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);
|
||||||
}
|
}
|
||||||
@@ -121,7 +198,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +252,18 @@ public class DeviceRepository {
|
|||||||
} else if (name.equals("name")) {
|
} else if (name.equals("name")) {
|
||||||
deviceEntry.setName(reader.nextString());
|
deviceEntry.setName(reader.nextString());
|
||||||
log.debug("Read a Device - device json name: " + deviceEntry.getName());
|
log.debug("Read a Device - device json name: " + deviceEntry.getName());
|
||||||
|
} else if (name.equals("mapType")) {
|
||||||
|
deviceEntry.setMapType(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json name: " + deviceEntry.getMapType());
|
||||||
|
} else if (name.equals("mapId")) {
|
||||||
|
deviceEntry.setMapId(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json name: " + deviceEntry.getMapId());
|
||||||
} else if (name.equals("deviceType")) {
|
} else if (name.equals("deviceType")) {
|
||||||
deviceEntry.setDeviceType(reader.nextString());
|
deviceEntry.setDeviceType(reader.nextString());
|
||||||
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
|
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
|
||||||
|
} else if (name.equals("targetDevice")) {
|
||||||
|
deviceEntry.setTargetDevice(reader.nextString());
|
||||||
|
log.debug("Read a Device - device json type:" + deviceEntry.getTargetDevice());
|
||||||
} else if (name.equals("offUrl")) {
|
} else if (name.equals("offUrl")) {
|
||||||
deviceEntry.setOffUrl(reader.nextString());
|
deviceEntry.setOffUrl(reader.nextString());
|
||||||
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());
|
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bwssystems.HABridge.devicemanagmeent;
|
package com.bwssystems.HABridge.devicemanagmeent;
|
||||||
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
|
import static spark.Spark.options;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
import static spark.Spark.delete;
|
import static spark.Spark.delete;
|
||||||
@@ -16,9 +17,14 @@ 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.BackupFilename;
|
||||||
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.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
import com.bwssystems.luupRequests.Sdata;
|
import com.bwssystems.luupRequests.Sdata;
|
||||||
|
import com.bwssystems.vera.VeraHome;
|
||||||
import com.bwssystems.vera.VeraInfo;
|
import com.bwssystems.vera.VeraInfo;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@@ -30,13 +36,31 @@ public class DeviceResource {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
||||||
|
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
private VeraInfo veraInfo;
|
private VeraHome veraHome;
|
||||||
|
private Version version;
|
||||||
|
private HarmonyHome myHarmonyHome;
|
||||||
|
private NestHome nestHome;
|
||||||
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, HarmonyHome theHarmonyHome, NestHome aNestHome) {
|
||||||
super();
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
|
||||||
veraInfo = new VeraInfo(theSettings.getVeraAddress());
|
if(theSettings.isValidVera())
|
||||||
|
this.veraHome = new VeraHome(theSettings);
|
||||||
|
else
|
||||||
|
this.veraHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidHarmony())
|
||||||
|
this.myHarmonyHome = theHarmonyHome;
|
||||||
|
else
|
||||||
|
this.myHarmonyHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidNest())
|
||||||
|
this.nestHome = aNestHome;
|
||||||
|
else
|
||||||
|
this.nestHome = null;
|
||||||
|
|
||||||
|
this.version = theVersion;
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +70,15 @@ public class DeviceResource {
|
|||||||
|
|
||||||
private void setupEndpoints() {
|
private void setupEndpoints() {
|
||||||
log.info("HABridge device management service started.... ");
|
log.info("HABridge device management service started.... ");
|
||||||
|
// http://ip_address:port/api/devices CORS request
|
||||||
|
options(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
post(API_CONTEXT, "application/json", (request, response) -> {
|
post(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
log.debug("Create a Device - request body: " + request.body());
|
log.debug("Create a Device - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
@@ -61,11 +94,21 @@ public class DeviceResource {
|
|||||||
deviceRepository.save(device);
|
deviceRepository.save(device);
|
||||||
log.debug("Created a Device: " + request.body());
|
log.debug("Created a Device: " + request.body());
|
||||||
|
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.status(HttpStatus.SC_CREATED);
|
response.status(HttpStatus.SC_CREATED);
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/:id CORS request
|
||||||
|
options(API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Edit a Device - request body: " + request.body());
|
log.debug("Edit a Device - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
@@ -81,6 +124,9 @@ public class DeviceResource {
|
|||||||
deviceEntry.setName(device.getName());
|
deviceEntry.setName(device.getName());
|
||||||
if (device.getDeviceType() != null)
|
if (device.getDeviceType() != null)
|
||||||
deviceEntry.setDeviceType(device.getDeviceType());
|
deviceEntry.setDeviceType(device.getDeviceType());
|
||||||
|
deviceEntry.setMapId(device.getMapId());
|
||||||
|
deviceEntry.setMapType(device.getMapType());
|
||||||
|
deviceEntry.setTargetDevice(device.getTargetDevice());
|
||||||
deviceEntry.setOnUrl(device.getOnUrl());
|
deviceEntry.setOnUrl(device.getOnUrl());
|
||||||
deviceEntry.setOffUrl(device.getOffUrl());
|
deviceEntry.setOffUrl(device.getOffUrl());
|
||||||
deviceEntry.setHttpVerb(device.getHttpVerb());
|
deviceEntry.setHttpVerb(device.getHttpVerb());
|
||||||
@@ -115,8 +161,9 @@ public class DeviceResource {
|
|||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Delete a device");
|
String anId = request.params(":id");
|
||||||
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
|
log.debug("Delete a device: " + anId);
|
||||||
|
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
||||||
if(deleted == null)
|
if(deleted == null)
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
else
|
else
|
||||||
@@ -127,28 +174,132 @@ 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();
|
if(veraHome == null){
|
||||||
if(sData == null){
|
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return sData.getDevices();
|
return veraHome.getDevices();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/vera/scenes", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/vera/scenes", "application/json", (request, response) -> {
|
||||||
log.debug("Get vera scenes");
|
log.debug("Get vera scenes");
|
||||||
Sdata sData = veraInfo.getSdata();
|
if(veraHome == null){
|
||||||
if(sData == null){
|
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return sData.getScenes();
|
return veraHome.getScenes();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony activities");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getActivities();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony current activity");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getCurrentActivities();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony devices");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/nest/items", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get nest items");
|
||||||
|
if(nestHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return nestHome.getItems();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get backup filenames");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return deviceRepository.getBackups();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/create CORS request
|
||||||
|
options(API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
BackupFilename returnFilename = new BackupFilename();
|
||||||
|
returnFilename.setFilename(deviceRepository.backup(aFilename.getFilename()));
|
||||||
|
return returnFilename;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/delete CORS request
|
||||||
|
options(API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
log.debug("Delete backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null)
|
||||||
|
deviceRepository.deleteBackup(aFilename.getFilename());
|
||||||
|
else
|
||||||
|
log.warn("No filename given for delete backup.");
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/restore CORS request
|
||||||
|
options(API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
log.debug("Restore backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null)
|
||||||
|
deviceRepository.restoreBackup(aFilename.getFilename());
|
||||||
|
else
|
||||||
|
log.warn("No filename given for restore backup.");
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,27 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
import com.bwssystems.HABridge.JsonTransformer;
|
||||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
import com.bwssystems.HABridge.dao.*;
|
import com.bwssystems.HABridge.dao.*;
|
||||||
|
import com.bwssystems.NestBridge.NestInstruction;
|
||||||
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.harmony.ButtonPress;
|
||||||
|
import com.bwssystems.harmony.HarmonyHandler;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.bwssystems.harmony.RunActivity;
|
||||||
|
import com.bwssystems.nest.controller.Nest;
|
||||||
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 javax.script.ScriptEngineManager;
|
|
||||||
import javax.script.ScriptException;
|
import net.java.dev.eval.Expression;
|
||||||
import javax.script.ScriptEngine;
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
|
import static spark.Spark.options;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
|
|
||||||
@@ -32,10 +41,16 @@ 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.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
||||||
*/
|
*/
|
||||||
@@ -47,27 +62,41 @@ public class HueMulator {
|
|||||||
private static final String INTENSITY_MATH = "${intensity.math(";
|
private static final String INTENSITY_MATH = "${intensity.math(";
|
||||||
private static final String INTENSITY_MATH_VALUE = "X";
|
private static final String INTENSITY_MATH_VALUE = "X";
|
||||||
private static final String INTENSITY_MATH_CLOSE = ")}";
|
private static final String INTENSITY_MATH_CLOSE = ")}";
|
||||||
private static final String ENGINE_JAVASCRIPT = "JavaScript";
|
|
||||||
private static final String HUE_CONTEXT = "/api";
|
private static final String HUE_CONTEXT = "/api";
|
||||||
|
|
||||||
private DeviceRepository repository;
|
private DeviceRepository repository;
|
||||||
|
private HarmonyHome myHarmonyHome;
|
||||||
|
private Nest theNest;
|
||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private ObjectMapper mapper;
|
private ObjectMapper mapper;
|
||||||
|
private BridgeSettings bridgeSettings;
|
||||||
|
private byte[] sendData;
|
||||||
|
|
||||||
|
|
||||||
public HueMulator(DeviceRepository aDeviceRepository){
|
public HueMulator(BridgeSettings theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome){
|
||||||
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;
|
||||||
|
if(theBridgeSettings.isValidHarmony())
|
||||||
|
this.myHarmonyHome = theHarmonyHome;
|
||||||
|
else
|
||||||
|
this.myHarmonyHome = null;
|
||||||
|
if(theBridgeSettings.isValidNest())
|
||||||
|
this.theNest = aNestHome.getTheNest();
|
||||||
|
else
|
||||||
|
this.theNest = null;
|
||||||
|
bridgeSettings = theBridgeSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function sets up the sparkjava rest calls for the hue api
|
// This function sets up the sparkjava rest calls for the hue api
|
||||||
public void setupServer() {
|
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) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue lights list requested: " + userId + " from " + request.ip());
|
||||||
log.debug("hue lights list requested: " + userId + " from " + request.ip());
|
log.debug("hue lights list requested: " + userId + " from " + request.ip());
|
||||||
List<DeviceDescriptor> deviceList = repository.findAll();
|
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
||||||
@@ -80,12 +109,23 @@ public class HueMulator {
|
|||||||
return deviceResponseMap;
|
return deviceResponseMap;
|
||||||
} , new JsonTransformer());
|
} , new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api with body of user request returns json object for a success of user add
|
// http://ip_address:port/api CORS request
|
||||||
|
options(HUE_CONTEXT, "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/api with body of user request returns json object for a success of user add
|
||||||
post(HUE_CONTEXT, "application/json", (request, response) -> {
|
post(HUE_CONTEXT, "application/json", (request, response) -> {
|
||||||
UserCreateRequest aNewUser = null;
|
UserCreateRequest aNewUser = null;
|
||||||
String newUser = null;
|
String newUser = null;
|
||||||
String aDeviceType = null;
|
String aDeviceType = null;
|
||||||
|
|
||||||
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue api/ user create requested: " + request.body() + " from " + request.ip());
|
||||||
log.debug("hue api user create requested: " + request.body() + " from " + request.ip());
|
log.debug("hue api user create requested: " + request.body() + " from " + request.ip());
|
||||||
|
|
||||||
if(request.body() != null && !request.body().isEmpty()) {
|
if(request.body() != null && !request.body().isEmpty()) {
|
||||||
@@ -98,20 +138,33 @@ public class HueMulator {
|
|||||||
|
|
||||||
if(aDeviceType == null)
|
if(aDeviceType == null)
|
||||||
aDeviceType = "<not given>";
|
aDeviceType = "<not given>";
|
||||||
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
||||||
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
||||||
|
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.type("application/json; charset=utf-8");
|
response.type("application/json; charset=utf-8");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// http://ip_address:port/api/* CORS request
|
||||||
|
options(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
// http://ip_address:port/api/* with body of user request returns json object for a success of user add - This method is for Harmony Hub
|
// http://ip_address:port/api/* with body of user request returns json object for a success of user add - This method is for Harmony Hub
|
||||||
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
||||||
UserCreateRequest aNewUser = null;
|
UserCreateRequest aNewUser = null;
|
||||||
String newUser = null;
|
String newUser = null;
|
||||||
String aDeviceType = null;
|
String aDeviceType = null;
|
||||||
|
|
||||||
log.info("HH trace: hue api user create requested: " + request.body() + " from " + request.ip());
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue api/* user create requested: " + request.body() + " from " + request.ip());
|
||||||
|
|
||||||
if(request.body() != null && !request.body().isEmpty()) {
|
if(request.body() != null && !request.body().isEmpty()) {
|
||||||
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
|
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
|
||||||
@@ -125,12 +178,42 @@ public class HueMulator {
|
|||||||
aDeviceType = "<not given>";
|
aDeviceType = "<not given>";
|
||||||
log.debug("HH trace: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
log.debug("HH trace: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
|
||||||
|
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.type("application/json; charset=utf-8");
|
response.type("application/json; charset=utf-8");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// http://ip_address:port/api/{userId} returns json objects for the full state
|
// http://ip_address:port/api/config returns json objects for the config when no user is given
|
||||||
|
get(HUE_CONTEXT + "/config", "application/json", (request, response) -> {
|
||||||
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue api/config config requested: <no_user> from " + request.ip());
|
||||||
|
log.debug("hue api config requested: <no_user> from " + request.ip());
|
||||||
|
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", "none");
|
||||||
|
|
||||||
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
// String responseString = null;
|
||||||
|
// responseString = "[{\"swversion\":\"" + apiResponse.getConfig().getSwversion() + "\",\"apiversion\":\"" + apiResponse.getConfig().getApiversion() + "\",\"name\":\"" + apiResponse.getConfig().getName() + "\",\"mac\":\"" + apiResponse.getConfig().getMac() + "\"}]";
|
||||||
|
// return responseString;
|
||||||
|
return apiResponse.getConfig();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/{userId}/config returns json objects for the config
|
||||||
|
get(HUE_CONTEXT + "/:userid/config", "application/json", (request, response) -> {
|
||||||
|
String userId = request.params(":userid");
|
||||||
|
if(bridgeSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + request.ip());
|
||||||
|
log.debug("hue api config requested: " + userId + " from " + request.ip());
|
||||||
|
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId);
|
||||||
|
|
||||||
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return apiResponse.getConfig();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
|
||||||
|
// http://ip_address:port/api/{userId} returns json objects for the full state
|
||||||
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
|
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
||||||
@@ -146,7 +229,7 @@ public class HueMulator {
|
|||||||
deviceList.put(descriptor.getId(), deviceResponse);
|
deviceList.put(descriptor.getId(), deviceResponse);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", request.ip(), "My App", userId);
|
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId);
|
||||||
apiResponse.setLights(deviceList);
|
apiResponse.setLights(deviceList);
|
||||||
|
|
||||||
response.type("application/json; charset=utf-8");
|
response.type("application/json; charset=utf-8");
|
||||||
@@ -154,7 +237,7 @@ public class HueMulator {
|
|||||||
return apiResponse;
|
return apiResponse;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api/{userId}/lights/{lightId} returns json object for a given light
|
// http://ip_address:port/api/{userId}/lights/{lightId} returns json object for a given light
|
||||||
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
|
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
String lightId = request.params(":id");
|
String lightId = request.params(":id");
|
||||||
@@ -173,7 +256,16 @@ public class HueMulator {
|
|||||||
return lightResponse;
|
return lightResponse;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api/{userId}/lights/{lightId}/state uses json object to set the lights state
|
// http://ip_address:port/api/:userid/lights/:id/state CORS request
|
||||||
|
options(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/api/{userId}/lights/{lightId}/state uses json object to set the lights state
|
||||||
put(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
|
put(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
|
||||||
/**
|
/**
|
||||||
* strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
|
* strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
|
||||||
@@ -181,50 +273,170 @@ public class HueMulator {
|
|||||||
*/
|
*/
|
||||||
String userId = request.params(":userid");
|
String userId = request.params(":userid");
|
||||||
String lightId = request.params(":id");
|
String lightId = request.params(":id");
|
||||||
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
String responseString = null;
|
||||||
|
String url = null;
|
||||||
DeviceState state = null;
|
DeviceState state = null;
|
||||||
|
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.type("application/json; charset=utf-8");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state = mapper.readValue(request.body(), DeviceState.class);
|
state = mapper.readValue(request.body(), DeviceState.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Object mapper barfed on input of body.", e);
|
log.warn("Object mapper barfed on input of body.", e);
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + ",\"description\": \"Object mapper barfed on input of body.\"}}]";
|
||||||
return null;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceDescriptor device = repository.findOne(lightId);
|
DeviceDescriptor device = repository.findOne(lightId);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
log.error("Could not find devcie: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + ",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||||
return null;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
String responseString;
|
|
||||||
String url;
|
|
||||||
if (state.isOn()) {
|
if (state.isOn()) {
|
||||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]";
|
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}";
|
||||||
url = device.getOnUrl();
|
url = device.getOnUrl();
|
||||||
} else {
|
} else if (request.body().contains("false")) {
|
||||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
|
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}";
|
||||||
url = device.getOffUrl();
|
url = device.getOffUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
//quick template
|
if(request.body().contains("bri"))
|
||||||
String body;
|
{
|
||||||
url = replaceIntensityValue(url, state.getBri());
|
if(url == null)
|
||||||
if (state.isOn())
|
{
|
||||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
url = device.getOnUrl();
|
||||||
|
responseString = "[";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
responseString = responseString + ",";
|
||||||
|
|
||||||
|
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
responseString = responseString + "]";
|
||||||
//make call
|
|
||||||
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
|
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
{
|
||||||
log.error("Error on calling url to change device state: " + url);
|
log.debug("executing HUE api request to change activity to Harmony: " + url);
|
||||||
return null;
|
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
|
||||||
|
HarmonyHandler myHarmony = myHarmonyHome.getHarmonyHandler(device.getTargetDevice());
|
||||||
|
if(myHarmony == null)
|
||||||
|
{
|
||||||
|
log.warn("Should not get here, no harmony hub available");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
myHarmony.startActivity(anActivity);
|
||||||
|
}
|
||||||
|
else if(device.getDeviceType().toLowerCase().contains("button") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to button press(es) to Harmony: " + url);
|
||||||
|
if(url.substring(0, 1).equalsIgnoreCase("{")) {
|
||||||
|
url = "[" + url +"]";
|
||||||
|
}
|
||||||
|
ButtonPress[] deviceButtons = new Gson().fromJson(url, ButtonPress[].class);
|
||||||
|
HarmonyHandler myHarmony = myHarmonyHome.getHarmonyHandler(device.getTargetDevice());
|
||||||
|
if(myHarmony == null)
|
||||||
|
{
|
||||||
|
log.warn("Should not get here, no harmony hub available");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(int i = 0; i < deviceButtons.length; i++) {
|
||||||
|
if( i > 0)
|
||||||
|
Thread.sleep(100);
|
||||||
|
log.debug("pressing button: " + deviceButtons[i].getDevice() + " - " + deviceButtons[i].getButton() + " - iteration: " + String.valueOf(i));
|
||||||
|
myHarmony.pressButton(deviceButtons[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(device.getDeviceType().toLowerCase().contains("home") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestHomeAway")))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to set away for nest home: " + url);
|
||||||
|
NestInstruction homeAway = new Gson().fromJson(url, NestInstruction.class);
|
||||||
|
if(theNest == null)
|
||||||
|
{
|
||||||
|
log.warn("Should not get here, no Nest available");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no Nest available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
theNest.getHome(homeAway.getName()).setAway(homeAway.getAway());
|
||||||
|
}
|
||||||
|
else if(device.getDeviceType().toLowerCase().contains("thermo") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestThermoSet")))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to set thermostat for nest: " + url);
|
||||||
|
NestInstruction thermoSetting = new Gson().fromJson(url, NestInstruction.class);
|
||||||
|
if(theNest == null)
|
||||||
|
{
|
||||||
|
log.warn("Should not get here, no Nest available");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no Nest available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
|
||||||
|
if(request.body().contains("bri")) {
|
||||||
|
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri())) - 32.0)/1.8));
|
||||||
|
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
|
||||||
|
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (thermoSetting.getControl().contains("range") ||thermoSetting.getControl().contains("heat") ||thermoSetting.getControl().contains("cool") ||thermoSetting.getControl().contains("off")) {
|
||||||
|
log.debug("Setting thermostat target type: " + thermoSetting.getName() + " to " + thermoSetting.getControl());
|
||||||
|
theNest.getThermostat(thermoSetting.getName()).setTargetType(thermoSetting.getControl());
|
||||||
|
}
|
||||||
|
else if(thermoSetting.getControl().contains("fan")) {
|
||||||
|
log.debug("Setting thermostat fan mode: " + thermoSetting.getName() + " to " + thermoSetting.getControl().substring(4));
|
||||||
|
theNest.getThermostat(thermoSetting.getName()).setFanMode(thermoSetting.getControl().substring(4));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("no valid Nest control info: " + thermoSetting.getControl());
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"no valid Nest control info\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(url.startsWith("udp://"))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to UDP: " + url);
|
||||||
|
try {
|
||||||
|
String intermediate = url.substring(6);
|
||||||
|
String ipAddr = intermediate.substring(0, intermediate.indexOf(':'));
|
||||||
|
String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/'));
|
||||||
|
String theBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||||
|
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||||
|
if(theBody.startsWith("0x")) {
|
||||||
|
sendData = DatatypeConverter.parseHexBinary(theBody.substring(2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sendData = theBody.getBytes();
|
||||||
|
InetAddress IPAddress = InetAddress.getByName(ipAddr);
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||||
|
responseSocket.send(sendPacket);
|
||||||
|
responseSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not send UDP Datagram packet for request.", e);
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + 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)) {
|
||||||
|
log.warn("Error on calling url to change device state: " + url);
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.type("application/json; charset=utf-8");
|
|
||||||
response.status(HttpStatus.SC_OK);
|
|
||||||
return responseString;
|
return responseString;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -232,9 +444,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){
|
||||||
@@ -248,17 +461,20 @@ public class HueMulator {
|
|||||||
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)){
|
} 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));
|
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
|
||||||
String updatedMath = mathDescriptor.replace(INTENSITY_MATH_VALUE, String.valueOf(intensity));
|
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
||||||
ScriptEngineManager mgr = new ScriptEngineManager();
|
|
||||||
ScriptEngine engine = mgr.getEngineByName(ENGINE_JAVASCRIPT);
|
|
||||||
try {
|
try {
|
||||||
log.debug("Math eval is: " + updatedMath);
|
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: " + String.valueOf(intensity));
|
||||||
Integer endResult = (Integer) engine.eval(updatedMath);
|
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());
|
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
|
||||||
} catch (ScriptException e) {
|
} catch (Exception e) {
|
||||||
log.error("Could not execute Math: " + updatedMath, e);
|
log.warn("Could not execute Math: " + mathDescriptor, e);
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,12 +501,12 @@ public class HueMulator {
|
|||||||
try {
|
try {
|
||||||
HttpResponse response = httpClient.execute(request);
|
HttpResponse response = httpClient.execute(request);
|
||||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
log.debug("Execute on URL responded: " + response.getStatusLine().getStatusCode());
|
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
if(response.getStatusLine().getStatusCode() == 200){
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error calling out to HA gateway", e);
|
log.warn("Error calling out to HA gateway", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(){
|
||||||
@@ -79,14 +76,7 @@ public class UpnpListener {
|
|||||||
byte[] buf = new byte[1024];
|
byte[] buf = new byte[1024];
|
||||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
upnpMulticastSocket.receive(packet);
|
upnpMulticastSocket.receive(packet);
|
||||||
String packetString = new String(packet.getData());
|
if(isSSDPDiscovery(packet)){
|
||||||
if(packetString != null && packetString.contains("M-SEARCH")) {
|
|
||||||
if(traceupnp)
|
|
||||||
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
|
||||||
else
|
|
||||||
log.debug("Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
|
||||||
}
|
|
||||||
if(isSSDPDiscovery(packetString)){
|
|
||||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,31 +90,40 @@ public class UpnpListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* very naive ssdp discovery packet detection
|
* ssdp discovery packet detection
|
||||||
* @param body
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
protected boolean isSSDPDiscovery(String body){
|
protected boolean isSSDPDiscovery(DatagramPacket packet){
|
||||||
// log.debug("Check if this is a MAN ssdp-discover packet for a upnp basic device: " + body);
|
//Only respond to discover request for strict upnp form
|
||||||
//Only respond to discover request for upnp basic device from echo, the others are for the wemo
|
String packetString = new String(packet.getData());
|
||||||
if(body != null && body.contains("M-SEARCH") && body.contains("\"ssdp:discover\"")){
|
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")){
|
||||||
if(traceupnp)
|
log.debug("isSSDPDiscovery Found message to be an M-SEARCH message.");
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message.");
|
log.debug("isSSDPDiscovery Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
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 && (packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") || packetString.contains("ST: upnp:rootdevice") || packetString.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 an M-SEARCH message.");
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
|
||||||
|
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
}
|
||||||
|
log.debug("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 an M-SEARCH message.");
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
|
||||||
|
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
}
|
||||||
|
log.debug("isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(traceupnp)
|
else {
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to not be valid - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
// log.debug("isSSDPDiscovery found message to not be valid - strict: " + strict);
|
||||||
|
// log.debug("SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,20 +134,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);
|
||||||
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
|
||||||
@@ -156,8 +144,4 @@ public class UpnpListener {
|
|||||||
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
||||||
socket.send(response);
|
socket.send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getRandomUUIDString(){
|
|
||||||
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,56 +40,20 @@ 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" +
|
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
|
||||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n" +
|
|
||||||
"<specVersion>\n" +
|
|
||||||
"<major>1</major>\n" +
|
|
||||||
"<minor>0</minor>\n" +
|
|
||||||
"</specVersion>\n" +
|
|
||||||
"<URLBase>http://%s:%s/</URLBase>\n" + //hostname string
|
|
||||||
"<device>\n" +
|
|
||||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n" +
|
|
||||||
"<friendlyName>Amazon-Echo-HA-Bridge (%s)</friendlyName>\n" +
|
|
||||||
"<manufacturer>Royal Philips Electronics</manufacturer>\n" +
|
|
||||||
"<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n" +
|
|
||||||
"<modelDescription>Hue Emulator for Amazon Echo bridge</modelDescription>\n" +
|
|
||||||
"<modelName>Philips hue bridge 2012</modelName>\n" +
|
|
||||||
"<modelNumber>929000226503</modelNumber>\n" +
|
|
||||||
"<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n" +
|
|
||||||
"<serialNumber>01189998819991197253</serialNumber>\n" +
|
|
||||||
"<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" +
|
|
||||||
"<serviceList>\n" +
|
|
||||||
"<service>\n" +
|
|
||||||
"<serviceType>(null)</serviceType>\n" +
|
|
||||||
"<serviceId>(null)</serviceId>\n" +
|
|
||||||
"<controlURL>(null)</controlURL>\n" +
|
|
||||||
"<eventSubURL>(null)</eventSubURL>\n" +
|
|
||||||
"<SCPDURL>(null)</SCPDURL>\n" +
|
|
||||||
"</service>\n" +
|
|
||||||
"</serviceList>\n" +
|
|
||||||
"<presentationURL>index.html</presentationURL>\n" +
|
|
||||||
"<iconList>\n" +
|
|
||||||
"<icon>\n" +
|
|
||||||
"<mimetype>image/png</mimetype>\n" +
|
|
||||||
"<height>48</height>\n" +
|
|
||||||
"<width>48</width>\n" +
|
|
||||||
"<depth>24</depth>\n" +
|
|
||||||
"<url>hue_logo_0.png</url>\n" +
|
|
||||||
"</icon>\n" +
|
|
||||||
"<icon>\n" +
|
|
||||||
"<mimetype>image/png</mimetype>\n" +
|
|
||||||
"<height>120</height>\n" +
|
|
||||||
"<width>120</width>\n" +
|
|
||||||
"<depth>24</depth>\n" +
|
|
||||||
"<url>hue_logo_3.png</url>\n" +
|
|
||||||
"</icon>\n" +
|
|
||||||
"</iconList>\n" +
|
|
||||||
"</device>\n" +
|
|
||||||
"</root>\n";
|
|
||||||
|
|
||||||
public UpnpSettingsResource(BridgeSettings theSettings) {
|
|
||||||
super();
|
super();
|
||||||
this.theSettings = theSettings;
|
this.theSettings = new BridgeSettings();
|
||||||
|
this.theSettings.setDevMode(theBridgeSettings.isDevMode());
|
||||||
|
this.theSettings.setHarmonyAddress(theBridgeSettings.getHarmonyAddress());
|
||||||
|
this.theSettings.setServerPort(theBridgeSettings.getServerPort());
|
||||||
|
this.theSettings.setTraceupnp(theBridgeSettings.isTraceupnp());
|
||||||
|
this.theSettings.setUpnpConfigAddress(theBridgeSettings.getUpnpConfigAddress());
|
||||||
|
this.theSettings.setUpnpDeviceDb(theBridgeSettings.getUpnpDeviceDb());
|
||||||
|
this.theSettings.setUpnpResponseDevices(theBridgeSettings.getUpnpResponseDevices());
|
||||||
|
this.theSettings.setUpnpResponsePort(theBridgeSettings.getUpnpResponsePort());
|
||||||
|
this.theSettings.setUpnpStrict(theBridgeSettings.isUpnpStrict());
|
||||||
|
this.theSettings.setVeraAddress(theBridgeSettings.getVeraAddress());
|
||||||
|
this.theSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupServer() {
|
public void setupServer() {
|
||||||
@@ -102,10 +66,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
|
||||||
|
|||||||
101
src/main/java/com/bwssystems/NestBridge/NestHome.java
Normal file
101
src/main/java/com/bwssystems/NestBridge/NestHome.java
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
|
import com.bwssystems.nest.controller.Home;
|
||||||
|
import com.bwssystems.nest.controller.Nest;
|
||||||
|
import com.bwssystems.nest.controller.NestSession;
|
||||||
|
import com.bwssystems.nest.controller.Thermostat;
|
||||||
|
import com.bwssystems.nest.protocol.error.LoginException;
|
||||||
|
import com.bwssystems.nest.protocol.status.WhereDetail;
|
||||||
|
import com.bwssystems.nest.protocol.status.WhereItem;
|
||||||
|
|
||||||
|
public class NestHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NestHome.class);
|
||||||
|
private NestSession theSession;
|
||||||
|
private Nest theNest;
|
||||||
|
private ArrayList<NestItem> nestItems;
|
||||||
|
|
||||||
|
public NestHome(BridgeSettings bridgeSettings) {
|
||||||
|
theSession = null;
|
||||||
|
theNest = null;
|
||||||
|
nestItems = null;
|
||||||
|
|
||||||
|
if(!bridgeSettings.isValidNest()) {
|
||||||
|
log.info("not a valid nest");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
theSession = new NestSession(bridgeSettings.getNestuser(), bridgeSettings.getNestpwd());
|
||||||
|
theNest = new Nest(theSession);
|
||||||
|
} catch (LoginException e) {
|
||||||
|
log.error("Caught Login Exception, exiting....");
|
||||||
|
theSession = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NestItem> getItems() {
|
||||||
|
if(theNest == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if(nestItems == null) {
|
||||||
|
nestItems = new ArrayList<NestItem>();
|
||||||
|
Set<String> homeNames = theNest.getHomeNames();
|
||||||
|
Home aHome = null;
|
||||||
|
NestItem anItem = null;
|
||||||
|
for(String name : homeNames) {
|
||||||
|
aHome = theNest.getHome(name);
|
||||||
|
anItem = new NestItem();
|
||||||
|
anItem.setId(name);
|
||||||
|
anItem.setName(aHome.getDetail().getName());
|
||||||
|
anItem.setType("Home");
|
||||||
|
anItem.setLocation(aHome.getDetail().getLocation());
|
||||||
|
nestItems.add(anItem);
|
||||||
|
}
|
||||||
|
Thermostat thermo = null;
|
||||||
|
Set<String> thermoNames = theNest.getThermostatNames();
|
||||||
|
for(String name : thermoNames) {
|
||||||
|
thermo = theNest.getThermostat(name);
|
||||||
|
anItem = new NestItem();
|
||||||
|
anItem.setId(name);
|
||||||
|
anItem.setType("Thermostat");
|
||||||
|
String where = null;
|
||||||
|
String homeName= null;
|
||||||
|
Boolean found = false;
|
||||||
|
for(String aHomeName : homeNames) {
|
||||||
|
WhereDetail aDetail = theNest.getWhere(aHomeName);
|
||||||
|
ListIterator<WhereItem> anIterator = aDetail.getWheres().listIterator();
|
||||||
|
while(anIterator.hasNext()) {
|
||||||
|
WhereItem aWhereItem = (WhereItem) anIterator.next();
|
||||||
|
if(aWhereItem.getWhereId().equals(thermo.getDeviceDetail().getWhereId())) {
|
||||||
|
where = aWhereItem.getName();
|
||||||
|
homeName = theNest.getHome(aHomeName).getDetail().getName();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
anItem.setName(where + "(" + name.substring(name.length() - 4) + ")");
|
||||||
|
anItem.setLocation(where + " - " + homeName);
|
||||||
|
nestItems.add(anItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nestItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Nest getTheNest() {
|
||||||
|
return theNest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
33
src/main/java/com/bwssystems/NestBridge/NestInstruction.java
Normal file
33
src/main/java/com/bwssystems/NestBridge/NestInstruction.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
public class NestInstruction {
|
||||||
|
private String name;
|
||||||
|
private Boolean away;
|
||||||
|
private String control;
|
||||||
|
private String temp;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Boolean getAway() {
|
||||||
|
return away;
|
||||||
|
}
|
||||||
|
public void setAway(Boolean away) {
|
||||||
|
this.away = away;
|
||||||
|
}
|
||||||
|
public String getControl() {
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
public void setControl(String control) {
|
||||||
|
this.control = control;
|
||||||
|
}
|
||||||
|
public String getTemp() {
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
public void setTemp(String temp) {
|
||||||
|
this.temp = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/com/bwssystems/NestBridge/NestItem.java
Normal file
32
src/main/java/com/bwssystems/NestBridge/NestItem.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
public class NestItem {
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
private String type;
|
||||||
|
private String location;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(String anid) {
|
||||||
|
id = anid;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
21
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
|
||||||
|
public class HarmonyActivity {
|
||||||
|
private String hub;
|
||||||
|
private Activity activity;
|
||||||
|
public String getHub() {
|
||||||
|
return hub;
|
||||||
|
}
|
||||||
|
public void setHub(String hub) {
|
||||||
|
this.hub = hub;
|
||||||
|
}
|
||||||
|
public Activity getActivity() {
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
public void setActivity(Activity activity) {
|
||||||
|
this.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
20
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
|
||||||
|
public class HarmonyDevice {
|
||||||
|
private Device device;
|
||||||
|
private String hub;
|
||||||
|
public Device getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(Device device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
public String getHub() {
|
||||||
|
return hub;
|
||||||
|
}
|
||||||
|
public void setHub(String hub) {
|
||||||
|
this.hub = hub;
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
115
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
|
import com.bwssystems.HABridge.IpList;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
|
||||||
|
public class HarmonyHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||||
|
private Map<String, HarmonyServer> hubs;
|
||||||
|
|
||||||
|
public HarmonyHome(BridgeSettings bridgeSettings) {
|
||||||
|
super();
|
||||||
|
hubs = new HashMap<String, HarmonyServer>();
|
||||||
|
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode())
|
||||||
|
return;
|
||||||
|
if(bridgeSettings.isDevMode()) {
|
||||||
|
NamedIP devModeIp = new NamedIP();
|
||||||
|
devModeIp.setIp("10.10.10.10");
|
||||||
|
devModeIp.setName("devMode");
|
||||||
|
List<NamedIP> theList = new ArrayList<NamedIP>();
|
||||||
|
theList.add(devModeIp);
|
||||||
|
IpList thedevList = new IpList();
|
||||||
|
thedevList.setDevices(theList);
|
||||||
|
bridgeSettings.setHarmonyAddress(thedevList);
|
||||||
|
}
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aHub = theList.next();
|
||||||
|
try {
|
||||||
|
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, aHub));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyHandler getHarmonyHandler(String aName) {
|
||||||
|
HarmonyHandler aHandler = null;
|
||||||
|
if(aName == null || aName.equals("")) {
|
||||||
|
aName = "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hubs.get(aName) == null) {
|
||||||
|
Set<String> keys = hubs.keySet();
|
||||||
|
if(!keys.isEmpty()) {
|
||||||
|
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aHandler = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aHandler = hubs.get(aName).getMyHarmony();
|
||||||
|
return aHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HarmonyActivity> getActivities() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
while(activities.hasNext()) {
|
||||||
|
HarmonyActivity anActivity = new HarmonyActivity();
|
||||||
|
anActivity.setActivity(activities.next());
|
||||||
|
anActivity.setHub(key);
|
||||||
|
activityList.add(anActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activityList;
|
||||||
|
}
|
||||||
|
public List<HarmonyActivity> getCurrentActivities() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
while(activities.hasNext()) {
|
||||||
|
HarmonyActivity anActivity = new HarmonyActivity();
|
||||||
|
anActivity.setActivity(activities.next());
|
||||||
|
anActivity.setHub(key);
|
||||||
|
activityList.add(anActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activityList;
|
||||||
|
}
|
||||||
|
public List<HarmonyDevice> getDevices() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
HarmonyDevice aDevice = new HarmonyDevice();
|
||||||
|
aDevice.setDevice(devices.next());
|
||||||
|
aDevice.setHub(key);
|
||||||
|
deviceList.add(aDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
84
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
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.bwssystems.HABridge.NamedIP;
|
||||||
|
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;
|
||||||
|
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
||||||
|
|
||||||
|
public class HarmonyServer {
|
||||||
|
@Inject
|
||||||
|
private HarmonyClient harmonyClient;
|
||||||
|
|
||||||
|
private HarmonyHandler myHarmony;
|
||||||
|
private DevModeResponse devResponse;
|
||||||
|
private OAReplyProvider dummyProvider;
|
||||||
|
private NamedIP myNameAndIP;
|
||||||
|
|
||||||
|
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||||
|
|
||||||
|
public HarmonyServer(NamedIP theHarmonyAddress) {
|
||||||
|
super();
|
||||||
|
myHarmony = null;
|
||||||
|
dummyProvider = null;
|
||||||
|
myNameAndIP = theHarmonyAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HarmonyServer setup(BridgeSettings bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
|
||||||
|
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode()) {
|
||||||
|
return new HarmonyServer(theHarmonyAddress);
|
||||||
|
}
|
||||||
|
Injector injector = null;
|
||||||
|
if(!bridgeSettings.isDevMode())
|
||||||
|
injector = Guice.createInjector(new HarmonyClientModule());
|
||||||
|
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
||||||
|
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(dummyProvider != null)
|
||||||
|
log.debug("something is very wrong as dummyProvider is not null...");
|
||||||
|
if(mySettings.isDevMode())
|
||||||
|
modeString = " (development mode)";
|
||||||
|
else 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(myNameAndIP.getIp(), 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ public class Device {
|
|||||||
private String level;
|
private String level;
|
||||||
private String state;
|
private String state;
|
||||||
private String comment;
|
private String comment;
|
||||||
|
private String veraname;
|
||||||
|
private String veraaddress;
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -79,5 +81,17 @@ public class Device {
|
|||||||
public void setComment(String comment) {
|
public void setComment(String comment) {
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
}
|
}
|
||||||
|
public String getVeraname() {
|
||||||
|
return veraname;
|
||||||
|
}
|
||||||
|
public void setVeraname(String veraname) {
|
||||||
|
this.veraname = veraname;
|
||||||
|
}
|
||||||
|
public String getVeraaddress() {
|
||||||
|
return veraaddress;
|
||||||
|
}
|
||||||
|
public void setVeraaddress(String veraaddress) {
|
||||||
|
this.veraaddress = veraaddress;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ public class Scene {
|
|||||||
private String name;
|
private String name;
|
||||||
private String id;
|
private String id;
|
||||||
private String room;
|
private String room;
|
||||||
|
private String veraname;
|
||||||
|
private String veraaddress;
|
||||||
public String getActive() {
|
public String getActive() {
|
||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
@@ -29,5 +31,17 @@ public class Scene {
|
|||||||
public void setRoom(String room) {
|
public void setRoom(String room) {
|
||||||
this.room = room;
|
this.room = room;
|
||||||
}
|
}
|
||||||
|
public String getVeraname() {
|
||||||
|
return veraname;
|
||||||
|
}
|
||||||
|
public void setVeraname(String veraname) {
|
||||||
|
this.veraname = veraname;
|
||||||
|
}
|
||||||
|
public String getVeraaddress() {
|
||||||
|
return veraaddress;
|
||||||
|
}
|
||||||
|
public void setVeraaddress(String veraaddress) {
|
||||||
|
this.veraaddress = veraaddress;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/main/java/com/bwssystems/vera/VeraHome.java
Normal file
58
src/main/java/com/bwssystems/vera/VeraHome.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package com.bwssystems.vera;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.luupRequests.Device;
|
||||||
|
import com.bwssystems.luupRequests.Scene;
|
||||||
|
|
||||||
|
public class VeraHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VeraHome.class);
|
||||||
|
private Map<String, VeraInfo> veras;
|
||||||
|
|
||||||
|
public VeraHome(BridgeSettings bridgeSettings) {
|
||||||
|
veras = new HashMap<String, VeraInfo>();
|
||||||
|
if(!bridgeSettings.isValidVera())
|
||||||
|
return;
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getVeraAddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aVera = theList.next();
|
||||||
|
veras.put(aVera.getName(), new VeraInfo(aVera, bridgeSettings.isValidVera()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
log.debug("consolidating devices for veras");
|
||||||
|
Iterator<String> keys = veras.keySet().iterator();
|
||||||
|
ArrayList<Device> deviceList = new ArrayList<Device>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Device> devices = veras.get(key).getSdata().getDevices().iterator();
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
deviceList.add(devices.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
public List<Scene> getScenes() {
|
||||||
|
log.debug("consolidating scenes for veras");
|
||||||
|
Iterator<String> keys = veras.keySet().iterator();
|
||||||
|
ArrayList<Scene> sceneList = new ArrayList<Scene>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Scene> scenes = veras.get(key).getSdata().getScenes().iterator();
|
||||||
|
while(scenes.hasNext()) {
|
||||||
|
sceneList.add(scenes.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sceneList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import org.apache.http.util.EntityUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.luupRequests.Categorie;
|
import com.bwssystems.luupRequests.Categorie;
|
||||||
import com.bwssystems.luupRequests.Device;
|
import com.bwssystems.luupRequests.Device;
|
||||||
import com.bwssystems.luupRequests.Room;
|
import com.bwssystems.luupRequests.Room;
|
||||||
@@ -25,16 +26,21 @@ public class VeraInfo {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(VeraInfo.class);
|
private static final Logger log = LoggerFactory.getLogger(VeraInfo.class);
|
||||||
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 NamedIP veraAddress;
|
||||||
|
private Boolean validVera;
|
||||||
|
|
||||||
public VeraInfo(String addressString) {
|
public VeraInfo(NamedIP addressName, Boolean isValidVera) {
|
||||||
super();
|
super();
|
||||||
httpClient = HttpClients.createMinimal();
|
httpClient = HttpClients.createDefault();
|
||||||
veraAddressString = addressString;
|
veraAddress = addressName;
|
||||||
|
validVera = isValidVera;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sdata getSdata() {
|
public Sdata getSdata() {
|
||||||
String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
|
if(!validVera)
|
||||||
|
return new Sdata();
|
||||||
|
|
||||||
|
String theUrl = "http://" + veraAddress.getIp() + SDATA_REQUEST;
|
||||||
String theData;
|
String theData;
|
||||||
|
|
||||||
theData = doHttpGETRequest(theUrl);
|
theData = doHttpGETRequest(theUrl);
|
||||||
@@ -66,6 +72,8 @@ public class VeraInfo {
|
|||||||
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
||||||
else
|
else
|
||||||
theDevice.setCategory("<unknown>");
|
theDevice.setCategory("<unknown>");
|
||||||
|
theDevice.setVeraaddress(veraAddress.getIp());
|
||||||
|
theDevice.setVeraname(veraAddress.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
||||||
@@ -76,6 +84,8 @@ public class VeraInfo {
|
|||||||
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
||||||
else
|
else
|
||||||
theScene.setRoom("no room");
|
theScene.setRoom("no room");
|
||||||
|
theScene.setVeraaddress(veraAddress.getIp());
|
||||||
|
theScene.setVeraname(veraAddress.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<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><a href="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Help</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"
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
<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.8</a></li>
|
<li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +1,13 @@
|
|||||||
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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 class="panel panel-default bridgeServer">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h1 class="panel-title">Bridge settings</h1>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
|
|
||||||
<form class="form-horizontal">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-xs-12 col-sm-3 control-label" for="bridge-base">Bridge
|
|
||||||
server</label>
|
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
|
||||||
<input id="bridge-base" class="form-control" type="text"
|
|
||||||
ng-model="bridge.base" placeholder="URL to bridge">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
|
||||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
|
||||||
ng-click="testUrl(bridge.base)">Go</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Setting</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.config.address</td>
|
|
||||||
<td>{{BridgeSettings.upnpconfigaddress}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>server.port</td>
|
|
||||||
<td>{{BridgeSettings.serverport}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.devices.db</td>
|
|
||||||
<td>{{BridgeSettings.upnpdevicedb}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.response.port</td>
|
|
||||||
<td>{{BridgeSettings.upnpresponseport}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>vera.address</td>
|
|
||||||
<td>{{BridgeSettings.veraaddress}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.strict</td>
|
|
||||||
<td>{{BridgeSettings.upnpstrict}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>trace.upnp</td>
|
|
||||||
<td>{{BridgeSettings.traceupnp}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>vtwo.compatibility</td>
|
|
||||||
<td>{{BridgeSettings.vtwocompatibility}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-controller="ErrorsController">
|
<div ng-controller="ErrorsController">
|
||||||
<div ng-if="bridge.error"
|
<div ng-if="bridge.error"
|
||||||
@@ -84,11 +24,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Current devices</h2>
|
<h2 class="panel-title">Current devices ({{bridge.devices.length}}) </h2>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('id')">ID</a>
|
<a href="" ng-click="order('id')">ID</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span></th>
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span></th>
|
||||||
@@ -98,23 +39,137 @@
|
|||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('deviceType')">Type</a>
|
<a href="" ng-click="order('deviceType')">Type</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
|
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('targetDevice')">Target</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'targetDevice'" ng-class="{reverse:reverse}"></span></th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
<td>{{device.id}}</td>
|
<td>{{device.id}}</td>
|
||||||
<td>{{device.name}}</td>
|
<td>{{device.name}}</td>
|
||||||
<td>{{device.deviceType}}</td>
|
<td>{{device.deviceType}}</td>
|
||||||
|
<td>{{device.targetDevice}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-info" type="submit"
|
<button class="btn btn-info" type="submit"
|
||||||
ng-click="testUrl(device, 'on')">Test ON</button>
|
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||||
<button class="btn btn-info" type="submit"
|
<button class="btn btn-info" type="submit"
|
||||||
ng-click="testUrl(device, 'off')">Test OFF</button>
|
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||||
<button class="btn btn-warning" type="submit"
|
<button class="btn btn-warning" type="submit"
|
||||||
ng-click="editDevice(device)">Edit</button>
|
ng-click="editDevice(device)">Edit/Copy</button>
|
||||||
<button class="btn btn-danger" type="submit"
|
<button class="btn btn-danger" type="submit"
|
||||||
ng-click="deleteDevice(device)">Delete</button>
|
ng-click="deleteDevice(device)">Delete</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default bridgeServer">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">Bridge Settings <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||||
|
</div>
|
||||||
|
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||||
|
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||||
|
server</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input id="bridge-base" class="form-control" type="text"
|
||||||
|
ng-model="bridge.base" placeholder="URL to bridge">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
|
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
||||||
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
|
ng-click="goBridgeUrl(bridge.base)">Go</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Setting</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr>
|
||||||
|
<td>upnp.config.address</td>
|
||||||
|
<td>{{bridge.settings.upnpconfigaddress}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>server.port</td>
|
||||||
|
<td>{{bridge.settings.serverport}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>upnp.devices.db</td>
|
||||||
|
<td>{{bridge.settings.upnpdevicedb}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>upnp.response.port</td>
|
||||||
|
<td>{{bridge.settings.upnpresponseport}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>vera.address</td>
|
||||||
|
<td>{{bridge.settings.veraaddress}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>harmony.address</td>
|
||||||
|
<td>{{bridge.settings.harmonyaddress}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>upnp.strict</td>
|
||||||
|
<td>{{bridge.settings.upnpstrict}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>trace.upnp</td>
|
||||||
|
<td>{{bridge.settings.traceupnp}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>dev.mode</td>
|
||||||
|
<td>{{bridge.settings.devmode}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>nest.configured</td>
|
||||||
|
<td>{{bridge.settings.nestconfigured}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default backup">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">Bridge Device DB Backup <a ng-click="toggleBk()"><span class={{imgBkUrl}} aria-hidden="true"></a></h1>
|
||||||
|
</div>
|
||||||
|
<div ng-if="visibleBk" class="animate-if" class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup File Name</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input id="backup-name" class="form-control" type="text"
|
||||||
|
ng-model="optionalbackupname" placeholder="Optional">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary"
|
||||||
|
ng-click="backupDeviceDb(optionalbackupname)">Backup Device DB</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Filename</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="backup in bridge.backups">
|
||||||
|
<td>{{backup}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="restoreBackup(backup)">Restore</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="deleteBackup(backup)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -1,18 +1,24 @@
|
|||||||
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a new device</h2>
|
<h2 class="panel-title">Edit/Copy a device</h2>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-muted">This screen allows the modification of many fields the bridge uses. Please use care when
|
||||||
|
updating these fields as you may break the settings used by the bridge to call a specific end point device.</p>
|
||||||
|
<p>When copying, update the name and select the "Add Bridge Device" Button.</p>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
<form class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
</label>
|
</label>
|
||||||
@@ -21,8 +27,48 @@
|
|||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-success" ng-click="addDevice()">
|
||||||
Update Device</button>
|
Update Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-target"
|
||||||
|
ng-model="device.targetDevice" placeholder="default">
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary" ng-click="copyDevice()">
|
||||||
|
Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-map-type" id="device-map-type" ng-model="device.mapType">
|
||||||
|
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="veraDevice">Vera Device</option>
|
||||||
|
<option value="veraScene">Vera Scene</option>
|
||||||
|
<option value="harmonyActivity">Harmony Activity</option>
|
||||||
|
<option value="harmonyButton">Harmony Button</option>
|
||||||
|
<option value="nestHomeAway">Nest Home Status</option>
|
||||||
|
<option value="nestThermoSet">Nest Thermostat</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.mapType" class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map ID
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-map-id"
|
||||||
|
ng-model="device.mapId" placeholder="1111">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -33,9 +79,6 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device, 'on')">Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -47,9 +90,6 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device, 'off')">Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -67,7 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
</label>
|
</label>
|
||||||
@@ -92,7 +132,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" 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 On</label>
|
for="device-content-body">Content Body On</label>
|
||||||
@@ -104,7 +144,7 @@
|
|||||||
<div class="clearfix visible-xs"></div>
|
<div class="clearfix visible-xs"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" 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-off">Content Body Off</label>
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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>
|
||||||
@@ -71,9 +74,11 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a new device</h2>
|
<h2 class="panel-title">Add a new device</h2>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-muted">This area allows you to create any http or udp call to an endpoint. You can use the default GET or select
|
||||||
|
the http verb type below and configure a payload for either on or off methods. Currently, https is not supported.</p>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
<form class="form-horizontal">
|
||||||
<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-name">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
@@ -83,8 +88,8 @@
|
|||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||||
Add Device</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -96,9 +101,8 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
Clear Device</button>
|
||||||
ng-click="testUrl(device, 'on')">Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -110,9 +114,6 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device, 'off')">Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -130,7 +131,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||||
</label>
|
</label>
|
||||||
@@ -155,7 +156,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" 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 On</label>
|
for="device-content-body">Content Body On</label>
|
||||||
@@ -167,7 +168,7 @@
|
|||||||
<div class="clearfix visible-xs"></div>
|
<div class="clearfix visible-xs"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div ng-if="device.httpVerb" 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-off">Content Body Off</label>
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|||||||
135
src/main/resources/public/views/harmonyactivity.html
Normal file
135
src/main/resources/public/views/harmonyactivity.html
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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">For any Harmony Activity, use the action buttons to generate the device addition information below automatically.
|
||||||
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Activities' list below will show what is already setup for your Harmony Hubs.</p>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<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>
|
||||||
|
<a href="" ng-click="order('hub')">Hub</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.id}}</td>
|
||||||
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||||
|
Activity URLs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Activities <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<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>
|
||||||
|
<a href="" ng-click="order('hub')">Hub</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.id}}</td>
|
||||||
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</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 Bridge Device for a Harmony Activity</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<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" ng-click="addDevice()">
|
||||||
|
Add Bridge Device</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>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</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>
|
||||||
158
src/main/resources/public/views/harmonydevice.html
Normal file
158
src/main/resources/public/views/harmonydevice.html
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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">For any Harmony Device and Buttons, use the build button to generate the configuration for this bridge device. You can add button presses by
|
||||||
|
selecting yoru devic and buttons and then selecting the Build Button. This will allow multiple button presses to be built for a given device.
|
||||||
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Harmony Buttons' list below will show what is already setup for your Harmony Hubs.</p>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<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>
|
||||||
|
<a href="" ng-click="order('hub')">Hub</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'hub'" 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>{{$index+1}}</td>
|
||||||
|
<td>{{harmonydevice.device.label}}</td>
|
||||||
|
<td>{{harmonydevice.device.id}}</td>
|
||||||
|
<td>{{harmonydevice.hub}}</td>
|
||||||
|
<td>
|
||||||
|
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
||||||
|
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}">
|
||||||
|
<option ng-repeat="funcon in ctrlon.function" value="{{funcon.action}}">{{funcon.label}}</option>
|
||||||
|
</optgroup >
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
||||||
|
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}">
|
||||||
|
<option ng-repeat="funcoff in ctrloff.function" value="{{funcoff.action}}">{{funcoff.label}}</option>
|
||||||
|
</optgroup >
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build A Button</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Harmony Buttons <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</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('id')">Device Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('targetDevice')">Hub</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'targetDevice'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('mapId')">Harmony Device-Button On-Button Off</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.targetDevice}}</td>
|
||||||
|
<td>{{device.mapId}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</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 Bridge Device for Harmony Buttons</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<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" ng-click="addDevice()">
|
||||||
|
Add Bridge Device</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>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</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>
|
||||||
156
src/main/resources/public/views/nestactions.html
Normal file
156
src/main/resources/public/views/nestactions.html
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
<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 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="#/nest">Nest</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">Nest Items List</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p class="text-muted">For any Nest Item, use the action buttons to generate the device addition information below automatically.
|
||||||
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Nest Items' list below will show what is already setup for your Nest.</p>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</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('type')">Type</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'type'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('location')">Location</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'location'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{nestitem.name}}</td>
|
||||||
|
<td>{{nestitem.type}}</td>
|
||||||
|
<td>{{nestitem.location}}</td>
|
||||||
|
<td>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li ng-if="nestitem.type ==='Home' " class="list-group-item">
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestHomeUrls(nestitem)">Home/Away</button>
|
||||||
|
</li>
|
||||||
|
<li ng-if="nestitem.type ==='Thermostat' " class="list-group-item">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestTempUrls(nestitem)">Temp</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestHeatUrls(nestitem)">Heat</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestCoolUrls(nestitem)">Cool</button>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestRangeUrls(nestitem)">Range</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestOffUrls(nestitem)">Off</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestFanUrls(nestitem)">Fan</button>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Nest Items <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</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('id')">Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('mapId')">mapId</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'mapId'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.mapId}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(device.mapId, 'nest')">Delete</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 Bridge Device for a Nest Item</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<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" ng-click="addDevice()">
|
||||||
|
Add Bridge Device</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>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</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>
|
||||||
@@ -2,17 +2,22 @@
|
|||||||
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</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 class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Vera Device List</h2>
|
<h2 class="panel-title">Vera Device List ({{bridge.veradevices.length}})</h2>
|
||||||
</div>
|
</div>
|
||||||
<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">For any Vera Device, use the action buttons to generate the device addition information below automatically.
|
||||||
the add device box selections automatically.</p><p>Also, use this select menu for which type of dim
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Vera Devices' list below will show what is already setup for your Vera.</p>
|
||||||
|
<p>Also, use this select menu for which type of dim
|
||||||
control you would like to be generated:
|
control you would like to be generated:
|
||||||
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
@@ -21,9 +26,13 @@
|
|||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
<p>Use the check boxes by the names to use the bulk addition feature. Select your items and dim control type if wanted, then click bulk add below.
|
||||||
|
Your items will be added with on and off or dim and off if selected with the name of the device from the Vera.
|
||||||
|
</p>
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('name')">Name</a>
|
<a href="" ng-click="order('name')">Name</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||||
@@ -39,15 +48,21 @@
|
|||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('room')">Room</a>
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('vera')">Vera</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'vera'" ng-class="{reverse:reverse}"></span>
|
||||||
</th>
|
</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="veradevice in bridge.veradevices | orderBy:predicate:reverse">
|
<tr ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId | orderBy:predicate:reverse">
|
||||||
<td>{{veradevice.name}}</td>
|
<td>{{$index+1}}</td>
|
||||||
|
<td><input type="checkbox" name="bulk.devices[]" value="{{veradevice.id}}" ng-checked="bulk.devices.indexOf(veradevice.id) > -1" ng-click="toggleSelection(veradevice.id)"> {{veradevice.name}}</td>
|
||||||
<td>{{veradevice.id}}</td>
|
<td>{{veradevice.id}}</td>
|
||||||
<td>{{veradevice.category}}</td>
|
<td>{{veradevice.category}}</td>
|
||||||
<td>{{veradevice.room}}</td>
|
<td>{{veradevice.room}}</td>
|
||||||
|
<td>{{veradevice.veraname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
|
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
|
||||||
@@ -55,16 +70,67 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="bulkAddDevices(device_dim_control)">Bulk Add ({{bulk.devices.length}})</button>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Vera Devices <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</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('id')">Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('category')">Category</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'category'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('vera')">Vera</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'vera'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{veradevice.name}}</td>
|
||||||
|
<td>{{veradevice.id}}</td>
|
||||||
|
<td>{{veradevice.category}}</td>
|
||||||
|
<td>{{veradevice.room}}</td>
|
||||||
|
<td>{{veradevice.veraname}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(veradevice.id, 'veraDevice')">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Vera device</h2>
|
<h2 class="panel-title">Add Bridge Device for a Vera Device</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
<form class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
</label>
|
</label>
|
||||||
@@ -73,8 +139,8 @@
|
|||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||||
Add Device</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -85,10 +151,8 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
Clear Device</button>
|
||||||
ng-click="testUrl(device, 'on')">Test</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -99,10 +163,6 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device, 'off')">Test</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -11,12 +14,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<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">For any Vera Scene, use the action buttons to generate the device addition information below automatically.
|
||||||
the add device box selections automatically.</p>
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Vera Scenes' list below will show what is already setup for your Vera.</p>
|
||||||
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('name')">Name</a>
|
<a href="" ng-click="order('name')">Name</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||||
@@ -28,14 +33,20 @@
|
|||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('room')">Room</a>
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('vera')">Vera</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'vera'" ng-class="{reverse:reverse}"></span>
|
||||||
</th>
|
</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="verascene in bridge.verascenes | orderBy:predicate:reverse">
|
<tr ng-repeat="verascene in bridge.verascenes | availableVeraSceneId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
<td>{{verascene.name}}</td>
|
<td>{{verascene.name}}</td>
|
||||||
<td>{{verascene.id}}</td>
|
<td>{{verascene.id}}</td>
|
||||||
<td>{{verascene.room}}</td>
|
<td>{{verascene.room}}</td>
|
||||||
|
<td>{{verascene.veraname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildSceneUrls(verascene)">Generate
|
ng-click="buildSceneUrls(verascene)">Generate
|
||||||
@@ -45,14 +56,56 @@
|
|||||||
</table>
|
</table>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Vera Scenes <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</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('id')">Id</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('room')">Room</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="" ng-click="order('vera')">Vera</a>
|
||||||
|
<span class="sortorder" ng-show="predicate === 'vera'" ng-class="{reverse:reverse}"></span>
|
||||||
|
</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{verascene.name}}</td>
|
||||||
|
<td>{{verascene.id}}</td>
|
||||||
|
<td>{{verascene.room}}</td>
|
||||||
|
<td>{{verascene.veraname}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(verascene.id, 'veraScene')">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Vera scene</h2>
|
<h2 class="panel-title">Add a Bridge Device for a Vera scene</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
<form class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
</label>
|
</label>
|
||||||
@@ -61,8 +114,8 @@
|
|||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||||
Add Scene</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -73,10 +126,8 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-on-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
Clear Device</button>
|
||||||
ng-click="testUrl(device, 'on')">Test</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -87,10 +138,6 @@
|
|||||||
<textarea rows="3" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix visible-xs"></div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device, 'off')">Test</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
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}
|
||||||
Reference in New Issue
Block a user