mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b335d6b9b | ||
|
|
b27bb5eef8 | ||
|
|
3c54ccd56d | ||
|
|
cf772334c4 | ||
|
|
5a843f7569 | ||
|
|
2a52783bb1 | ||
|
|
195f1854ec | ||
|
|
2e5596a6e4 | ||
|
|
9fc13c6c45 | ||
|
|
4b4d4e36c7 | ||
|
|
1e7bdc560b | ||
|
|
aff0f8d64c | ||
|
|
7a812d6e6b | ||
|
|
26f2105801 | ||
|
|
feef345a3b | ||
|
|
314ae58ebd | ||
|
|
d8b6232ac1 | ||
|
|
41e22ee64d | ||
|
|
be2fbcd4cb | ||
|
|
14e7f37522 | ||
|
|
e3f5946c9d | ||
|
|
12eab16f21 | ||
|
|
3df68047a9 | ||
|
|
0dd652f82a | ||
|
|
53af1a4dfd | ||
|
|
816a0025b1 | ||
|
|
405562809a | ||
|
|
4c87c6fce8 | ||
|
|
2fd0f7748b | ||
|
|
ed5f3b4b3c | ||
|
|
aad09b7527 | ||
|
|
0ae66da085 | ||
|
|
d344b764da | ||
|
|
c85b67fb9f | ||
|
|
a23d662444 | ||
|
|
4b98f799c2 | ||
|
|
acba2b5cae | ||
|
|
4dc818296a | ||
|
|
40123ed858 | ||
|
|
718ba5a5c2 | ||
|
|
2e6944d840 | ||
|
|
e29f12905d | ||
|
|
408b79d5d8 | ||
|
|
bf5ad2e23c | ||
|
|
59f1db285d | ||
|
|
203ed0b5d3 | ||
|
|
b443d16a11 | ||
|
|
295b1e1a30 |
92
pom.xml
92
pom.xml
@@ -5,11 +5,11 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>0.4.10</version>
|
||||
<version>1.2.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera, using lightweight frameworks</description>
|
||||
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub, using lightweight frameworks</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
@@ -17,11 +17,23 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>harmony-java-client</artifactId>
|
||||
<version>1.0.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
@@ -58,9 +70,35 @@
|
||||
<artifactId>eval</artifactId>
|
||||
<version>0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>4.0-beta4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.igniterealtime.smack</groupId>
|
||||
<artifactId>smack-core</artifactId>
|
||||
<version>4.0.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>version.properties</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>version.properties</exclude>
|
||||
</excludes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -83,24 +121,42 @@
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
<exclude>META-INF/*.txt</exclude>
|
||||
<exclude>META-INF/maven/**</exclude>
|
||||
<exclude>META-INF/services/**</exclude>
|
||||
<exclude>META-INF/DEPENDENCIES</exclude>
|
||||
<exclude>about_files/**</exclude>
|
||||
<exclude>*.properties</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.slf4j:*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>commons-logging:commons-logging</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.slf4j:*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>commons-logging:commons-logging</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>xpp3:xpp3</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.igniterealtime.smack:*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>com.github.bwssytems:harmony-java-client</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<transformers>
|
||||
<transformer
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BridgeSettings {
|
||||
private String upnpconfigaddress;
|
||||
private String serverport;
|
||||
private String upnpresponseport;
|
||||
private String upnpdevicedb;
|
||||
private String veraaddress;
|
||||
private IpList harmonyaddress;
|
||||
private String harmonyuser;
|
||||
private String harmonypwd;
|
||||
private Integer upnpresponsedevices;
|
||||
private boolean upnpstrict;
|
||||
private boolean traceupnp;
|
||||
private boolean vtwocompatibility;
|
||||
private boolean devmode;
|
||||
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
@@ -40,7 +46,30 @@ public class BridgeSettings {
|
||||
public void setVeraAddress(String veraAddress) {
|
||||
this.veraaddress = veraAddress;
|
||||
}
|
||||
|
||||
public IpList getHarmonyAddress() {
|
||||
return harmonyaddress;
|
||||
}
|
||||
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||
this.harmonyaddress = harmonyaddress;
|
||||
}
|
||||
public String getHarmonyUser() {
|
||||
return harmonyuser;
|
||||
}
|
||||
public void setHarmonyUser(String harmonyuser) {
|
||||
this.harmonyuser = harmonyuser;
|
||||
}
|
||||
public String getHarmonyPwd() {
|
||||
return harmonypwd;
|
||||
}
|
||||
public void setHarmonyPwd(String harmonypwd) {
|
||||
this.harmonypwd = harmonypwd;
|
||||
}
|
||||
public Integer getUpnpResponseDevices() {
|
||||
return upnpresponsedevices;
|
||||
}
|
||||
public void setUpnpResponseDevices(Integer upnpresponsedevices) {
|
||||
this.upnpresponsedevices = upnpresponsedevices;
|
||||
}
|
||||
public boolean isUpnpStrict() {
|
||||
return upnpstrict;
|
||||
}
|
||||
@@ -53,17 +82,25 @@ public class BridgeSettings {
|
||||
public void setTraceupnp(boolean traceupnp) {
|
||||
this.traceupnp = traceupnp;
|
||||
}
|
||||
|
||||
public boolean isVtwocompatibility() {
|
||||
return vtwocompatibility;
|
||||
public boolean isDevMode() {
|
||||
return devmode;
|
||||
}
|
||||
public void setVtwocompatibility(boolean vtwocompatibility) {
|
||||
this.vtwocompatibility = vtwocompatibility;
|
||||
public void setDevMode(boolean devmode) {
|
||||
this.devmode = devmode;
|
||||
}
|
||||
|
||||
public Boolean isValidVera() {
|
||||
if(this.veraaddress.contains(Configuration.DEFAULT_VERA_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public Boolean isValidHarmony() {
|
||||
List<NamedIP> devicesList = this.harmonyaddress.getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_HARMONY_ADDRESS))
|
||||
return false;
|
||||
if(this.harmonypwd == null || this.harmonypwd == "")
|
||||
return false;
|
||||
if(this.harmonyuser == null || this.harmonyuser == "")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package com.bwssystems.HABridge;
|
||||
public class Configuration {
|
||||
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||
public final static String UPNP_RESPONSE_DEVICES = "30";
|
||||
public final static String DEFAULT_VERA_ADDRESS = "1.1.1.1";
|
||||
public final static String DEFAULT_HARMONY_ADDRESS = "1.1.1.1";
|
||||
public final static String DEFAULT_HARMONY_ADDRESS_LIST = "{devices:[{name:default,ip:1.1.1.1}]}";
|
||||
public final static String DEFAULT_HARMONY_USER = "";
|
||||
public final static String DEFAULT_HARMONY_PWD = "";
|
||||
public final static String DFAULT_WEB_PORT = "8080";
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
|
||||
import com.bwssystems.HABridge.hue.HueMulator;
|
||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||
import com.bwssystems.harmony.HarmonyHome;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HABridge {
|
||||
|
||||
@@ -33,14 +35,18 @@ public class HABridge {
|
||||
public static void main(String[] args) {
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
DeviceResource theResources;
|
||||
HarmonyHome harmonyHome;
|
||||
HueMulator theHueMulator;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
InetAddress address;
|
||||
String addressString;
|
||||
BridgeSettings bridgeSettings;
|
||||
Version theVersion;
|
||||
|
||||
theVersion = new Version();
|
||||
|
||||
log.info("HA Bridge (v0.4.10) starting setup....");
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
|
||||
//get ip address for upnp requests
|
||||
try {
|
||||
address = InetAddress.getLocalHost();
|
||||
@@ -51,25 +57,43 @@ public class HABridge {
|
||||
}
|
||||
|
||||
bridgeSettings = new BridgeSettings();
|
||||
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.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
|
||||
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_HARMONY_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_HARMONY_USER));
|
||||
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_HARMONY_PWD));
|
||||
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||
bridgeSettings.setVtwocompatibility(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "false")));
|
||||
|
||||
bridgeSettings.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "false")));
|
||||
bridgeSettings.setUpnpResponseDevices(Integer.parseInt(System.getProperty("upnp.response.devices", Configuration.UPNP_RESPONSE_DEVICES)));
|
||||
|
||||
// sparkjava config directive to set ip address for the web server to listen on
|
||||
// ipAddress("0.0.0.0"); // not used
|
||||
// sparkjava config directive to set port for the web server to listen on
|
||||
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
|
||||
port(Integer.valueOf(bridgeSettings.getServerPort()));
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
staticFileLocation("/public");
|
||||
//setup the harmony connection if available
|
||||
harmonyHome = new HarmonyHome(bridgeSettings);
|
||||
// setup the class to handle the resource setup rest api
|
||||
theResources = new DeviceResource(bridgeSettings);
|
||||
theResources = new DeviceResource(bridgeSettings, theVersion, harmonyHome);
|
||||
// setup the class to handle the hue emulator rest api
|
||||
theHueMulator = new HueMulator(theResources.getDeviceRepository());
|
||||
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), harmonyHome);
|
||||
theHueMulator.setupServer();
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||
|
||||
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class IpList {
|
||||
private List<NamedIP> devices;
|
||||
|
||||
public List<NamedIP> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public void setDevices(List<NamedIP> devices) {
|
||||
this.devices = devices;
|
||||
}
|
||||
|
||||
}
|
||||
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
public class NamedIP {
|
||||
private String name;
|
||||
private String ip;
|
||||
private String port;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
public String getPort() {
|
||||
return port;
|
||||
}
|
||||
public void setPort(String port) {
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
public final class Version {
|
||||
|
||||
private String version;
|
||||
private String groupId;
|
||||
private String artifactId;
|
||||
private Properties prop;
|
||||
|
||||
public Version()
|
||||
{
|
||||
InputStream resourceAsStream =
|
||||
(InputStream) this.getClass().getResourceAsStream(
|
||||
"/version.properties"
|
||||
);
|
||||
this.prop = new Properties();
|
||||
|
||||
try
|
||||
{
|
||||
this.prop.load( resourceAsStream );
|
||||
this.version = this.prop.getProperty("version");
|
||||
this.groupId = this.prop.getProperty("groupId");
|
||||
this.artifactId = this.prop.getProperty("artifactId");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.version = "0.0.0";
|
||||
this.groupId = "no group";
|
||||
this.artifactId = "no artifact";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
*/
|
||||
@@ -14,7 +11,6 @@ public class DeviceResponse {
|
||||
private String manufacturername;
|
||||
private String uniqueid;
|
||||
private String swversion;
|
||||
private Map<String, String> pointsymbol;
|
||||
|
||||
public DeviceState getState() {
|
||||
return state;
|
||||
@@ -72,27 +68,6 @@ public class DeviceResponse {
|
||||
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){
|
||||
DeviceState deviceState = new DeviceState();
|
||||
DeviceResponse response = new DeviceResponse();
|
||||
@@ -102,14 +77,13 @@ public class DeviceResponse {
|
||||
deviceState.setEffect("none");
|
||||
deviceState.setAlert("none");
|
||||
deviceState.setBri(254);
|
||||
deviceState.setSat(254);
|
||||
|
||||
response.setName(name);
|
||||
response.setUniqueid(id);
|
||||
response.setManufacturername("Philips");
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB004");
|
||||
response.setSwversion("65003148");
|
||||
response.setSwversion("66012040");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
@@ -8,14 +7,9 @@ import java.util.List;
|
||||
public class DeviceState {
|
||||
private boolean on;
|
||||
private int bri = 255;
|
||||
private int hue;
|
||||
private int sat;
|
||||
private String effect;
|
||||
private int ct;
|
||||
private String alert;
|
||||
private String colormode;
|
||||
private boolean reachable;
|
||||
private List<Double> xy;
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
@@ -33,22 +27,6 @@ public class DeviceState {
|
||||
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() {
|
||||
return effect;
|
||||
}
|
||||
@@ -57,14 +35,6 @@ public class DeviceState {
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public int getCt() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
public void setCt(int ct) {
|
||||
this.ct = ct;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return alert;
|
||||
}
|
||||
@@ -73,14 +43,6 @@ public class DeviceState {
|
||||
this.alert = alert;
|
||||
}
|
||||
|
||||
public String getColormode() {
|
||||
return colormode;
|
||||
}
|
||||
|
||||
public void setColormode(String colormode) {
|
||||
this.colormode = colormode;
|
||||
}
|
||||
|
||||
public boolean isReachable() {
|
||||
return reachable;
|
||||
}
|
||||
@@ -89,14 +51,6 @@ public class DeviceState {
|
||||
this.reachable = reachable;
|
||||
}
|
||||
|
||||
public List<Double> getXy() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXy(List<Double> xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceState{" +
|
||||
|
||||
@@ -12,11 +12,17 @@ public class HueApiResponse {
|
||||
private Map<String, DeviceResponse> lights;
|
||||
private Map<String, String> scenes;
|
||||
private Map<String, String> groups;
|
||||
private Map<String, String> schedules;
|
||||
private Map<String, String> sensors;
|
||||
private Map<String, String> rules;
|
||||
private HueConfig config;
|
||||
|
||||
public HueApiResponse(String name, String ipaddress, String username, String userid) {
|
||||
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
||||
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.setScenes(new HashMap<>());
|
||||
}
|
||||
@@ -45,6 +51,30 @@ public class HueApiResponse {
|
||||
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() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
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.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class HueConfig
|
||||
{
|
||||
@@ -26,10 +33,13 @@ public class HueConfig
|
||||
|
||||
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
|
||||
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.setPortalservices(false);
|
||||
aConfig.setGateway("192.168.1.1");
|
||||
aConfig.setMac("00:00:88:00:bb:ee");
|
||||
aConfig.setGateway(ipaddress);
|
||||
aConfig.setSwversion("01005215");
|
||||
aConfig.setLinkbutton(false);
|
||||
aConfig.setIpaddress(ipaddress);
|
||||
@@ -38,20 +48,50 @@ public class HueConfig
|
||||
aConfig.setNetmask("255.255.255.0");
|
||||
aConfig.setName(name);
|
||||
aConfig.setDhcp(true);
|
||||
aConfig.setUtc("2014-07-17T09:27:35");
|
||||
aConfig.setProxyaddress("0.0.0.0");
|
||||
aConfig.setLocaltime("2014-07-17T11:27:35");
|
||||
aConfig.setTimezone("America/Chicago");
|
||||
aConfig.setUtc(dateFormatGmt.format(new Date()));
|
||||
aConfig.setProxyaddress("none");
|
||||
aConfig.setLocaltime(dateFormat.format(new Date()));
|
||||
aConfig.setTimezone(TimeZone.getDefault().getID());
|
||||
aConfig.setZigbeechannel("6");
|
||||
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
|
||||
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype));
|
||||
aConfig.setWhitelist(awhitelist);
|
||||
|
||||
|
||||
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() {
|
||||
return portalservices;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ package com.bwssystems.HABridge.dao;
|
||||
public class DeviceDescriptor{
|
||||
private String id;
|
||||
private String name;
|
||||
private String mapId;
|
||||
private String mapType;
|
||||
private String deviceType;
|
||||
private String targetDevice;
|
||||
private String offUrl;
|
||||
private String onUrl;
|
||||
private String httpVerb;
|
||||
@@ -21,7 +24,23 @@ public class DeviceDescriptor{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
public String getMapId() {
|
||||
return mapId;
|
||||
}
|
||||
|
||||
public void setMapId(String mapId) {
|
||||
this.mapId = mapId;
|
||||
}
|
||||
|
||||
public String getMapType() {
|
||||
return mapType;
|
||||
}
|
||||
|
||||
public void setMapType(String mapType) {
|
||||
this.mapType = mapType;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
@@ -29,7 +48,15 @@ public class DeviceDescriptor{
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public String getOffUrl() {
|
||||
public String getTargetDevice() {
|
||||
return targetDevice;
|
||||
}
|
||||
|
||||
public void setTargetDevice(String targetDevice) {
|
||||
this.targetDevice = targetDevice;
|
||||
}
|
||||
|
||||
public String getOffUrl() {
|
||||
return offUrl;
|
||||
}
|
||||
|
||||
|
||||
@@ -178,9 +178,18 @@ public class DeviceRepository {
|
||||
} else if (name.equals("name")) {
|
||||
deviceEntry.setName(reader.nextString());
|
||||
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")) {
|
||||
deviceEntry.setDeviceType(reader.nextString());
|
||||
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")) {
|
||||
deviceEntry.setOffUrl(reader.nextString());
|
||||
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bwssystems.HABridge.devicemanagmeent;
|
||||
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.options;
|
||||
import static spark.Spark.post;
|
||||
import static spark.Spark.put;
|
||||
import static spark.Spark.delete;
|
||||
@@ -16,8 +17,10 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.JsonTransformer;
|
||||
import com.bwssystems.HABridge.Version;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||
import com.bwssystems.harmony.HarmonyHome;
|
||||
import com.bwssystems.luupRequests.Sdata;
|
||||
import com.bwssystems.vera.VeraInfo;
|
||||
import com.google.gson.Gson;
|
||||
@@ -31,12 +34,18 @@ public class DeviceResource {
|
||||
|
||||
private DeviceRepository deviceRepository;
|
||||
private VeraInfo veraInfo;
|
||||
private Version version;
|
||||
private HarmonyHome myHarmonyHome;
|
||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||
|
||||
public DeviceResource(BridgeSettings theSettings) {
|
||||
super();
|
||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
||||
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHome theHarmonyHome) {
|
||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
this.veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
||||
if(theSettings.isValidHarmony())
|
||||
this.myHarmonyHome = theHarmonyHome;
|
||||
else
|
||||
this.myHarmonyHome = null;
|
||||
this.version = theVersion;
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
@@ -46,6 +55,15 @@ public class DeviceResource {
|
||||
|
||||
private void setupEndpoints() {
|
||||
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) -> {
|
||||
log.debug("Create a Device - request body: " + request.body());
|
||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||
@@ -61,11 +79,21 @@ public class DeviceResource {
|
||||
deviceRepository.save(device);
|
||||
log.debug("Created a Device: " + request.body());
|
||||
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.status(HttpStatus.SC_CREATED);
|
||||
|
||||
return device;
|
||||
}, 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) -> {
|
||||
log.debug("Edit a Device - request body: " + request.body());
|
||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||
@@ -81,6 +109,9 @@ public class DeviceResource {
|
||||
deviceEntry.setName(device.getName());
|
||||
if (device.getDeviceType() != null)
|
||||
deviceEntry.setDeviceType(device.getDeviceType());
|
||||
deviceEntry.setMapId(device.getMapId());
|
||||
deviceEntry.setMapType(device.getMapType());
|
||||
deviceEntry.setTargetDevice(device.getTargetDevice());
|
||||
deviceEntry.setOnUrl(device.getOnUrl());
|
||||
deviceEntry.setOffUrl(device.getOffUrl());
|
||||
deviceEntry.setHttpVerb(device.getHttpVerb());
|
||||
@@ -115,8 +146,9 @@ public class DeviceResource {
|
||||
}, new JsonTransformer());
|
||||
|
||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||
log.debug("Delete a device");
|
||||
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
|
||||
String anId = request.params(":id");
|
||||
log.debug("Delete a device: " + anId);
|
||||
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
||||
if(deleted == null)
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
else
|
||||
@@ -127,6 +159,12 @@ public class DeviceResource {
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
|
||||
log.debug("Get HA Bridge version: v" + version.getVersion());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return "{\"version\":\"" + version.getVersion() + "\"}";
|
||||
});
|
||||
|
||||
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get vera devices");
|
||||
Sdata sData = veraInfo.getSdata();
|
||||
@@ -150,5 +188,35 @@ public class DeviceResource {
|
||||
return sData.getScenes();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||
log.debug("Get harmony activities");
|
||||
if(myHarmonyHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return null;
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return myHarmonyHome.getActivities();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
||||
log.debug("Get harmony current activity");
|
||||
if(myHarmonyHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return null;
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return myHarmonyHome.getCurrentActivities();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get harmony devices");
|
||||
if(myHarmonyHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return null;
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return myHarmonyHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.JsonTransformer;
|
||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||
import com.bwssystems.HABridge.dao.*;
|
||||
import com.bwssystems.harmony.ButtonPress;
|
||||
import com.bwssystems.harmony.HarmonyHandler;
|
||||
import com.bwssystems.harmony.HarmonyHome;
|
||||
import com.bwssystems.harmony.RunActivity;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
@@ -13,6 +18,7 @@ import com.google.gson.Gson;
|
||||
import net.java.dev.eval.Expression;
|
||||
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.options;
|
||||
import static spark.Spark.post;
|
||||
import static spark.Spark.put;
|
||||
|
||||
@@ -33,10 +39,15 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
/**
|
||||
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
||||
*/
|
||||
@@ -51,23 +62,33 @@ public class HueMulator {
|
||||
private static final String HUE_CONTEXT = "/api";
|
||||
|
||||
private DeviceRepository repository;
|
||||
private HarmonyHome myHarmonyHome;
|
||||
private HttpClient httpClient;
|
||||
private ObjectMapper mapper;
|
||||
private BridgeSettings bridgeSettings;
|
||||
private byte[] sendData;
|
||||
|
||||
|
||||
public HueMulator(DeviceRepository aDeviceRepository){
|
||||
public HueMulator(BridgeSettings theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome){
|
||||
httpClient = HttpClients.createDefault();
|
||||
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
repository = aDeviceRepository;
|
||||
if(theBridgeSettings.isValidHarmony())
|
||||
this.myHarmonyHome = theHarmonyHome;
|
||||
else
|
||||
this.myHarmonyHome = null;
|
||||
bridgeSettings = theBridgeSettings;
|
||||
}
|
||||
|
||||
// This function sets up the sparkjava rest calls for the hue api
|
||||
public void setupServer() {
|
||||
log.info("Hue emulator service started....");
|
||||
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
|
||||
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
|
||||
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
|
||||
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());
|
||||
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
||||
@@ -80,12 +101,23 @@ public class HueMulator {
|
||||
return deviceResponseMap;
|
||||
} , 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) -> {
|
||||
UserCreateRequest aNewUser = null;
|
||||
String newUser = 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());
|
||||
|
||||
if(request.body() != null && !request.body().isEmpty()) {
|
||||
@@ -98,20 +130,33 @@ public class HueMulator {
|
||||
|
||||
if(aDeviceType == null)
|
||||
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);
|
||||
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
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
|
||||
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
|
||||
UserCreateRequest aNewUser = null;
|
||||
String newUser = null;
|
||||
String aDeviceType = null;
|
||||
|
||||
log.info("HH trace: hue api user create requested: " + request.body() + " from " + request.ip());
|
||||
if(bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api/* user create requested: " + request.body() + " from " + request.ip());
|
||||
|
||||
if(request.body() != null && !request.body().isEmpty()) {
|
||||
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
|
||||
@@ -125,12 +170,42 @@ public class HueMulator {
|
||||
aDeviceType = "<not given>";
|
||||
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.status(HttpStatus.SC_OK);
|
||||
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) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
||||
@@ -146,7 +221,7 @@ public class HueMulator {
|
||||
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);
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
@@ -154,7 +229,7 @@ public class HueMulator {
|
||||
return apiResponse;
|
||||
}, 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) -> {
|
||||
String userId = request.params(":userid");
|
||||
String lightId = request.params(":id");
|
||||
@@ -173,7 +248,16 @@ public class HueMulator {
|
||||
return lightResponse;
|
||||
}, 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) -> {
|
||||
/**
|
||||
* strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
|
||||
@@ -181,50 +265,117 @@ public class HueMulator {
|
||||
*/
|
||||
String userId = request.params(":userid");
|
||||
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;
|
||||
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 {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
} catch (IOException e) {
|
||||
log.error("Object mapper barfed on input of body.", e);
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
return null;
|
||||
log.warn("Object mapper barfed on input of body.", e);
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + ",\"description\": \"Object mapper barfed on input of body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if (device == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
log.error("Could not find devcie: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
return null;
|
||||
log.warn("Could not find device: " + 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 responseString;
|
||||
}
|
||||
|
||||
String responseString;
|
||||
String url;
|
||||
if (state.isOn()) {
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]";
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}";
|
||||
url = device.getOnUrl();
|
||||
} else {
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
|
||||
} else if (request.body().contains("false")) {
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}";
|
||||
url = device.getOffUrl();
|
||||
}
|
||||
|
||||
//quick template
|
||||
String body;
|
||||
url = replaceIntensityValue(url, state.getBri());
|
||||
if (state.isOn())
|
||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||
|
||||
if(request.body().contains("bri"))
|
||||
{
|
||||
if(url == null)
|
||||
{
|
||||
url = device.getOnUrl();
|
||||
responseString = "[";
|
||||
}
|
||||
else
|
||||
responseString = responseString + ",";
|
||||
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||
}
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||
//make call
|
||||
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
|
||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||
log.error("Error on calling url to change device state: " + url);
|
||||
return null;
|
||||
responseString = responseString + "]";
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||
{
|
||||
log.debug("executing activity to Harmony: " + url);
|
||||
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
|
||||
HarmonyHandler myHarmony = myHarmonyHome.getHarmonyHandler(device.getTargetDevice());
|
||||
if(myHarmony == null)
|
||||
{
|
||||
log.warn("Should not get here, no harmony hub available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
}
|
||||
else
|
||||
myHarmony.startActivity(anActivity);
|
||||
}
|
||||
else if(device.getDeviceType().toLowerCase().contains("button") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||
{
|
||||
log.debug("executing button press to Harmony: " + url);
|
||||
ButtonPress aDeviceButton = 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
|
||||
myHarmony.pressButton(aDeviceButton);
|
||||
}
|
||||
else if(url.startsWith("udp://"))
|
||||
{
|
||||
try {
|
||||
String intermediate = url.substring(6);
|
||||
String ipAddr = intermediate.substring(0, intermediate.indexOf(':'));
|
||||
String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/'));
|
||||
String theBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||
if(theBody.startsWith("0x")) {
|
||||
sendData = DatatypeConverter.parseHexBinary(theBody.substring(2));
|
||||
}
|
||||
else
|
||||
sendData = theBody.getBytes();
|
||||
InetAddress IPAddress = InetAddress.getByName(ipAddr);
|
||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||
responseSocket.send(sendPacket);
|
||||
responseSocket.close();
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not send UDP Datagram packet for request.", e);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug("executing activity to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + url);
|
||||
// quick template
|
||||
String body;
|
||||
url = replaceIntensityValue(url, state.getBri());
|
||||
if (state.isOn())
|
||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||
// make call
|
||||
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
||||
log.warn("Error on calling url to change device state: " + url);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
}
|
||||
}
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return responseString;
|
||||
});
|
||||
}
|
||||
@@ -260,7 +411,7 @@ public class HueMulator {
|
||||
Integer endResult = Math.round(result.floatValue());
|
||||
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("Could not execute Math: " + mathDescriptor, e);
|
||||
log.warn("Could not execute Math: " + mathDescriptor, e);
|
||||
} }
|
||||
return request;
|
||||
}
|
||||
@@ -288,12 +439,12 @@ public class HueMulator {
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
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){
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error calling out to HA gateway", e);
|
||||
log.warn("Error calling out to HA gateway", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ public class UpnpListener {
|
||||
|
||||
private boolean traceupnp;
|
||||
|
||||
private boolean vTwoCompatibility;
|
||||
|
||||
public UpnpListener(BridgeSettings theSettings) {
|
||||
super();
|
||||
upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort());
|
||||
@@ -36,7 +34,6 @@ public class UpnpListener {
|
||||
responseAddress = theSettings.getUpnpConfigAddress();
|
||||
strict = theSettings.isUpnpStrict();
|
||||
traceupnp = theSettings.isTraceupnp();
|
||||
vTwoCompatibility = theSettings.isVtwocompatibility();
|
||||
}
|
||||
|
||||
public void startListening(){
|
||||
@@ -79,14 +76,7 @@ public class UpnpListener {
|
||||
byte[] buf = new byte[1024];
|
||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||
upnpMulticastSocket.receive(packet);
|
||||
String packetString = new String(packet.getData());
|
||||
if(packetString != null && packetString.contains("M-SEARCH")) {
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||
else
|
||||
log.debug("Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||
}
|
||||
if(isSSDPDiscovery(packetString)){
|
||||
if(isSSDPDiscovery(packet)){
|
||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||
}
|
||||
}
|
||||
@@ -100,31 +90,40 @@ public class UpnpListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* very naive ssdp discovery packet detection
|
||||
* @param body
|
||||
* @return
|
||||
* ssdp discovery packet detection
|
||||
*/
|
||||
protected boolean isSSDPDiscovery(String body){
|
||||
// log.debug("Check if this is a MAN ssdp-discover packet for a upnp basic device: " + body);
|
||||
//Only respond to discover request for upnp basic device from echo, the others are for the wemo
|
||||
if(body != null && body.contains("M-SEARCH") && body.contains("\"ssdp:discover\"")){
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message.");
|
||||
if(strict && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"") && (body.contains("ST: urn:schemas-upnp-org:device:basic:1") || body.contains("ST: upnp:rootdevice") || body.contains("ST: ssdp:all")))
|
||||
protected boolean isSSDPDiscovery(DatagramPacket packet){
|
||||
//Only respond to discover request for strict upnp form
|
||||
String packetString = new String(packet.getData());
|
||||
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")){
|
||||
log.debug("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 && (packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") || packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all")))
|
||||
{
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||
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: 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;
|
||||
}
|
||||
else if (!strict || vTwoCompatibility)
|
||||
else if (!strict)
|
||||
{
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||
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: 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;
|
||||
}
|
||||
}
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: isSSDPDiscovery found message to not be valid - strict: " + strict + ", vTwo.Compatibility: " + vTwoCompatibility);
|
||||
else {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -135,20 +134,9 @@ public class UpnpListener {
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||
String discoveryTemplateVTwo = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
|
||||
"01-NLS: %s\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
|
||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||
String discoveryResponse = null;
|
||||
if(vTwoCompatibility)
|
||||
discoveryResponse = String.format(discoveryTemplateVTwo, responseAddress, httpServerPort, getRandomUUIDString());
|
||||
else
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
|
||||
else
|
||||
@@ -156,8 +144,4 @@ public class UpnpListener {
|
||||
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
||||
socket.send(response);
|
||||
}
|
||||
|
||||
protected String getRandomUUIDString(){
|
||||
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,56 +40,19 @@ public class UpnpSettingsResource {
|
||||
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
|
||||
+ "</root>\n";
|
||||
|
||||
private String hueTemplateVTwo = "<?xml version=\"1.0\"?>\n" +
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n" +
|
||||
"<specVersion>\n" +
|
||||
"<major>1</major>\n" +
|
||||
"<minor>0</minor>\n" +
|
||||
"</specVersion>\n" +
|
||||
"<URLBase>http://%s:%s/</URLBase>\n" + //hostname string
|
||||
"<device>\n" +
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n" +
|
||||
"<friendlyName>Amazon-Echo-HA-Bridge (%s)</friendlyName>\n" +
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>\n" +
|
||||
"<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n" +
|
||||
"<modelDescription>Hue Emulator for Amazon Echo bridge</modelDescription>\n" +
|
||||
"<modelName>Philips hue bridge 2012</modelName>\n" +
|
||||
"<modelNumber>929000226503</modelNumber>\n" +
|
||||
"<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n" +
|
||||
"<serialNumber>01189998819991197253</serialNumber>\n" +
|
||||
"<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" +
|
||||
"<serviceList>\n" +
|
||||
"<service>\n" +
|
||||
"<serviceType>(null)</serviceType>\n" +
|
||||
"<serviceId>(null)</serviceId>\n" +
|
||||
"<controlURL>(null)</controlURL>\n" +
|
||||
"<eventSubURL>(null)</eventSubURL>\n" +
|
||||
"<SCPDURL>(null)</SCPDURL>\n" +
|
||||
"</service>\n" +
|
||||
"</serviceList>\n" +
|
||||
"<presentationURL>index.html</presentationURL>\n" +
|
||||
"<iconList>\n" +
|
||||
"<icon>\n" +
|
||||
"<mimetype>image/png</mimetype>\n" +
|
||||
"<height>48</height>\n" +
|
||||
"<width>48</width>\n" +
|
||||
"<depth>24</depth>\n" +
|
||||
"<url>hue_logo_0.png</url>\n" +
|
||||
"</icon>\n" +
|
||||
"<icon>\n" +
|
||||
"<mimetype>image/png</mimetype>\n" +
|
||||
"<height>120</height>\n" +
|
||||
"<width>120</width>\n" +
|
||||
"<depth>24</depth>\n" +
|
||||
"<url>hue_logo_3.png</url>\n" +
|
||||
"</icon>\n" +
|
||||
"</iconList>\n" +
|
||||
"</device>\n" +
|
||||
"</root>\n";
|
||||
|
||||
public UpnpSettingsResource(BridgeSettings theSettings) {
|
||||
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
|
||||
super();
|
||||
this.theSettings = theSettings;
|
||||
this.theSettings = new BridgeSettings();
|
||||
this.theSettings.setDevMode(theBridgeSettings.isDevMode());
|
||||
this.theSettings.setHarmonyAddress(theBridgeSettings.getHarmonyAddress());
|
||||
this.theSettings.setServerPort(theBridgeSettings.getServerPort());
|
||||
this.theSettings.setTraceupnp(theBridgeSettings.isTraceupnp());
|
||||
this.theSettings.setUpnpConfigAddress(theBridgeSettings.getUpnpConfigAddress());
|
||||
this.theSettings.setUpnpDeviceDb(theBridgeSettings.getUpnpDeviceDb());
|
||||
this.theSettings.setUpnpResponseDevices(theBridgeSettings.getUpnpResponseDevices());
|
||||
this.theSettings.setUpnpResponsePort(theBridgeSettings.getUpnpResponsePort());
|
||||
this.theSettings.setUpnpStrict(theBridgeSettings.isUpnpStrict());
|
||||
this.theSettings.setVeraAddress(theBridgeSettings.getVeraAddress());
|
||||
}
|
||||
|
||||
public void setupServer() {
|
||||
@@ -102,10 +65,7 @@ public class UpnpSettingsResource {
|
||||
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
||||
String portNumber = Integer.toString(request.port());
|
||||
String filledTemplate = null;
|
||||
if(theSettings.isVtwocompatibility())
|
||||
filledTemplate = String.format(hueTemplateVTwo, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
else
|
||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
if(theSettings.isTraceupnp())
|
||||
log.info("Traceupnp: upnp device settings response: " + filledTemplate);
|
||||
else
|
||||
|
||||
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
public class ButtonPress {
|
||||
private String device;
|
||||
private String button;
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
public void setDevice(String device) {
|
||||
this.device = device;
|
||||
}
|
||||
public String getButton() {
|
||||
return button;
|
||||
}
|
||||
public void setButton(String button) {
|
||||
this.button = button;
|
||||
}
|
||||
public Boolean isValid() {
|
||||
if (device != null && !device.isEmpty()){
|
||||
if (button != null && !button.isEmpty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||
|
||||
public class DevModeResponse {
|
||||
final Logger log = LoggerFactory.getLogger(DevModeResponse.class);
|
||||
|
||||
private final static String powerOff = "PowerOff";
|
||||
private HarmonyConfig harmonyConfig;
|
||||
private Activity currentActivity;
|
||||
|
||||
public DevModeResponse() {
|
||||
super();
|
||||
harmonyConfig = HarmonyConfig.parse(dataReader("/config.data"));
|
||||
this.currentActivity = harmonyConfig.getActivityByName(powerOff);
|
||||
}
|
||||
|
||||
public Activity getCurrentActivity() {
|
||||
return currentActivity;
|
||||
}
|
||||
|
||||
public void setCurrentActivity(Activity currentActivity) {
|
||||
this.currentActivity = currentActivity;
|
||||
}
|
||||
|
||||
public List<Activity> getActivities() {
|
||||
return harmonyConfig.getActivities();
|
||||
}
|
||||
|
||||
public List<Device> getDevices() {
|
||||
return harmonyConfig.getDevices();
|
||||
}
|
||||
|
||||
public HarmonyConfig getConfig() {
|
||||
return harmonyConfig;
|
||||
}
|
||||
|
||||
private String dataReader(String filePath) {
|
||||
|
||||
String content = null;
|
||||
try {
|
||||
InputStream input = getClass().getResourceAsStream(filePath);
|
||||
OutputStream out = new ByteArrayOutputStream();
|
||||
int read;
|
||||
byte[] bytes = new byte[1024];
|
||||
|
||||
while ((read = input.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, read);
|
||||
}
|
||||
content = out.toString();
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
21
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
|
||||
public class HarmonyActivity {
|
||||
private String hub;
|
||||
private Activity activity;
|
||||
public String getHub() {
|
||||
return hub;
|
||||
}
|
||||
public void setHub(String hub) {
|
||||
this.hub = hub;
|
||||
}
|
||||
public Activity getActivity() {
|
||||
return activity;
|
||||
}
|
||||
public void setActivity(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
}
|
||||
20
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
20
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
|
||||
public class HarmonyDevice {
|
||||
private Device device;
|
||||
private String hub;
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
public void setDevice(Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
public String getHub() {
|
||||
return hub;
|
||||
}
|
||||
public void setHub(String hub) {
|
||||
this.hub = hub;
|
||||
}
|
||||
}
|
||||
122
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
122
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||
|
||||
public class HarmonyHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||
private HarmonyClient harmonyClient;
|
||||
private Boolean noopCalls;
|
||||
private Boolean devMode;
|
||||
private DevModeResponse devResponse;
|
||||
|
||||
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
|
||||
super();
|
||||
noopCalls = noopCallsSetting;
|
||||
devMode = Boolean.TRUE;
|
||||
devResponse = null;
|
||||
if(devResponseSetting == null)
|
||||
devMode = Boolean.FALSE;
|
||||
else
|
||||
devResponse = devResponseSetting;
|
||||
harmonyClient = theClient;
|
||||
}
|
||||
|
||||
public List<Activity> getActivities() {
|
||||
log.debug("Harmony api activities list requested.");
|
||||
if(devMode)
|
||||
return devResponse.getActivities();
|
||||
|
||||
return harmonyClient.getConfig().getActivities();
|
||||
}
|
||||
|
||||
public List<Device> getDevices() {
|
||||
log.debug("Harmony api device list requested.");
|
||||
if(devMode)
|
||||
return devResponse.getDevices();
|
||||
|
||||
return harmonyClient.getConfig().getDevices();
|
||||
}
|
||||
|
||||
public HarmonyConfig getConfig() {
|
||||
log.debug("Harmony api config requested.");
|
||||
if(devMode)
|
||||
return devResponse.getConfig();
|
||||
|
||||
return harmonyClient.getConfig();
|
||||
}
|
||||
|
||||
public Activity getCurrentActivity() {
|
||||
log.debug("Harmony api current sctivity requested.");
|
||||
if(devMode)
|
||||
return devResponse.getCurrentActivity();
|
||||
|
||||
return harmonyClient.getCurrentActivity();
|
||||
}
|
||||
|
||||
public Boolean startActivity(RunActivity anActivity) {
|
||||
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls);
|
||||
if (anActivity.isValid()) {
|
||||
try {
|
||||
if (noopCalls || devMode) {
|
||||
if(devMode)
|
||||
{
|
||||
if(anActivity != null)
|
||||
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
||||
}
|
||||
|
||||
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName());
|
||||
}
|
||||
else
|
||||
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.startActivityByName(anActivity.getName());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding activity: " + anActivity.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding activity: " + anActivity.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean pressButton(ButtonPress aDeviceButton) {
|
||||
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls);
|
||||
if (aDeviceButton.isValid()) {
|
||||
try {
|
||||
if (noopCalls || devMode) {
|
||||
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton());
|
||||
}
|
||||
else
|
||||
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
115
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
115
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.IpList;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
|
||||
public class HarmonyHome {
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||
private Map<String, HarmonyServer> hubs;
|
||||
|
||||
public HarmonyHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
hubs = new HashMap<String, HarmonyServer>();
|
||||
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode())
|
||||
return;
|
||||
if(bridgeSettings.isDevMode()) {
|
||||
NamedIP devModeIp = new NamedIP();
|
||||
devModeIp.setIp("10.10.10.10");
|
||||
devModeIp.setName("devMode");
|
||||
List<NamedIP> theList = new ArrayList<NamedIP>();
|
||||
theList.add(devModeIp);
|
||||
IpList thedevList = new IpList();
|
||||
thedevList.setDevices(theList);
|
||||
bridgeSettings.setHarmonyAddress(thedevList);
|
||||
}
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aHub = theList.next();
|
||||
try {
|
||||
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, aHub));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HarmonyHandler getHarmonyHandler(String aName) {
|
||||
HarmonyHandler aHandler = null;
|
||||
if(aName == null || aName.equals("")) {
|
||||
aName = "default";
|
||||
}
|
||||
|
||||
if(hubs.get(aName) == null) {
|
||||
Set<String> keys = hubs.keySet();
|
||||
if(!keys.isEmpty()) {
|
||||
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
||||
}
|
||||
else
|
||||
aHandler = null;
|
||||
}
|
||||
else
|
||||
aHandler = hubs.get(aName).getMyHarmony();
|
||||
return aHandler;
|
||||
}
|
||||
|
||||
public List<HarmonyActivity> getActivities() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||
while(activities.hasNext()) {
|
||||
HarmonyActivity anActivity = new HarmonyActivity();
|
||||
anActivity.setActivity(activities.next());
|
||||
anActivity.setHub(key);
|
||||
activityList.add(anActivity);
|
||||
}
|
||||
}
|
||||
return activityList;
|
||||
}
|
||||
public List<HarmonyActivity> getCurrentActivities() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||
while(activities.hasNext()) {
|
||||
HarmonyActivity anActivity = new HarmonyActivity();
|
||||
anActivity.setActivity(activities.next());
|
||||
anActivity.setHub(key);
|
||||
activityList.add(anActivity);
|
||||
}
|
||||
}
|
||||
return activityList;
|
||||
}
|
||||
public List<HarmonyDevice> getDevices() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||
while(devices.hasNext()) {
|
||||
HarmonyDevice aDevice = new HarmonyDevice();
|
||||
aDevice.setDevice(devices.next());
|
||||
aDevice.setHub(key);
|
||||
deviceList.add(aDevice);
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
84
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
84
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
import net.whistlingfish.harmony.ActivityChangeListener;
|
||||
import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.HarmonyClientModule;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
||||
|
||||
public class HarmonyServer {
|
||||
@Inject
|
||||
private HarmonyClient harmonyClient;
|
||||
|
||||
private HarmonyHandler myHarmony;
|
||||
private DevModeResponse devResponse;
|
||||
private OAReplyProvider dummyProvider;
|
||||
private NamedIP myNameAndIP;
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||
|
||||
public HarmonyServer(NamedIP theHarmonyAddress) {
|
||||
super();
|
||||
myHarmony = null;
|
||||
dummyProvider = null;
|
||||
myNameAndIP = theHarmonyAddress;
|
||||
}
|
||||
|
||||
public static HarmonyServer setup(BridgeSettings bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
|
||||
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode()) {
|
||||
return new HarmonyServer(theHarmonyAddress);
|
||||
}
|
||||
Injector injector = null;
|
||||
if(!bridgeSettings.isDevMode())
|
||||
injector = Guice.createInjector(new HarmonyClientModule());
|
||||
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
||||
if(!bridgeSettings.isDevMode())
|
||||
injector.injectMembers(mainObject);
|
||||
mainObject.execute(bridgeSettings);
|
||||
return mainObject;
|
||||
}
|
||||
|
||||
private void execute(BridgeSettings mySettings) throws Exception {
|
||||
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||
String modeString = "";
|
||||
if(dummyProvider != null)
|
||||
log.debug("something is very wrong as dummyProvider is not null...");
|
||||
if(mySettings.isDevMode())
|
||||
modeString = " (development mode)";
|
||||
else if(noopCalls)
|
||||
modeString = " (no op calls to harmony)";
|
||||
log.info("setup initiated " + modeString + "....");
|
||||
if(mySettings.isDevMode())
|
||||
{
|
||||
harmonyClient = null;
|
||||
devResponse = new DevModeResponse();
|
||||
}
|
||||
else {
|
||||
devResponse = null;
|
||||
harmonyClient.addListener(new ActivityChangeListener() {
|
||||
@Override
|
||||
public void activityStarted(Activity activity) {
|
||||
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||
}
|
||||
});
|
||||
harmonyClient.connect(myNameAndIP.getIp(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||
}
|
||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||
}
|
||||
|
||||
public HarmonyHandler getMyHarmony() {
|
||||
return myHarmony;
|
||||
}
|
||||
}
|
||||
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
public class RunActivity {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Boolean isValid() {
|
||||
if (name != null && !name.isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class VeraInfo {
|
||||
|
||||
public VeraInfo(String addressString, Boolean isValidVera) {
|
||||
super();
|
||||
httpClient = HttpClients.createMinimal();
|
||||
httpClient = HttpClients.createDefault();
|
||||
veraAddressString = addressString;
|
||||
validVera = isValidVera;
|
||||
}
|
||||
|
||||
1
src/main/resources/config.data
Normal file
1
src/main/resources/config.data
Normal file
File diff suppressed because one or more lines are too long
@@ -16,7 +16,7 @@
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="container" ng-controller="VersionController">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
@@ -29,6 +29,7 @@
|
||||
<ul class="nav navbar-nav">
|
||||
<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="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Help</a></li>
|
||||
<li class="dropdown">
|
||||
<a id="dropdownMenu1" href="" class="dropdown-toggle"
|
||||
data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||
@@ -36,7 +37,7 @@
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
|
||||
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
||||
<li><a href="">HA Bridge Version 0.4.10</a></li>
|
||||
<li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -18,6 +18,12 @@ app.config(function ($routeProvider) {
|
||||
}).when('/verascenes', {
|
||||
templateUrl: 'views/verascene.html',
|
||||
controller: 'AddingController'
|
||||
}).when('/harmonydevices', {
|
||||
templateUrl: 'views/harmonydevice.html',
|
||||
controller: 'AddingController'
|
||||
}).when('/harmonyactivities', {
|
||||
templateUrl: 'views/harmonyactivity.html',
|
||||
controller: 'AddingController'
|
||||
}).otherwise({
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
@@ -27,6 +33,8 @@ app.config(function ($routeProvider) {
|
||||
app.run( function (bridgeService) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.updateShowVera();
|
||||
bridgeService.updateShowHarmony();
|
||||
bridgeService.getHABridgeVersion();
|
||||
});
|
||||
|
||||
app.factory('BridgeSettings', function() {
|
||||
@@ -37,9 +45,10 @@ app.factory('BridgeSettings', function() {
|
||||
BridgeSettings.upnpdevicedb = "";
|
||||
BridgeSettings.upnpresponseport = "";
|
||||
BridgeSettings.veraaddress = "";
|
||||
BridgeSettings.harmonyaddress = "";
|
||||
BridgeSettings.upnpstrict = "";
|
||||
BridgeSettings.traceupnp = "";
|
||||
BridgeSettings.vtwocompatibility = "";
|
||||
BridgeSettings.devmode = "";
|
||||
|
||||
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
|
||||
BridgeSettings.upnpconfigaddress = aconfigaddress;
|
||||
@@ -60,14 +69,17 @@ app.factory('BridgeSettings', function() {
|
||||
BridgeSettings.setveraaddress = function(averaaddress){
|
||||
BridgeSettings.veraaddress = averaaddress;
|
||||
};
|
||||
BridgeSettings.setharmonyaddress = function(aharmonyaddress){
|
||||
BridgeSettings.harmonyaddress = aharmonyaddress;
|
||||
};
|
||||
BridgeSettings.setupnpstrict = function(aupnpstrict){
|
||||
BridgeSettings.upnpstrict = aupnpstrict;
|
||||
};
|
||||
BridgeSettings.settraceupnp = function(atraceupnp){
|
||||
BridgeSettings.traceupnp = atraceupnp;
|
||||
};
|
||||
BridgeSettings.setvtwocompatibility = function(avtwocompatibility){
|
||||
BridgeSettings.vtwocompatibility = avtwocompatibility;
|
||||
BridgeSettings.setdevmode = function(adevmode){
|
||||
BridgeSettings.devmode = adevmode;
|
||||
};
|
||||
|
||||
return BridgeSettings;
|
||||
@@ -76,7 +88,7 @@ app.factory('BridgeSettings', function() {
|
||||
app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
var self = this;
|
||||
self.BridgeSettings = BridgeSettings;
|
||||
this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", devices: [], device: [], error: "", showVera: false};
|
||||
this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", huebase: window.location.origin + "/api", devices: [], device: [], error: "", showVera: false, showHarmony: false, habridgeversion: ""};
|
||||
|
||||
this.viewDevices = function () {
|
||||
this.state.error = "";
|
||||
@@ -88,14 +100,55 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
if (error.data) {
|
||||
self.state.error = error.data.message;
|
||||
} else {
|
||||
self.state.error = "If you're not seeing any devices, you may be running into problems with CORS. " +
|
||||
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
|
||||
self.state.error = "Some error occurred.";
|
||||
}
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.getHABridgeVersion = function () {
|
||||
this.state.error = "";
|
||||
return $http.get(this.state.base + "/habridge/version").then(
|
||||
function (response) {
|
||||
self.state.habridgeversion = response.data.version;
|
||||
},
|
||||
function (error) {
|
||||
if (error.data) {
|
||||
self.state.error = error.data.message;
|
||||
} else {
|
||||
self.state.error = "cannot get version";
|
||||
}
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.aContainsB = function (a, b) {
|
||||
return a.indexOf(b) >= 0;
|
||||
}
|
||||
|
||||
this.updateShowVera = function () {
|
||||
if(this.aContainsB(self.BridgeSettings.veraaddress, "1.1.1.1") || self.BridgeSettings.veraaddress == "" || self.BridgeSettings.veraaddress == null)
|
||||
this.state.showVera = false;
|
||||
else
|
||||
this.state.showVera = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateShowHarmony = function () {
|
||||
if(self.BridgeSettings.harmonyaddress.devices) {
|
||||
if(this.aContainsB(self.BridgeSettings.harmonyaddress.devices[0].ip, "1.1.1.1") || self.BridgeSettings.harmonyaddress == "" || self.BridgeSettings.harmonyaddress == null)
|
||||
this.state.showHarmony = false;
|
||||
else
|
||||
this.state.showHarmony = true;
|
||||
}
|
||||
else
|
||||
this.state.showHarmony = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.loadBridgeSettings = function () {
|
||||
this.state.error = "";
|
||||
return $http.get(this.state.upnpbase).then(
|
||||
@@ -105,13 +158,10 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
self.BridgeSettings.setupnpdevicedb(response.data.upnpdevicedb);
|
||||
self.BridgeSettings.setupnpresponseport(response.data.upnpresponseport);
|
||||
self.BridgeSettings.setveraaddress(response.data.veraaddress);
|
||||
self.BridgeSettings.setharmonyaddress(response.data.harmonyaddress);
|
||||
self.BridgeSettings.settraceupnp(response.data.traceupnp);
|
||||
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
|
||||
self.BridgeSettings.setvtwocompatibility(response.data.vtwocompatibility);
|
||||
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
|
||||
self.state.showVera = false;
|
||||
else
|
||||
self.state.showVera = true;
|
||||
self.BridgeSettings.setdevmode(response.data.devmode);
|
||||
},
|
||||
function (error) {
|
||||
if (error.data) {
|
||||
@@ -124,17 +174,9 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
);
|
||||
};
|
||||
|
||||
this.updateShowVera = function () {
|
||||
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
|
||||
this.state.showVera = false;
|
||||
else
|
||||
this.state.showVera = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewVeraDevices = function () {
|
||||
this.state.error = "";
|
||||
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||
if(!this.state.showVera)
|
||||
return;
|
||||
this.state.error = "";
|
||||
return $http.get(this.state.base + "/vera/devices").then(
|
||||
@@ -150,10 +192,10 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
this.viewVeraScenes = function () {
|
||||
this.state.error = "";
|
||||
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||
if(!this.state.showVera)
|
||||
return;
|
||||
return $http.get(this.state.base + "/vera/scenes").then(
|
||||
function (response) {
|
||||
@@ -168,21 +210,70 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||
|
||||
this.viewHarmonyActivities = function () {
|
||||
this.state.error = "";
|
||||
if (id) {
|
||||
var putUrl = this.state.base + "/" + id;
|
||||
if(!this.state.showHarmony)
|
||||
return;
|
||||
return $http.get(this.state.base + "/harmony/activities").then(
|
||||
function (response) {
|
||||
self.state.harmonyactivities = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.data) {
|
||||
$window.alert("Get Harmony Activities Error: " + error.data.message);
|
||||
} else {
|
||||
$window.alert("Get Harmony Activities Error: unknown");
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.viewHarmonyDevices = function () {
|
||||
this.state.error = "";
|
||||
if(!this.state.showHarmony)
|
||||
return;
|
||||
return $http.get(this.state.base + "/harmony/devices").then(
|
||||
function (response) {
|
||||
self.state.harmonydevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.data) {
|
||||
$window.alert("Get Harmony Devices Error: " + error.data.message);
|
||||
} else {
|
||||
$window.alert("Get Harmony Devices Error: unknown");
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.findDeviceByMapId = function(id, target, type) {
|
||||
for(var i = 0; i < this.state.devices.length; i++) {
|
||||
if(this.state.devices[i].mapId == id && this.state.devices[i].mapType == type && this.state.devices[i].targetDevice == target)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.addDevice = function (device) {
|
||||
this.state.error = "";
|
||||
if(device.httpVerb != null && device.httpVerb != "")
|
||||
device.deviceType = "custom";
|
||||
if (device.id) {
|
||||
var putUrl = this.state.base + "/" + device.id;
|
||||
return $http.put(putUrl, {
|
||||
id: id,
|
||||
name: name,
|
||||
deviceType: type,
|
||||
onUrl: onUrl,
|
||||
offUrl: offUrl,
|
||||
httpVerb: httpVerb,
|
||||
contentType: contentType,
|
||||
contentBody: contentBody,
|
||||
contentBodyOff: contentBodyOff
|
||||
id: device.id,
|
||||
name: device.name,
|
||||
mapId: device.mapId,
|
||||
mapType: device.mapType,
|
||||
deviceType: device.deviceType,
|
||||
targetDevice: device.targetDevice,
|
||||
onUrl: device.onUrl,
|
||||
offUrl: device.offUrl,
|
||||
httpVerb: device.httpVerb,
|
||||
contentType: device.contentType,
|
||||
contentBody: device.contentBody,
|
||||
contentBodyOff: device.contentBodyOff
|
||||
}).then(
|
||||
function (response) {
|
||||
self.viewDevices();
|
||||
@@ -195,17 +286,22 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if(type == null || type == "")
|
||||
type = "switch";
|
||||
if(device.deviceType == null || device.deviceType == "")
|
||||
device.deviceType = "custom";
|
||||
if(device.httpVerb != null && device.httpVerb != "")
|
||||
device.deviceType = "custom";
|
||||
return $http.post(this.state.base, {
|
||||
name: name,
|
||||
deviceType: type,
|
||||
onUrl: onUrl,
|
||||
offUrl: offUrl,
|
||||
httpVerb: httpVerb,
|
||||
contentType: contentType,
|
||||
contentBody: contentBody,
|
||||
contentBodyOff: contentBodyOff
|
||||
name: device.name,
|
||||
mapId: device.mapId,
|
||||
mapType: device.mapType,
|
||||
deviceType: device.deviceType,
|
||||
targetDevice: device.targetDevice,
|
||||
onUrl: device.onUrl,
|
||||
offUrl: device.offUrl,
|
||||
httpVerb: device.httpVerb,
|
||||
contentType: device.contentType,
|
||||
contentBody: device.contentBody,
|
||||
contentBodyOff: device.contentBodyOff
|
||||
}).then(
|
||||
function (response) {
|
||||
self.viewDevices();
|
||||
@@ -235,8 +331,40 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
);
|
||||
};
|
||||
|
||||
this.editDevice = function (id, name, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl, httpVerb: httpVerb, contentType: contentType, contentBody: contentBody, contentBodyOff: contentBodyOff};
|
||||
this.deleteDeviceByMapId = function (id, type) {
|
||||
for(var i = 0; i < this.state.devices.length; i++) {
|
||||
if(this.state.devices[i].mapId == id && this.state.devices[i].mapType == type)
|
||||
return self.deleteDevice(this.state.devices[i].id);
|
||||
}
|
||||
};
|
||||
|
||||
this.editDevice = function (device) {
|
||||
self.state.device = device;
|
||||
};
|
||||
|
||||
this.testUrl = function (device, type) {
|
||||
if(type == "on") {
|
||||
$http.put(this.state.huebase + "/test/lights/" + device.id + "/state", "{\"on\":true}").then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.statusText + ", with status: " + error.status + ", Pleae look in your console log.");
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$http.put(this.state.huebase + "/test/lights/" + device.id + "/state", "{\"on\":false}").then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.statusText + ", with status: " + error.status + ", Pleae look in your console log.");
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -246,6 +374,9 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.viewDevices();
|
||||
$scope.bridge = bridgeService.state;
|
||||
bridgeService.updateShowVera();
|
||||
bridgeService.updateShowHarmony();
|
||||
$scope.visible = false;
|
||||
$scope.imgUrl = "glyphicon glyphicon-plus";
|
||||
$scope.predicate = '';
|
||||
$scope.reverse = true;
|
||||
$scope.order = function(predicate) {
|
||||
@@ -256,72 +387,50 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.deleteDevice(device.id);
|
||||
};
|
||||
$scope.testUrl = function (device, type) {
|
||||
if(type == "on") {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.onUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else if(device.httpVerb == "POST")
|
||||
$http.post(device.onUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else
|
||||
window.open(device.onUrl, "_blank");
|
||||
}
|
||||
else {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.offUrl, device.contentBodyOff).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else if(device.httpVerb == "POST")
|
||||
$http.post(device.offUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else
|
||||
window.open(device.offUrl, "_blank");
|
||||
}
|
||||
bridgeService.testUrl(device, type);
|
||||
};
|
||||
$scope.setBridgeUrl = function (url) {
|
||||
bridgeService.state.base = url;
|
||||
bridgeService.viewDevices();
|
||||
};
|
||||
$scope.goBridgeUrl = function (url) {
|
||||
window.open(url, "_blank");
|
||||
};
|
||||
$scope.editDevice = function (device) {
|
||||
bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl, device.httpVerb, device.contentType, device.contentBody, device.contentBodyOff);
|
||||
bridgeService.editDevice(device);
|
||||
$location.path('/editdevice');
|
||||
};
|
||||
$scope.toggle = function () {
|
||||
$scope.visible = !$scope.visible;
|
||||
if($scope.visible)
|
||||
$scope.imgUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('AddingController', function ($scope, $location, $http, bridgeService, BridgeSettings) {
|
||||
|
||||
$scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
|
||||
$scope.device = {id: "", name: "", deviceType: "custom", onUrl: "", offUrl: ""};
|
||||
$scope.vera = {base: "", port: "3480", id: ""};
|
||||
$scope.vera.base = "http://" + BridgeSettings.veraaddress;
|
||||
bridgeService.device = $scope.device;
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
bridgeService.viewHarmonyActivities();
|
||||
bridgeService.viewHarmonyDevices();
|
||||
$scope.bridge = bridgeService.state;
|
||||
bridgeService.updateShowVera();
|
||||
bridgeService.updateShowHarmony();
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.activitiesVisible = false;
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
$scope.buttonsVisible = false;
|
||||
$scope.imgActivitiesUrl = "glyphicon glyphicon-plus";
|
||||
$scope.devicesVisible = false;
|
||||
$scope.imgDevicesUrl = "glyphicon glyphicon-plus";
|
||||
$scope.scenesVisible = false;
|
||||
$scope.imgScenesUrl = "glyphicon glyphicon-plus";
|
||||
$scope.predicate = '';
|
||||
$scope.reverse = true;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -334,6 +443,9 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
if ($scope.vera.base.indexOf("http") < 0) {
|
||||
$scope.vera.base = "http://" + $scope.vera.base;
|
||||
}
|
||||
$scope.device.deviceType = "switch";
|
||||
$scope.device.mapType = "veraDevice";
|
||||
$scope.device.mapId = $scope.vera.id;
|
||||
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||
@@ -354,6 +466,8 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
$scope.vera.base = "http://" + $scope.vera.base;
|
||||
}
|
||||
$scope.device.deviceType = "scene";
|
||||
$scope.device.mapType = "veraScene";
|
||||
$scope.device.mapId = $scope.vera.id;
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||
+ $scope.vera.id;
|
||||
@@ -368,6 +482,8 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
}
|
||||
$scope.device.deviceType = "switch";
|
||||
$scope.device.name = veradevice.name;
|
||||
$scope.device.mapType = "veraDevice";
|
||||
$scope.device.mapId = veradevice.id;
|
||||
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||
@@ -389,6 +505,8 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
}
|
||||
$scope.device.deviceType = "scene";
|
||||
$scope.device.name = verascene.name;
|
||||
$scope.device.mapType = "veraScene";
|
||||
$scope.device.mapId = verascene.id;
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||
+ verascene.id;
|
||||
@@ -397,60 +515,40 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
+ verascene.id;
|
||||
};
|
||||
|
||||
$scope.testUrl = function (url) {
|
||||
if(type == "on") {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.onUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else if(device.httpVerb == "POST")
|
||||
$http.post(device.onUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else
|
||||
window.open(device.onUrl, "_blank");
|
||||
}
|
||||
else {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.offUrl, device.contentBodyOff).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else if(device.httpVerb == "POST")
|
||||
$http.post(device.offUrl, device.contentBody).then(
|
||||
function (response) {
|
||||
$window.alert("Request Exceuted: " + response.statusText);
|
||||
},
|
||||
function (error) {
|
||||
$window.alert("Request Error: " + error.data.message);
|
||||
}
|
||||
);
|
||||
else
|
||||
window.open(device.offUrl, "_blank");
|
||||
}
|
||||
$scope.buildActivityUrls = function (harmonyactivity) {
|
||||
$scope.device.deviceType = "activity";
|
||||
$scope.device.targetDevice = harmonyactivity.hub;
|
||||
$scope.device.name = harmonyactivity.activity.label;
|
||||
$scope.device.mapType = "harmonyActivity";
|
||||
$scope.device.mapId = harmonyactivity.activity.id;
|
||||
$scope.device.onUrl = "{\"name\":\"" + harmonyactivity.activity.id + "\"}";
|
||||
$scope.device.offUrl = "{\"name\":\"-1\"}";
|
||||
};
|
||||
|
||||
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
|
||||
$scope.device.deviceType = "button";
|
||||
$scope.device.targetDevice = harmonydevice.hub;
|
||||
$scope.device.name = harmonydevice.device.label;
|
||||
$scope.device.mapType = "harmonyButton";
|
||||
$scope.device.mapId = harmonydevice.device.id + "-" + onbutton + "-" + offbutton;
|
||||
$scope.device.onUrl = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + onbutton + "\"}";
|
||||
$scope.device.offUrl = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + offbutton + "\"}";
|
||||
};
|
||||
|
||||
$scope.testUrl = function (device, type) {
|
||||
bridgeService.testUrl(device, type);
|
||||
};
|
||||
|
||||
$scope.addDevice = function () {
|
||||
bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl, $scope.device.httpVerb, $scope.device.contentType, $scope.device.contentBody, $scope.device.contentBodyOff).then(
|
||||
bridgeService.addDevice($scope.device).then(
|
||||
function () {
|
||||
$scope.device.id = "";
|
||||
$scope.device.mapType = null;
|
||||
$scope.device.mapId = null;
|
||||
$scope.device.name = "";
|
||||
$scope.device.onUrl = "";
|
||||
$scope.device.deviceType = "switch";
|
||||
$scope.device.deviceType = "custom";
|
||||
$scope.device.targetDevice = null;
|
||||
$scope.device.offUrl = "";
|
||||
$scope.device.httpVerb = null;
|
||||
$scope.device.contentType = null;
|
||||
@@ -462,9 +560,148 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$scope.toggleActivities = function () {
|
||||
$scope.activitiesVisible = !$scope.activitiesVisible;
|
||||
if($scope.activitiesVisible)
|
||||
$scope.imgActivitiesUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgActivitiesUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.toggleButtons = function () {
|
||||
$scope.buttonsVisible = !$scope.buttonsVisible;
|
||||
if($scope.buttonsVisible)
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.toggleDevices = function () {
|
||||
$scope.devicesVisible = !$scope.devicesVisible;
|
||||
if($scope.devicesVisible)
|
||||
$scope.imgDevicesUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgDevicesUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.toggleScenes = function () {
|
||||
$scope.scenesVisible = !$scope.scenesVisible;
|
||||
if($scope.scenesVisible)
|
||||
$scope.imgScenesUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgScenesUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.filter('availableHarmonyActivityId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(!bridgeService.findDeviceByMapId(input[i].activity.id, input[i].hub, "harmonyActivity")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('unavailableHarmonyActivityId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(bridgeService.findDeviceByMapId(input[i].activity.id, input[i].hub, "harmonyActivity")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('availableVeraDeviceId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(!bridgeService.findDeviceByMapId(input[i].id, null, "veraDevice")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('unavailableVeraDeviceId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(bridgeService.findDeviceByMapId(input[i].id, null, "veraDevice")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('availableVeraSceneId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(!bridgeService.findDeviceByMapId(input[i].id, null, "veraScene")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('unavailableVeraSceneId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(bridgeService.findDeviceByMapId(input[i].id, null, "veraScene")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('configuredButtons', function() {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(input[i].mapType == "harmonyButton"){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.controller('ErrorsController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
});
|
||||
|
||||
app.controller('VersionController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
@@ -2,72 +2,11 @@
|
||||
<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 class="panel panel-default bridgeServer">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge settings</h1>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-3 control-label" for="bridge-base">Bridge
|
||||
server</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="bridge-base" class="form-control" type="text"
|
||||
ng-model="bridge.base" placeholder="URL to bridge">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="testUrl(bridge.base)">Go</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Setting</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>upnp.config.address</td>
|
||||
<td>{{BridgeSettings.upnpconfigaddress}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.port</td>
|
||||
<td>{{BridgeSettings.serverport}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.devices.db</td>
|
||||
<td>{{BridgeSettings.upnpdevicedb}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.response.port</td>
|
||||
<td>{{BridgeSettings.upnpresponseport}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vera.address</td>
|
||||
<td>{{BridgeSettings.veraaddress}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.strict</td>
|
||||
<td>{{BridgeSettings.upnpstrict}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>trace.upnp</td>
|
||||
<td>{{BridgeSettings.traceupnp}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vtwo.compatibility</td>
|
||||
<td>{{BridgeSettings.vtwocompatibility}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-controller="ErrorsController">
|
||||
<div ng-if="bridge.error"
|
||||
@@ -98,6 +37,9 @@
|
||||
<th>
|
||||
<a href="" ng-click="order('deviceType')">Type</a>
|
||||
<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>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -105,6 +47,7 @@
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.deviceType}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>
|
||||
<button class="btn btn-info" type="submit"
|
||||
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||
@@ -117,4 +60,72 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge settings <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||
server</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="bridge-base" class="form-control" type="text"
|
||||
ng-model="bridge.base" placeholder="URL to bridge">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="goBridgeUrl(bridge.base)">Go</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Setting</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>upnp.config.address</td>
|
||||
<td>{{BridgeSettings.upnpconfigaddress}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.port</td>
|
||||
<td>{{BridgeSettings.serverport}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.devices.db</td>
|
||||
<td>{{BridgeSettings.upnpdevicedb}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.response.port</td>
|
||||
<td>{{BridgeSettings.upnpresponseport}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vera.address</td>
|
||||
<td>{{BridgeSettings.veraaddress}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>harmony.address</td>
|
||||
<td>{{BridgeSettings.harmonyaddress}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upnp.strict</td>
|
||||
<td>{{BridgeSettings.upnpstrict}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>trace.upnp</td>
|
||||
<td>{{BridgeSettings.traceupnp}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>dev.mode</td>
|
||||
<td>{{BridgeSettings.devmode}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
<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"><a href="#/editor">Manual Add</a></li>
|
||||
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a new device</h2>
|
||||
<h2 class="panel-title">Edit a device</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
@@ -24,6 +26,40 @@
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||
Update 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>
|
||||
</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>
|
||||
</select>
|
||||
</div>
|
||||
</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 class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
@@ -33,9 +69,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</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 class="form-group">
|
||||
@@ -47,9 +80,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</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 class="form-group">
|
||||
@@ -67,7 +97,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||
</label>
|
||||
@@ -92,7 +122,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body On</label>
|
||||
@@ -104,7 +134,7 @@
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body-off">Content Body Off</label>
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
<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="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default bridgeServer" ng-if="bridge.showVera">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
||||
</div>
|
||||
@@ -96,9 +98,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</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 class="form-group">
|
||||
@@ -110,9 +109,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</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 class="form-group">
|
||||
@@ -130,7 +126,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||
</label>
|
||||
@@ -155,7 +151,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body On</label>
|
||||
@@ -167,7 +163,7 @@
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body-off">Content Body Off</label>
|
||||
|
||||
127
src/main/resources/public/views/harmonyactivity.html
Normal file
127
src/main/resources/public/views/harmonyactivity.html
Normal file
@@ -0,0 +1,127 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Configuration</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Harmony Activity List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">You can select a Harmony Activity and generate
|
||||
the add activity box selections automatically.</p>
|
||||
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="" ng-click="order('label')">Name</a>
|
||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<a href="" ng-click="order('id')">Id</a>
|
||||
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<a href="" ng-click="order('hub')">Hub</a>
|
||||
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId | orderBy:predicate:reverse">
|
||||
<td>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||
Activity URLs</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Activities <a ng-click="toggleActivities()"><span class={{imgActivitiesUrl}} aria-hidden="true"></a></h2>
|
||||
</div>
|
||||
<ul ng-if="activitiesVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="" ng-click="order('label')">Name</a>
|
||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<a href="" ng-click="order('id')">Id</a>
|
||||
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<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>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Harmony Activity</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal" ng-submit="addDevice()">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||
Add Activity</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-off-url">Off URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
150
src/main/resources/public/views/harmonydevice.html
Normal file
150
src/main/resources/public/views/harmonydevice.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Configuration</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Harmony Device List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">You can select a Harmony Device and Button and generate
|
||||
the add button box selections automatically.</p>
|
||||
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="" ng-click="order('label')">Name</a>
|
||||
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<a href="" ng-click="order('id')">Id</a>
|
||||
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>
|
||||
<a href="" ng-click="order('hub')">Hub</a>
|
||||
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
|
||||
</th>
|
||||
<th>On Button</th>
|
||||
<th>Off Button</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
|
||||
<td>{{harmonydevice.device.label}}</td>
|
||||
<td>{{harmonydevice.device.id}}</td>
|
||||
<td>{{harmonydevice.hub}}</td>
|
||||
<td>
|
||||
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
||||
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}">
|
||||
<option ng-repeat="funcon in ctrlon.function">{{funcon.name}}</option>
|
||||
</optgroup >
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
||||
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}">
|
||||
<option ng-repeat="funcoff in ctrloff.function">{{funcoff.name}}</option>
|
||||
</optgroup >
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Generate
|
||||
Button URLs</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
<div 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>
|
||||
<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>{{device.name}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>{{device.mapId}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Harmony Button</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal" ng-submit="addDevice()">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
||||
Add Button</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-off-url">Off URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -2,6 +2,8 @@
|
||||
<li role="presentation"><a href="#">Configuration</a></li>
|
||||
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li 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>
|
||||
|
||||
@@ -43,7 +45,7 @@
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</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>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
@@ -57,6 +59,46 @@
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Vera Devices <a ng-click="toggleDevices()"><span class={{imgDevicesUrl}} aria-hidden="true"></a></h2>
|
||||
</div>
|
||||
<ul ng-if="devicesVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<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>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId | orderBy:predicate:reverse">
|
||||
<td>{{veradevice.name}}</td>
|
||||
<td>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
<td>{{veradevice.room}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(veradevice.id, 'veraDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
@@ -85,10 +127,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</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 class="form-group">
|
||||
<div class="row">
|
||||
@@ -99,10 +137,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</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>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<li role="presentation"><a href="#">Configuration</a></li>
|
||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li 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>
|
||||
|
||||
@@ -12,7 +14,7 @@
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">You can select a Vera scene and generate
|
||||
the add device box selections automatically.</p>
|
||||
the add scene box selections automatically.</p>
|
||||
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
@@ -32,7 +34,7 @@
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="verascene in bridge.verascenes | orderBy:predicate:reverse">
|
||||
<tr ng-repeat="verascene in bridge.verascenes | availableVeraSceneId | orderBy:predicate:reverse">
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
@@ -45,6 +47,41 @@
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Vera Scenes <a ng-click="toggleScenes()"><span class={{imgScenesUrl}} aria-hidden="true"></a></h2>
|
||||
</div>
|
||||
<ul ng-if="scenesVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<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>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId | orderBy:predicate:reverse">
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(verascene.id, 'veraScene')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel-heading">
|
||||
@@ -73,10 +110,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</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 class="form-group">
|
||||
<div class="row">
|
||||
@@ -87,10 +120,6 @@
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</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>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
3
src/main/resources/version.properties
Normal file
3
src/main/resources/version.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
version=${project.version}
|
||||
groupId=${project.groupId}
|
||||
artifactId=${project.artifactId}
|
||||
Reference in New Issue
Block a user