mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cca9a6be78 | ||
|
|
5d5b68209a | ||
|
|
d2e906caa3 | ||
|
|
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 |
46
pom.xml
46
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>1.0.6</version>
|
<version>1.3.8</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 or Harmony Hub, 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>
|
||||||
@@ -30,15 +30,25 @@
|
|||||||
<artifactId>harmony-java-client</artifactId>
|
<artifactId>harmony-java-client</artifactId>
|
||||||
<version>1.0.8</version>
|
<version>1.0.8</version>
|
||||||
</dependency>
|
</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>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpcore</artifactId>
|
||||||
|
<version>4.4.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
@@ -80,11 +90,6 @@
|
|||||||
<artifactId>smack-core</artifactId>
|
<artifactId>smack-core</artifactId>
|
||||||
<version>4.0.7</version>
|
<version>4.0.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.igniterealtime.smack</groupId>
|
|
||||||
<artifactId>smack-debug</artifactId>
|
|
||||||
<version>4.0.7</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -126,11 +131,12 @@
|
|||||||
<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>
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>org.slf4j:*</artifact>
|
<artifact>org.slf4j:*</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
@@ -143,6 +149,24 @@
|
|||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</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,17 +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 String harmonyaddress;
|
private IpList harmonyaddress;
|
||||||
private String harmonyuser;
|
private String harmonyuser;
|
||||||
private String harmonypwd;
|
private String harmonypwd;
|
||||||
|
private Integer buttonsleep;
|
||||||
private boolean upnpstrict;
|
private boolean upnpstrict;
|
||||||
private boolean traceupnp;
|
private boolean traceupnp;
|
||||||
private boolean devmode;
|
private boolean devmode;
|
||||||
|
private String nestuser;
|
||||||
|
private String nestpwd;
|
||||||
|
private boolean nestconfigured;
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
return upnpconfigaddress;
|
return upnpconfigaddress;
|
||||||
@@ -37,16 +43,16 @@ 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 String getHarmonyAddress() {
|
public IpList getHarmonyAddress() {
|
||||||
return harmonyaddress;
|
return harmonyaddress;
|
||||||
}
|
}
|
||||||
public void setHarmonyAddress(String harmonyaddress) {
|
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||||
this.harmonyaddress = harmonyaddress;
|
this.harmonyaddress = harmonyaddress;
|
||||||
}
|
}
|
||||||
public String getHarmonyUser() {
|
public String getHarmonyUser() {
|
||||||
@@ -79,13 +85,39 @@ public class BridgeSettings {
|
|||||||
public void setDevMode(boolean devmode) {
|
public void setDevMode(boolean devmode) {
|
||||||
this.devmode = devmode;
|
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 Integer getButtonsleep() {
|
||||||
|
return buttonsleep;
|
||||||
|
}
|
||||||
|
public void setButtonsleep(Integer buttonsleep) {
|
||||||
|
this.buttonsleep = buttonsleep;
|
||||||
|
}
|
||||||
public Boolean isValidVera() {
|
public Boolean isValidVera() {
|
||||||
if(this.veraaddress.contains(Configuration.DEFAULT_VERA_ADDRESS))
|
List<NamedIP> devicesList = this.veraaddress.getDevices();
|
||||||
|
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public Boolean isValidHarmony() {
|
public Boolean isValidHarmony() {
|
||||||
if(this.harmonyaddress.contains(Configuration.DEFAULT_HARMONY_ADDRESS))
|
List<NamedIP> devicesList = this.harmonyaddress.getDevices();
|
||||||
|
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
if(this.harmonypwd == null || this.harmonypwd == "")
|
if(this.harmonypwd == null || this.harmonypwd == "")
|
||||||
return false;
|
return false;
|
||||||
@@ -93,4 +125,11 @@ public class BridgeSettings {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public Boolean isValidNest() {
|
||||||
|
if(this.nestpwd == null || this.nestpwd == "")
|
||||||
|
return false;
|
||||||
|
if(this.nestuser == null || this.nestuser == "")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ package com.bwssystems.HABridge;
|
|||||||
public class Configuration {
|
public class Configuration {
|
||||||
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||||
public final static String UPNP_RESPONSE_PORT = "50000";
|
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||||
public final static String DEFAULT_VERA_ADDRESS = "1.1.1.1";
|
public final static String UPNP_RESPONSE_DEVICES = "30";
|
||||||
public final static String DEFAULT_HARMONY_ADDRESS = "1.1.1.1";
|
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
||||||
public final static String DEFAULT_HARMONY_USER = "";
|
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
||||||
public final static String DEFAULT_HARMONY_PWD = "";
|
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";
|
public final static String DFAULT_WEB_PORT = "8080";
|
||||||
|
public final static String DFAULT_BUTTON_SLEEP = "100";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,7 +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.harmony.HarmonyServer;
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -34,39 +39,90 @@ public class HABridge {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||||
DeviceResource theResources;
|
DeviceResource theResources;
|
||||||
HarmonyServer myHarmonyServer;
|
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;
|
Version theVersion;
|
||||||
|
|
||||||
theVersion = new Version();
|
theVersion = new Version();
|
||||||
|
|
||||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
|
||||||
//get ip address for upnp requests
|
|
||||||
|
bridgeSettings = new BridgeSettings();
|
||||||
|
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
||||||
|
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", Configuration.DEFAULT_ADDRESS));
|
||||||
|
if(bridgeSettings.getUpnpConfigAddress().equalsIgnoreCase(Configuration.DEFAULT_ADDRESS)) {
|
||||||
try {
|
try {
|
||||||
address = InetAddress.getLocalHost();
|
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();
|
addressString = address.getHostAddress();
|
||||||
} catch (UnknownHostException e) {
|
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);
|
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings.setUpnpConfigAddress(addressString);
|
||||||
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
}
|
||||||
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
|
|
||||||
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
|
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
|
||||||
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
|
IpList theVeraList;
|
||||||
bridgeSettings.setHarmonyAddress(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS));
|
|
||||||
bridgeSettings.setHarmonyUser(System.getProperty("harmony.user", Configuration.DEFAULT_HARMONY_USER));
|
try {
|
||||||
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_HARMONY_PWD));
|
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.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.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "false")));
|
bridgeSettings.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "false")));
|
||||||
|
bridgeSettings.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DFAULT_BUTTON_SLEEP)));
|
||||||
|
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
|
||||||
@@ -75,16 +131,13 @@ public class HABridge {
|
|||||||
// 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");
|
||||||
//setup the harmony connection if available
|
//setup the harmony connection if available
|
||||||
try {
|
harmonyHome = new HarmonyHome(bridgeSettings);
|
||||||
myHarmonyServer = HarmonyServer.setup(bridgeSettings);
|
//setup the nest connection if available
|
||||||
} catch (Exception e) {
|
nestHome = new NestHome(bridgeSettings);
|
||||||
log.error("Cannot get harmony client setup, Exiting with message: " + e.getMessage(), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// setup the class to handle the resource setup rest api
|
// setup the class to handle the resource setup rest api
|
||||||
theResources = new DeviceResource(bridgeSettings, theVersion, myHarmonyServer.getMyHarmony());
|
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(), myHarmonyServer.getMyHarmony());
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
*/
|
*/
|
||||||
@@ -14,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;
|
||||||
@@ -72,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();
|
||||||
@@ -102,14 +77,13 @@ public class DeviceResponse {
|
|||||||
deviceState.setEffect("none");
|
deviceState.setEffect("none");
|
||||||
deviceState.setAlert("none");
|
deviceState.setAlert("none");
|
||||||
deviceState.setBri(254);
|
deviceState.setBri(254);
|
||||||
deviceState.setSat(254);
|
|
||||||
|
|
||||||
response.setName(name);
|
response.setName(name);
|
||||||
response.setUniqueid(id);
|
response.setUniqueid(id);
|
||||||
response.setManufacturername("Philips");
|
response.setManufacturername("Philips");
|
||||||
response.setType("Dimmable light");
|
response.setType("Dimmable light");
|
||||||
response.setModelid("LWB004");
|
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,6 +24,22 @@ public class DeviceDescriptor{
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
public String getDeviceType() {
|
||||||
return deviceType;
|
return deviceType;
|
||||||
}
|
}
|
||||||
@@ -29,6 +48,14 @@ public class DeviceDescriptor{
|
|||||||
this.deviceType = deviceType;
|
this.deviceType = deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTargetDevice() {
|
||||||
|
return targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetDevice(String targetDevice) {
|
||||||
|
this.targetDevice = targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
public String getOffUrl() {
|
public String getOffUrl() {
|
||||||
return offUrl;
|
return offUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +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.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;
|
||||||
@@ -33,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)
|
||||||
@@ -47,6 +60,7 @@ public class DeviceRepository {
|
|||||||
put(theDevice.getId(), theDevice);
|
put(theDevice.getId(), theDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DeviceDescriptor> findAll() {
|
public List<DeviceDescriptor> findAll() {
|
||||||
@@ -79,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());
|
||||||
@@ -178,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;
|
||||||
@@ -17,10 +18,13 @@ 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.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.harmony.HarmonyHandler;
|
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;
|
||||||
|
|
||||||
@@ -32,16 +36,30 @@ 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 Version version;
|
||||||
private HarmonyHandler myHarmonyHandler;
|
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, Version theVersion, HarmonyHandler myHarmony) {
|
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHome theHarmonyHome, NestHome aNestHome) {
|
||||||
super();
|
|
||||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
this.veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
|
||||||
this.myHarmonyHandler = myHarmony;
|
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;
|
this.version = theVersion;
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
@@ -52,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);
|
||||||
@@ -67,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);
|
||||||
@@ -87,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());
|
||||||
@@ -121,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
|
||||||
@@ -141,56 +182,124 @@ public class DeviceResource {
|
|||||||
|
|
||||||
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) -> {
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||||
log.debug("Get harmony activities");
|
log.debug("Get harmony activities");
|
||||||
if(myHarmonyHandler == null) {
|
if(myHarmonyHome == 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 myHarmonyHandler.getActivities();
|
return myHarmonyHome.getActivities();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
||||||
log.debug("Get harmony current activity");
|
log.debug("Get harmony current activity");
|
||||||
if(myHarmonyHandler == null) {
|
if(myHarmonyHome == 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 myHarmonyHandler.getCurrentActivity();
|
return myHarmonyHome.getCurrentActivities();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
||||||
log.debug("Get harmony devices");
|
log.debug("Get harmony devices");
|
||||||
if(myHarmonyHandler == null) {
|
if(myHarmonyHome == 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 myHarmonyHandler.getDevices();
|
return myHarmonyHome.getDevices();
|
||||||
}, new JsonTransformer());
|
}, 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,14 +1,19 @@
|
|||||||
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.ButtonPress;
|
||||||
import com.bwssystems.harmony.HarmonyHandler;
|
import com.bwssystems.harmony.HarmonyHandler;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
import com.bwssystems.harmony.RunActivity;
|
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;
|
||||||
@@ -16,6 +21,7 @@ import com.google.gson.Gson;
|
|||||||
import net.java.dev.eval.Expression;
|
import net.java.dev.eval.Expression;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@@ -36,10 +42,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
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
|
||||||
*/
|
*/
|
||||||
@@ -54,25 +65,38 @@ public class HueMulator {
|
|||||||
private static final String HUE_CONTEXT = "/api";
|
private static final String HUE_CONTEXT = "/api";
|
||||||
|
|
||||||
private DeviceRepository repository;
|
private DeviceRepository repository;
|
||||||
private HarmonyHandler myHarmony;
|
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, HarmonyHandler theHandler){
|
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;
|
||||||
myHarmony = theHandler;
|
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<>();
|
||||||
@@ -85,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()) {
|
||||||
@@ -103,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);
|
||||||
@@ -130,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());
|
||||||
@@ -151,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");
|
||||||
@@ -159,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");
|
||||||
@@ -178,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
|
||||||
@@ -186,49 +273,156 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(device.getDeviceType().contains("activity"))
|
if(request.body().contains("bri"))
|
||||||
{
|
{
|
||||||
log.debug("executing activity to Harmony: " + url);
|
if(url == null)
|
||||||
|
{
|
||||||
|
url = device.getOnUrl();
|
||||||
|
responseString = "[";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
responseString = responseString + ",";
|
||||||
|
|
||||||
|
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
responseString = responseString + "]";
|
||||||
|
|
||||||
|
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to change activity to Harmony: " + url);
|
||||||
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
|
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);
|
myHarmony.startActivity(anActivity);
|
||||||
}
|
}
|
||||||
else if(device.getDeviceType().contains("button"))
|
else if(device.getDeviceType().toLowerCase().contains("button") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||||
{
|
{
|
||||||
log.debug("executing button press to Harmony: " + url);
|
log.debug("executing HUE api request to button press(es) to Harmony: " + url);
|
||||||
ButtonPress aDeviceButton = new Gson().fromJson(url, ButtonPress.class);
|
if(url.substring(0, 1).equalsIgnoreCase("{")) {
|
||||||
myHarmony.pressButton(aDeviceButton);
|
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(bridgeSettings.getButtonsleep());
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
log.debug("executing activity to Http: " + url);
|
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + url);
|
||||||
// quick template
|
// quick template
|
||||||
String body;
|
String body;
|
||||||
url = replaceIntensityValue(url, state.getBri());
|
url = replaceIntensityValue(url, state.getBri());
|
||||||
@@ -238,14 +432,11 @@ public class HueMulator {
|
|||||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||||
// make call
|
// make call
|
||||||
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
||||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
log.warn("Error on calling url to change device state: " + url);
|
||||||
log.error("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\"}}]";
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.type("application/json; charset=utf-8");
|
|
||||||
response.status(HttpStatus.SC_OK);
|
|
||||||
return responseString;
|
return responseString;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -281,8 +472,9 @@ public class HueMulator {
|
|||||||
Integer endResult = Math.round(result.floatValue());
|
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 (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Could not execute Math: " + mathDescriptor, e);
|
log.warn("Could not execute Math: " + mathDescriptor, e);
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,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 an M-SEARCH message.");
|
||||||
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
|
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)
|
else if (!strict)
|
||||||
{
|
{
|
||||||
if(traceupnp)
|
if(traceupnp) {
|
||||||
|
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: 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);
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +136,7 @@ public class UpnpListener {
|
|||||||
"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";
|
||||||
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;
|
||||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||||
if(traceupnp)
|
if(traceupnp)
|
||||||
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
||||||
else
|
else
|
||||||
@@ -142,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,9 +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";
|
||||||
|
|
||||||
public UpnpSettingsResource(BridgeSettings theSettings) {
|
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
|
||||||
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.setButtonsleep(theBridgeSettings.getButtonsleep());
|
||||||
|
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() {
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettings;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import net.whistlingfish.harmony.ActivityChangeListener;
|
|||||||
import net.whistlingfish.harmony.HarmonyClient;
|
import net.whistlingfish.harmony.HarmonyClient;
|
||||||
import net.whistlingfish.harmony.HarmonyClientModule;
|
import net.whistlingfish.harmony.HarmonyClientModule;
|
||||||
import net.whistlingfish.harmony.config.Activity;
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
||||||
|
|
||||||
public class HarmonyServer {
|
public class HarmonyServer {
|
||||||
@Inject
|
@Inject
|
||||||
@@ -22,22 +24,26 @@ public class HarmonyServer {
|
|||||||
|
|
||||||
private HarmonyHandler myHarmony;
|
private HarmonyHandler myHarmony;
|
||||||
private DevModeResponse devResponse;
|
private DevModeResponse devResponse;
|
||||||
|
private OAReplyProvider dummyProvider;
|
||||||
|
private NamedIP myNameAndIP;
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||||
|
|
||||||
public HarmonyServer() {
|
public HarmonyServer(NamedIP theHarmonyAddress) {
|
||||||
super();
|
super();
|
||||||
myHarmony = null;
|
myHarmony = null;
|
||||||
|
dummyProvider = null;
|
||||||
|
myNameAndIP = theHarmonyAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HarmonyServer setup(BridgeSettings bridgeSettings) throws Exception {
|
public static HarmonyServer setup(BridgeSettings bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
|
||||||
if(!bridgeSettings.isValidHarmony()) {
|
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode()) {
|
||||||
return new HarmonyServer();
|
return new HarmonyServer(theHarmonyAddress);
|
||||||
}
|
}
|
||||||
Injector injector = null;
|
Injector injector = null;
|
||||||
if(!bridgeSettings.isDevMode())
|
if(!bridgeSettings.isDevMode())
|
||||||
injector = Guice.createInjector(new HarmonyClientModule());
|
injector = Guice.createInjector(new HarmonyClientModule());
|
||||||
HarmonyServer mainObject = new HarmonyServer();
|
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
||||||
if(!bridgeSettings.isDevMode())
|
if(!bridgeSettings.isDevMode())
|
||||||
injector.injectMembers(mainObject);
|
injector.injectMembers(mainObject);
|
||||||
mainObject.execute(bridgeSettings);
|
mainObject.execute(bridgeSettings);
|
||||||
@@ -47,9 +53,11 @@ public class HarmonyServer {
|
|||||||
private void execute(BridgeSettings mySettings) throws Exception {
|
private void execute(BridgeSettings mySettings) throws Exception {
|
||||||
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||||
String modeString = "";
|
String modeString = "";
|
||||||
|
if(dummyProvider != null)
|
||||||
|
log.debug("something is very wrong as dummyProvider is not null...");
|
||||||
if(mySettings.isDevMode())
|
if(mySettings.isDevMode())
|
||||||
modeString = " (development mode)";
|
modeString = " (development mode)";
|
||||||
if(noopCalls)
|
else if(noopCalls)
|
||||||
modeString = " (no op calls to harmony)";
|
modeString = " (no op calls to harmony)";
|
||||||
log.info("setup initiated " + modeString + "....");
|
log.info("setup initiated " + modeString + "....");
|
||||||
if(mySettings.isDevMode())
|
if(mySettings.isDevMode())
|
||||||
@@ -65,7 +73,7 @@ public class HarmonyServer {
|
|||||||
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
harmonyClient.connect(mySettings.getHarmonyAddress(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
harmonyClient.connect(myNameAndIP.getIp(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||||
}
|
}
|
||||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,13 +26,13 @@ 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;
|
private Boolean validVera;
|
||||||
|
|
||||||
public VeraInfo(String addressString, Boolean isValidVera) {
|
public VeraInfo(NamedIP addressName, Boolean isValidVera) {
|
||||||
super();
|
super();
|
||||||
httpClient = HttpClients.createMinimal();
|
httpClient = HttpClients.createDefault();
|
||||||
veraAddressString = addressString;
|
veraAddress = addressName;
|
||||||
validVera = isValidVera;
|
validVera = isValidVera;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ public class VeraInfo {
|
|||||||
if(!validVera)
|
if(!validVera)
|
||||||
return new Sdata();
|
return new Sdata();
|
||||||
|
|
||||||
String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
|
String theUrl = "http://" + veraAddress.getIp() + SDATA_REQUEST;
|
||||||
String theData;
|
String theData;
|
||||||
|
|
||||||
theData = doHttpGETRequest(theUrl);
|
theData = doHttpGETRequest(theUrl);
|
||||||
@@ -71,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();
|
||||||
@@ -81,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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
src/main/resources/public/css/ngToast.min.css
vendored
Normal file
7
src/main/resources/public/css/ngToast.min.css
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
* ngToast v1.5.6 (http://tameraydin.github.io/ngToast)
|
||||||
|
* Copyright 2015 Tamer Aydin (http://tamerayd.in)
|
||||||
|
* Licensed under MIT (http://tameraydin.mit-license.org/)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ng-toast{position:fixed;z-index:1080;width:100%;height:0;margin-top:20px;text-align:center}.ng-toast.ng-toast--top,.ng-toast.ng-toast--top .ng-toast__list{top:0;bottom:auto}.ng-toast.ng-toast--top.ng-toast--center .ng-toast__list{position:static}.ng-toast.ng-toast--bottom,.ng-toast.ng-toast--bottom .ng-toast__list{top:auto;bottom:0}.ng-toast.ng-toast--bottom.ng-toast--center .ng-toast__list{pointer-events:none}.ng-toast.ng-toast--bottom.ng-toast--center .ng-toast__message .alert{pointer-events:auto}.ng-toast.ng-toast--right .ng-toast__list{left:auto;right:0;margin-right:20px}.ng-toast.ng-toast--right .ng-toast__message{text-align:right}.ng-toast.ng-toast--left .ng-toast__list{right:auto;left:0;margin-left:20px}.ng-toast.ng-toast--left .ng-toast__message{text-align:left}.ng-toast .ng-toast__list{display:inline-block;position:absolute;right:0;left:0;margin:0 auto;padding:0;list-style:none}.ng-toast .ng-toast__message{display:block;width:100%;text-align:center}.ng-toast .ng-toast__message .alert{display:inline-block}.ng-toast .ng-toast__message__count{display:inline-block;margin:0 15px 0 5px}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<title>HA Bridge</title>
|
<title>HA Bridge</title>
|
||||||
<link href="css/main.css" rel="stylesheet">
|
<link href="css/main.css" rel="stylesheet">
|
||||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="css/ngToast.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script type="text/javascript" src="js/html5shiv.min.js"></script>
|
<script type="text/javascript" src="js/html5shiv.min.js"></script>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<toast></toast>
|
||||||
|
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||||
<div class="container" ng-controller="VersionController">
|
<div class="container" ng-controller="VersionController">
|
||||||
@@ -29,6 +31,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"
|
||||||
@@ -53,6 +56,8 @@
|
|||||||
<script src="js/jquery-1.11.3.min.js"></script>
|
<script src="js/jquery-1.11.3.min.js"></script>
|
||||||
<script src="js/angular.min.js"></script>
|
<script src="js/angular.min.js"></script>
|
||||||
<script src="js/angular-route.min.js"></script>
|
<script src="js/angular-route.min.js"></script>
|
||||||
|
<script src="js/angular-sanitize.min.js"></script>
|
||||||
|
<script src="js/ngToast.min.js"></script>
|
||||||
<script src="js/bootstrap.min.js"></script>
|
<script src="js/bootstrap.min.js"></script>
|
||||||
<script src="scripts/app.js"></script>
|
<script src="scripts/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
16
src/main/resources/public/js/angular-sanitize.min.js
vendored
Normal file
16
src/main/resources/public/js/angular-sanitize.min.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
AngularJS v1.4.3
|
||||||
|
(c) 2010-2015 Google, Inc. http://angularjs.org
|
||||||
|
License: MIT
|
||||||
|
*/
|
||||||
|
(function(n,h,p){'use strict';function E(a){var f=[];r(f,h.noop).chars(a);return f.join("")}function g(a,f){var d={},c=a.split(","),b;for(b=0;b<c.length;b++)d[f?h.lowercase(c[b]):c[b]]=!0;return d}function F(a,f){function d(a,b,d,l){b=h.lowercase(b);if(s[b])for(;e.last()&&t[e.last()];)c("",e.last());u[b]&&e.last()==b&&c("",b);(l=v[b]||!!l)||e.push(b);var m={};d.replace(G,function(b,a,f,c,d){m[a]=q(f||c||d||"")});f.start&&f.start(b,m,l)}function c(b,a){var c=0,d;if(a=h.lowercase(a))for(c=e.length-
|
||||||
|
1;0<=c&&e[c]!=a;c--);if(0<=c){for(d=e.length-1;d>=c;d--)f.end&&f.end(e[d]);e.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,e=[],m=a,l;for(e.last=function(){return e[e.length-1]};a;){l="";k=!0;if(e.last()&&w[e.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");f.chars&&f.chars(q(b));return""}),c("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",
|
||||||
|
b)===b&&(f.comment&&f.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(x.test(a)){if(b=a.match(x))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(y))a=a.substring(b[0].length),b[0].replace(y,c),k=!1}else K.test(a)&&((b=a.match(z))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(z,d)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),f.chars&&f.chars(q(l)))}if(a==m)throw L("badparse",a);m=a}c()}function q(a){if(!a)return"";A.innerHTML=
|
||||||
|
a.replace(/</g,"<");return A.textContent}function B(a){return a.replace(/&/g,"&").replace(M,function(a){var d=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(d-55296)+(a-56320)+65536)+";"}).replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"<").replace(/>/g,">")}function r(a,f){var d=!1,c=h.bind(a,a.push);return{start:function(a,k,e){a=h.lowercase(a);!d&&w[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(k,function(d,e){var k=h.lowercase(e),g="img"===a&&"src"===k||
|
||||||
|
"background"===k;!0!==O[k]||!0===D[k]&&!f(d,g)||(c(" "),c(e),c('="'),c(B(d)),c('"'))}),c(e?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||c(B(a))}}}var L=h.$$minErr("$sanitize"),z=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,y=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\//,H=/\x3c!--(.*?)--\x3e/g,x=/<!DOCTYPE([^>]*?)>/i,
|
||||||
|
I=/<!\[CDATA\[(.*?)]]\x3e/g,M=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,N=/([^\#-~| |!])/g,v=g("area,br,col,hr,img,wbr");n=g("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");p=g("rp,rt");var u=h.extend({},p,n),s=h.extend({},n,g("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),t=h.extend({},p,g("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
||||||
|
n=g("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan,use");var w=g("script,style"),C=h.extend({},v,s,t,u,n),D=g("background,cite,href,longdesc,src,usemap,xlink:href");n=g("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width");
|
||||||
|
p=g("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
|
||||||
|
!0);var O=h.extend({},D,p,n),A=document.createElement("pre");h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(f){var d=[];F(f,r(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var f=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,d=/^mailto:/i;return function(c,b){function k(a){a&&g.push(E(a))}function e(a,
|
||||||
|
c){g.push("<a ");h.isDefined(b)&&g.push('target="',b,'" ');g.push('href="',a.replace(/"/g,"""),'">');k(c);g.push("</a>")}if(!c)return c;for(var m,l=c,g=[],n,p;m=l.match(f);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),e(n,m[0].replace(d,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular);
|
||||||
|
//# sourceMappingURL=angular-sanitize.min.js.map
|
||||||
6
src/main/resources/public/js/ngToast.min.js
vendored
Normal file
6
src/main/resources/public/js/ngToast.min.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* ngToast v1.5.6 (http://tameraydin.github.io/ngToast)
|
||||||
|
* Copyright 2015 Tamer Aydin (http://tamerayd.in)
|
||||||
|
* Licensed under MIT (http://tameraydin.mit-license.org/)
|
||||||
|
*/
|
||||||
|
!function(a,b,c){"use strict";b.module("ngToast.provider",[]).provider("ngToast",[function(){function a(a){for(var d=Math.floor(1e3*Math.random());c.indexOf(d)>-1;)d=Math.floor(1e3*Math.random());this.id=d,this.count=0,this.animation=e.animation,this.className=e.className,this.additionalClasses=e.additionalClasses,this.dismissOnTimeout=e.dismissOnTimeout,this.timeout=e.timeout,this.dismissButton=e.dismissButton,this.dismissButtonHtml=e.dismissButtonHtml,this.dismissOnClick=e.dismissOnClick,this.compileContent=e.compileContent,b.extend(this,a)}var c=[],d=[],e={animation:!1,className:"success",additionalClasses:null,dismissOnTimeout:!0,timeout:4e3,dismissButton:!1,dismissButtonHtml:"×",dismissOnClick:!0,compileContent:!1,combineDuplications:!1,horizontalPosition:"right",verticalPosition:"top",maxNumber:0};this.configure=function(a){b.extend(e,a)},this.$get=[function(){var b=function(a,b){return b="object"==typeof b?b:{content:b},b.className=a,this.create(b)};return{settings:e,messages:c,dismiss:function(a){if(a){for(var b=c.length-1;b>=0;b--)if(c[b].id===a)return c.splice(b,1),void d.splice(d.indexOf(a),1)}else{for(;c.length>0;)c.pop();d=[]}},create:function(b){if(b="object"==typeof b?b:{content:b},e.combineDuplications)for(var f=d.length-1;f>=0;f--){var g=c[f],h=b.className||"success";if(g.content===b.content&&g.className===h)return void c[f].count++}e.maxNumber>0&&d.length>=e.maxNumber&&this.dismiss(d[0]);var i=new a(b);return"bottom"===e.verticalPosition?c.unshift(i):c.push(i),d.push(i.id),i.id},success:function(a){return b.call(this,"success",a)},info:function(a){return b.call(this,"info",a)},warning:function(a){return b.call(this,"warning",a)},danger:function(a){return b.call(this,"danger",a)}}}]}])}(window,window.angular),function(a,b){"use strict";b.module("ngToast.directives",["ngToast.provider"]).run(["$templateCache",function(a){a.put("ngToast/toast.html",'<div class="ng-toast ng-toast--{{hPos}} ng-toast--{{vPos}} {{animation ? \'ng-toast--animate-\' + animation : \'\'}}"><ul class="ng-toast__list"><toast-message ng-repeat="message in messages" message="message" count="message.count"><span ng-bind-html="message.content"></span></toast-message></ul></div>'),a.put("ngToast/toastMessage.html",'<li class="ng-toast__message {{message.additionalClasses}}"ng-mouseenter="onMouseEnter()"ng-mouseleave="onMouseLeave()"><div class="alert alert-{{message.className}}" ng-class="{\'alert-dismissible\': message.dismissButton}"><button type="button" class="close" ng-if="message.dismissButton" ng-bind-html="message.dismissButtonHtml" ng-click="!message.dismissOnClick && dismiss()"></button><span ng-if="count" class="ng-toast__message__count">{{count + 1}}</span><span ng-if="!message.compileContent" ng-transclude></span></div></li>')}]).directive("toast",["ngToast","$templateCache","$log",function(a,b,c){return{replace:!0,restrict:"EA",templateUrl:"ngToast/toast.html",compile:function(d,e){if(e.template){var f=b.get(e.template);f?d.replaceWith(f):c.warn("ngToast: Provided template could not be loaded. Please be sure that it is populated before the <toast> element is represented.")}return function(b){b.hPos=a.settings.horizontalPosition,b.vPos=a.settings.verticalPosition,b.animation=a.settings.animation,b.messages=a.messages}}}}]).directive("toastMessage",["$timeout","$compile","ngToast",function(a,b,c){return{replace:!0,transclude:!0,restrict:"EA",scope:{message:"=",count:"="},controller:["$scope","ngToast",function(a,b){a.dismiss=function(){b.dismiss(a.message.id)}}],templateUrl:"ngToast/toastMessage.html",link:function(d,e,f,g,h){e.attr("data-message-id",d.message.id);var i,j=d.message.compileContent;if(d.cancelTimeout=function(){a.cancel(i)},d.startTimeout=function(){d.message.dismissOnTimeout&&(i=a(function(){c.dismiss(d.message.id)},d.message.timeout))},d.onMouseEnter=function(){d.cancelTimeout()},d.onMouseLeave=function(){d.startTimeout()},j){var k;h(d,function(a){k=a,e.children().append(k)}),a(function(){b(k.contents())("boolean"==typeof j?d.$parent:j,function(a){k.replaceWith(a)})},0)}d.startTimeout(),d.message.dismissOnClick&&e.bind("click",function(){c.dismiss(d.message.id),d.$apply()})}}}])}(window,window.angular),function(a,b){"use strict";b.module("ngToast",["ngSanitize","ngToast.directives","ngToast.provider"])}(window,window.angular);
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
|||||||
<li ng-if="bridge.showVera" 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="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
||||||
|
|
||||||
@@ -23,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>
|
||||||
@@ -37,20 +39,25 @@
|
|||||||
<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>
|
||||||
@@ -60,14 +67,13 @@
|
|||||||
|
|
||||||
<div class="panel panel-default bridgeServer">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<a href="#/"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></a>
|
<h1 class="panel-title">Bridge Settings <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||||
<h1 class="panel-title">Bridge settings</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||||
|
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-3 control-label" for="bridge-base">Bridge
|
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||||
server</label>
|
server</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
@@ -77,7 +83,7 @@
|
|||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
ng-click="testUrl(bridge.base)">Go</button>
|
ng-click="goBridgeUrl(bridge.base)">Go</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
@@ -89,40 +95,85 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>upnp.config.address</td>
|
<td>upnp.config.address</td>
|
||||||
<td>{{BridgeSettings.upnpconfigaddress}}</td>
|
<td>{{bridge.settings.upnpconfigaddress}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>server.port</td>
|
<td>server.port</td>
|
||||||
<td>{{BridgeSettings.serverport}}</td>
|
<td>{{bridge.settings.serverport}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>upnp.devices.db</td>
|
<td>upnp.devices.db</td>
|
||||||
<td>{{BridgeSettings.upnpdevicedb}}</td>
|
<td>{{bridge.settings.upnpdevicedb}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>upnp.response.port</td>
|
<td>upnp.response.port</td>
|
||||||
<td>{{BridgeSettings.upnpresponseport}}</td>
|
<td>{{bridge.settings.upnpresponseport}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>vera.address</td>
|
<td>vera.address</td>
|
||||||
<td>{{BridgeSettings.veraaddress}}</td>
|
<td>{{bridge.settings.veraaddress}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>harmony.address</td>
|
<td>harmony.address</td>
|
||||||
<td>{{BridgeSettings.harmonyaddress}}</td>
|
<td>{{bridge.settings.harmonyaddress}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>upnp.strict</td>
|
<td>upnp.strict</td>
|
||||||
<td>{{BridgeSettings.upnpstrict}}</td>
|
<td>{{bridge.settings.upnpstrict}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>trace.upnp</td>
|
<td>trace.upnp</td>
|
||||||
<td>{{BridgeSettings.traceupnp}}</td>
|
<td>{{bridge.settings.traceupnp}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>dev.mode</td>
|
<td>dev.mode</td>
|
||||||
<td>{{BridgeSettings.devmode}}</td>
|
<td>{{bridge.settings.devmode}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>nest.configured</td>
|
||||||
|
<td>{{bridge.settings.nestconfigured}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>button.sleep</td>
|
||||||
|
<td>{{bridge.settings.buttonsleep}} ms</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
|
|
||||||
@@ -4,17 +4,21 @@
|
|||||||
<li ng-if="bridge.showVera" 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="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
||||||
@@ -23,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">
|
||||||
@@ -35,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">
|
||||||
@@ -49,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">
|
||||||
@@ -69,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>
|
||||||
@@ -94,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>
|
||||||
@@ -106,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>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<li ng-if="bridge.showVera" 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="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
||||||
|
|
||||||
@@ -73,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
|
||||||
@@ -85,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">
|
||||||
@@ -98,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">
|
||||||
@@ -112,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">
|
||||||
@@ -132,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>
|
||||||
@@ -157,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>
|
||||||
@@ -169,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>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</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" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -13,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 Harmony Activity and generate
|
<p class="text-muted">For any Harmony Activity, use the action buttons to generate the device addition information below automatically.
|
||||||
the add activity 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 Activities' list below will show what is already setup for your Harmony Hubs.</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('label')">Name</a>
|
<a href="" ng-click="order('label')">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>
|
||||||
@@ -26,13 +29,19 @@
|
|||||||
<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>
|
<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>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | orderBy:predicate:reverse">
|
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId | orderBy:predicate:reverse">
|
||||||
<td>{{harmonyactivity.label}}</td>
|
<td>{{$index+1}}</td>
|
||||||
<td>{{harmonyactivity.id}}</td>
|
<td>{{harmonyactivity.activity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.id}}</td>
|
||||||
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||||
@@ -42,14 +51,49 @@
|
|||||||
</table>
|
</table>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</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>
|
||||||
<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 Harmony Activity</h2>
|
<h2 class="panel-title">Add a Bridge Device for a Harmony Activity</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>
|
||||||
@@ -58,8 +102,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 Activity</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -70,6 +114,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>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</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"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</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>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -13,12 +14,15 @@
|
|||||||
</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 Harmony Device and Button and generate
|
<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
|
||||||
the add button box selections automatically.</p>
|
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">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
<th>
|
<th>
|
||||||
<a href="" ng-click="order('label')">Name</a>
|
<a href="" ng-click="order('label')">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>
|
||||||
@@ -26,6 +30,10 @@
|
|||||||
<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>
|
<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>
|
||||||
<th>On Button</th>
|
<th>On Button</th>
|
||||||
<th>Off Button</th>
|
<th>Off Button</th>
|
||||||
@@ -33,26 +41,69 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
|
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
|
||||||
<td>{{harmonydevice.label}}</td>
|
<td>{{$index+1}}</td>
|
||||||
<td>{{harmonydevice.id}}</td>
|
<td>{{harmonydevice.device.label}}</td>
|
||||||
|
<td>{{harmonydevice.device.id}}</td>
|
||||||
|
<td>{{harmonydevice.hub}}</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
||||||
<optgroup ng-repeat="ctrlon in harmonydevice.controlGroup" label="{{ctrlon.name}}">
|
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}">
|
||||||
<option ng-repeat="funcon in ctrlon.function">{{funcon.name}}</option>
|
<option ng-repeat="funcon in ctrlon.function" value="{{funcon.action}}">{{funcon.label}}</option>
|
||||||
</optgroup >
|
</optgroup >
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
||||||
<optgroup ng-repeat="ctrloff in harmonydevice.controlGroup" label="{{ctrloff.name}}">
|
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}">
|
||||||
<option ng-repeat="funcoff in ctrloff.function">{{funcoff.name}}</option>
|
<option ng-repeat="funcoff in ctrloff.function" value="{{funcoff.action}}">{{funcoff.label}}</option>
|
||||||
</optgroup >
|
</optgroup >
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Generate
|
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build A Button</button>
|
||||||
Button URLs</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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -61,11 +112,11 @@
|
|||||||
</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 Harmony Button</h2>
|
<h2 class="panel-title">Add a Bridge Device for Harmony Buttons</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>
|
||||||
@@ -74,8 +125,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 Button</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -86,6 +137,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>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
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>
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
|
||||||
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
|
||||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
|
||||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div ng-controller="ErrorsController">
|
|
||||||
<div ng-if="bridge.error"
|
|
||||||
class="alert alert-warning alert-dismissible" role="alert">
|
|
||||||
<button type="button" class="close" data-dismiss="alert"
|
|
||||||
aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h2 ng-show='bridge.error != ""'>ERROR</h2>
|
|
||||||
|
|
||||||
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">Current devices</h2>
|
|
||||||
</div>
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<a href="" ng-click="order('id')">ID</a>
|
|
||||||
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span></th>
|
|
||||||
<th>
|
|
||||||
<a href="" ng-click="order('name')">Name</a>
|
|
||||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span></th>
|
|
||||||
<th>
|
|
||||||
<a href="" ng-click="order('deviceType')">Type</a>
|
|
||||||
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
|
|
||||||
<td>{{device.id}}</td>
|
|
||||||
<td>{{device.name}}</td>
|
|
||||||
<td>{{device.deviceType}}</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device, 'on')">Test ON</button>
|
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device, 'off')">Test OFF</button>
|
|
||||||
<button class="btn btn-warning" type="submit"
|
|
||||||
ng-click="editDevice(device)">Edit</button>
|
|
||||||
<button class="btn btn-danger" type="submit"
|
|
||||||
ng-click="deleteDevice(device)">Delete</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="panel panel-default bridgeServer">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<a href="#/show"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a>
|
|
||||||
<h1 class="panel-title">Bridge settings</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -4,17 +4,20 @@
|
|||||||
<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="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
||||||
@@ -23,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>
|
||||||
@@ -41,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
|
||||||
@@ -57,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>
|
||||||
@@ -75,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">
|
||||||
@@ -87,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">
|
||||||
@@ -101,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>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<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="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</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>
|
||||||
|
|
||||||
@@ -13,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 scene 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>
|
||||||
@@ -30,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
|
||||||
@@ -47,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>
|
||||||
@@ -63,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">
|
||||||
@@ -75,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">
|
||||||
@@ -89,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>
|
||||||
|
|||||||
Reference in New Issue
Block a user