Compare commits

..

72 Commits

Author SHA1 Message Date
Admin
314ae58ebd This closes #8, closes #9, closes #10 and closes #11.
Finished device, scene and activity tracking, updated upnp handling,
updated HUE API config handling and test on and off calls.
2015-11-18 16:31:11 -06:00
Admin
d8b6232ac1 First draft and start of tracking for scenes, devices, activities.
Implemented Harmony activity list so far.
2015-11-17 16:40:24 -06:00
Admin
41e22ee64d Refactor TestUrl call in apps.js. Updated UI to only have test buttons
after a device is added.
2015-11-16 16:38:29 -06:00
Admin
be2fbcd4cb Update script for test on and off. Incorrect body sent for off commands
error return was interpretted incorrectly.
2015-11-16 14:53:42 -06:00
Admin
14e7f37522 Updated HUE API for generic config requests. Updated config parameters
to be more real.
2015-11-13 16:17:49 -06:00
Admin
e3f5946c9d Updated handling to be CORS compatible. 2015-11-13 11:40:13 -06:00
Admin
12eab16f21 updated Readme and enhance emulator logging code. 2015-11-13 11:26:19 -06:00
Admin
3df68047a9 Updated handling of dimming/brightness request. This could be buggy if
the echo changed to not send an on command when changing dimming. The
HUE state change API is not consistent for brightness handling.
2015-11-13 10:57:18 -06:00
Admin
0dd652f82a Updated device return for HUE emulation based on new information of LUX
bulb handling in the API from the Philips dev info.
2015-11-12 16:31:01 -06:00
Admin
53af1a4dfd Final tweaks to the order of sections in the readme 2015-11-11 15:24:17 -06:00
Admin
816a0025b1 Finished updating upnp for the readme 2015-11-11 15:16:42 -06:00
Admin
405562809a finished adding harmony items to readme 2015-11-11 14:39:13 -06:00
Admin
4c87c6fce8 Update readme some more. 2015-11-11 13:29:06 -06:00
Admin
2fd0f7748b Some more readme updates. 2015-11-11 13:19:50 -06:00
Admin
ed5f3b4b3c More readme updates. 2015-11-11 12:43:38 -06:00
Admin
aad09b7527 More updates to readme 2015-11-11 11:28:41 -06:00
Admin
0ae66da085 Continuation of readme updating. 2015-11-11 11:26:42 -06:00
Admin
d344b764da Updated HUE REst descriptions. 2015-11-10 16:48:30 -06:00
Admin
c85b67fb9f Next update for HUE API description 2015-11-10 16:25:16 -06:00
Admin
a23d662444 Adding supported HUE API calls descriptions. 2015-11-10 13:57:01 -06:00
Admin
4b98f799c2 Updated vera returns for scened and devices. 2015-11-10 11:51:21 -06:00
Admin
acba2b5cae Another config rest api clarification. 2015-11-10 11:45:40 -06:00
Admin
4dc818296a Updated Configuration REST API commands. 2015-11-10 11:40:41 -06:00
Admin
40123ed858 Updating document for REST usage. 2015-11-09 16:47:38 -06:00
Admin
718ba5a5c2 Updated build in pom.xml to include classes that were removed for
minimize. This required a dummy clas setup as well in the Harmony
Server.
2015-11-04 11:00:46 -06:00
Admin
2e6944d840 Missed new java class in release. 2015-11-03 15:26:56 -06:00
Admin
e29f12905d Finalized handling for barmony. Added a version call for use in api.
Updated version handling in the pom.xml and code. Removed
vtwocompatibility as it should not be used.
2015-11-03 15:16:01 -06:00
Admin
408b79d5d8 Finished coding need to test. 2015-11-02 16:46:48 -06:00
Admin
bf5ad2e23c Adding button selection control for harmony. in progress.... 2015-10-30 16:30:30 -05:00
Admin
59f1db285d Updating pom configuration for adding harmony control. 2015-10-29 15:59:00 -05:00
Admin
203ed0b5d3 Updated pom to use new harmony client version. 2015-10-28 16:42:23 -05:00
Admin
b443d16a11 First Beta of Harmony configuration for testing. 2015-10-27 16:39:13 -05:00
Admin
295b1e1a30 Adding Harmony Hub Control directly into the Bridge. First iteration
updates the ui harness. Also, updated settings in the configuration
page.
2015-10-26 16:35:51 -05:00
Admin
c872f3543d Updated Hue Device emulation to be Lux bulbs as most things this bridge
will emulate will not be color friendly....
2015-10-23 16:16:18 -05:00
Admin
23f2d2716d Update Readme.md, typo with bracket placement. 2015-10-13 16:36:53 -05:00
Admin
7c1d6e40b8 Updated math to use Math.round to help get better values. Updated code
for determining if Vera is available so as to not show those screens.
Updated file handling as there were issues due to no checks for file
handling, this will improve for windows.
2015-10-13 16:30:45 -05:00
Admin
c5fbd5d1f0 Updated math variable execution to use net.java.dev.eval package. Safer
and more robust than using JavaScript Engine Eval. Also, added checks if
a default vera address is uses , "1.1.1.1", that we ignore the vera
helpers to not throw errors.
2015-10-12 16:34:21 -05:00
Admin
aebde7ee48 Updated the bridge to handle a new dimming and value control context,
$intensity.mat{(X*1)} for custom calculations. Also, added helpers for
generating URLS on the value contexts.
2015-10-09 14:28:05 -05:00
Admin
c8fb93eeb6 Add testing and error pop ups where needed. 2015-10-05 16:19:09 -05:00
Admin
1602ed004a Updated test methods for special PUT/POST calls. Cleaned up device.db
file write to not keep junk around.
2015-10-05 15:50:46 -05:00
Admin
7514e36edb Updated bridge to be robust on put/post calls and testing. HAd to add a
body for off types.
2015-10-02 16:35:17 -05:00
Admin
2789d8c180 Cleanup code for variable usage. Remvoed dummy test classes. 2015-09-29 08:48:27 -05:00
Admin
af1777aeb3 Updated UI header menu to not switch page to Home everytime. 2015-09-18 10:12:15 -05:00
Admin
fc2d587e1a update project synchronization settings. 2015-09-14 09:10:21 -05:00
Admin
416b4d3fda Updated logging for upnp listener and description service. Added method
in huemulator for "/*" which was present in the armzilla version for the
Harmony Hub. Updated the readme.
2015-09-11 16:01:38 -05:00
Admin
9666273840 Fixed issue with not adding device by checking for an httpVerb always. 2015-09-10 16:38:36 -05:00
Admin
774bc8a36b Update upnp listener module to even be less strict in normal mode as I
have found instances of devices that do not follow the pure upnp
standard. Updated README as it was wrong for the upnp.device.db...it had
an s after device. updated the code to return back to config after
adding or updating a device.
2015-09-10 16:08:29 -05:00
Admin
74d4548beb Fixed saving of updated device context when special commands are used.
Updated create user in hue emulator to handle no device tpye or usernmae
given. Fixed parameter settings as they were incorrect. Updated config
display to show new parameters.
2015-09-03 11:44:26 -05:00
Admin
eecf0f9875 ADded more for editing special get/put/post and started addimg more to
bridge settings in UI.
2015-09-02 16:42:40 -05:00
Admin
ed96b5ad81 another readme update 2015-09-02 13:27:30 -05:00
Admin
9f7d3ea331 update Readme 2015-09-02 13:08:27 -05:00
Admin
68de92bb74 Updtated bridge to be able to emulate the armzilla upnp responses.
Adding optional field edits - in progress.
2015-09-02 13:06:59 -05:00
Admin
392a46c3d8 uodate readme again 2015-09-01 14:08:49 -05:00
Admin
568569248a update readme 2015-09-01 14:04:40 -05:00
Admin
d61d10b5b6 Added settings for strict upnp mode of checking ig it is a request for a
hue or not before responding.
Updated Readme
2015-09-01 13:59:35 -05:00
Admin
7294dbf175 Added the Post Put capabilities for the http eecution. cleaned up css
for list ordering. Cleaned up device management calls.
2015-09-01 13:40:53 -05:00
Admin
6c99358f95 Updated upnp response listener code. Updated hue api. Updated input
areas for urls to be textareas to handle long strings. Added sorting to
all lists.
2015-08-31 16:44:38 -05:00
Admin
eee0394f20 updated upnp discovery calls to be more like the hue. 2015-08-28 15:56:36 -05:00
Admin
d87f3bc541 Fix mapping for scene room mapping as well. doh! 2015-08-27 11:47:00 -05:00
Admin
e38374f749 Fixes bwssytems/ha-bridge#1 2015-08-27 10:04:08 -05:00
Admin
937fb5d32d Final fix for resolving room mapping. Also applied this fix to category
mappign in SDATA as well.
2015-08-27 08:44:09 -05:00
Admin
bd60d63d0f Fix issue with devices with no rooms or categories. 2015-08-26 16:52:44 -05:00
Admin
439b081bd5 Updated vera info class logging calls to be debug only. 2015-08-26 11:48:51 -05:00
Admin
41f68f58b0 Updated Hue description response emulation. Updated the management of
devices in the map. Updated logging information to be less in normal
mode.
2015-08-26 11:26:49 -05:00
Admin
fa15cf3952 update upnp description.xml response to come from root instead of
/upnp.....
2015-08-25 16:42:30 -05:00
Admin
3ea7f2903f commit for any latent changes. 2015-08-25 10:19:02 -05:00
Admin
7746938c62 Updated upnp discovery logic to only respond to the echo request for a
upnp device and updated hue response when getting lights to be more
accurate with the hue.
2015-08-21 16:06:06 -05:00
Admin
96074628fb Merge remote-tracking branch 'origin/master' 2015-08-21 08:56:05 -05:00
Admin
9dc8d8f8bc Updated call for hue user create/addition call. Updated upnp response
variables.
2015-08-20 16:49:12 -05:00
Admin
8de39a8bee Work on naming scenes 2015-08-19 16:43:46 -05:00
Admin
626f0641cc Changed navigation to use nav tab pills look. 2015-08-19 15:17:24 -05:00
Admin
020da99e1c Update .gitignore attributes for eclipse 2015-08-18 14:18:24 -05:00
42 changed files with 3297 additions and 560 deletions

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ buildNumber.properties
data data
.idea .idea
/target/ /target/
/.settings/
/start.bat
/.classpath

23
.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ha-bridge</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

674
README.md

File diff suppressed because one or more lines are too long

95
pom.xml
View File

@@ -5,11 +5,11 @@
<groupId>com.bwssystems.HABridge</groupId> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>0.3.0</version> <version>1.1.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera, using lightweight frameworks</description> <description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub, using lightweight frameworks</description>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
@@ -17,7 +17,19 @@
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
</properties> </properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>harmony-java-client</artifactId>
<version>1.0.8</version>
</dependency>
<dependency> <dependency>
<groupId>com.sparkjava</groupId> <groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId> <artifactId>spark-core</artifactId>
@@ -53,9 +65,40 @@
<artifactId>json-io</artifactId> <artifactId>json-io</artifactId>
<version>4.1.6</version> <version>4.1.6</version>
</dependency> </dependency>
<dependency>
<groupId>net.java.dev.eval</groupId>
<artifactId>eval</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0-beta4</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.0.7</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>version.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -78,24 +121,42 @@
<exclude>META-INF/*.RSA</exclude> <exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/*.txt</exclude> <exclude>META-INF/*.txt</exclude>
<exclude>META-INF/maven/**</exclude> <exclude>META-INF/maven/**</exclude>
<exclude>META-INF/services/**</exclude>
<exclude>META-INF/DEPENDENCIES</exclude>
<exclude>about_files/**</exclude> <exclude>about_files/**</exclude>
<exclude>*.properties</exclude>
</excludes> </excludes>
</filter> </filter>
<filter> <filter>
<artifact>org.slf4j:*</artifact> <artifact>*:*</artifact>
<includes> </filter>
<include>**</include> <filter>
</includes> <artifact>org.slf4j:*</artifact>
</filter> <includes>
<filter> <include>**</include>
<artifact>commons-logging:commons-logging</artifact> </includes>
<includes> </filter>
<include>**</include> <filter>
</includes> <artifact>commons-logging:commons-logging</artifact>
</filter> <includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>xpp3:xpp3</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>org.igniterealtime.smack:*</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>com.github.bwssytems:harmony-java-client</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters> </filters>
<transformers> <transformers>
<transformer <transformer

View File

@@ -6,6 +6,12 @@ public class BridgeSettings {
private String upnpresponseport; private String upnpresponseport;
private String upnpdevicedb; private String upnpdevicedb;
private String veraaddress; private String veraaddress;
private String harmonyaddress;
private String harmonyuser;
private String harmonypwd;
private boolean upnpstrict;
private boolean traceupnp;
private boolean devmode;
public String getUpnpConfigAddress() { public String getUpnpConfigAddress() {
return upnpconfigaddress; return upnpconfigaddress;
@@ -37,6 +43,54 @@ public class BridgeSettings {
public void setVeraAddress(String veraAddress) { public void setVeraAddress(String veraAddress) {
this.veraaddress = veraAddress; this.veraaddress = veraAddress;
} }
public String getHarmonyAddress() {
return harmonyaddress;
}
public void setHarmonyAddress(String harmonyaddress) {
this.harmonyaddress = harmonyaddress;
}
public String getHarmonyUser() {
return harmonyuser;
}
public void setHarmonyUser(String harmonyuser) {
this.harmonyuser = harmonyuser;
}
public String getHarmonyPwd() {
return harmonypwd;
}
public void setHarmonyPwd(String harmonypwd) {
this.harmonypwd = harmonypwd;
}
public boolean isUpnpStrict() {
return upnpstrict;
}
public void setUpnpStrict(boolean upnpStrict) {
this.upnpstrict = upnpStrict;
}
public boolean isTraceupnp() {
return traceupnp;
}
public void setTraceupnp(boolean traceupnp) {
this.traceupnp = traceupnp;
}
public boolean isDevMode() {
return devmode;
}
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() {
if(this.harmonyaddress.contains(Configuration.DEFAULT_HARMONY_ADDRESS))
return false;
if(this.harmonypwd == null || this.harmonypwd == "")
return false;
if(this.harmonyuser == null || this.harmonyuser == "")
return false;
return true;
}
} }

View File

@@ -0,0 +1,11 @@
package com.bwssystems.HABridge;
public class Configuration {
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
public final static String UPNP_RESPONSE_PORT = "50000";
public final static String DEFAULT_VERA_ADDRESS = "1.1.1.1";
public final static String DEFAULT_HARMONY_ADDRESS = "1.1.1.1";
public final static String DEFAULT_HARMONY_USER = "";
public final static String DEFAULT_HARMONY_PWD = "";
public final static String DFAULT_WEB_PORT = "8080";
}

View File

@@ -12,7 +12,7 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
import com.bwssystems.HABridge.hue.HueMulator; import com.bwssystems.HABridge.hue.HueMulator;
import com.bwssystems.HABridge.upnp.UpnpListener; import com.bwssystems.HABridge.upnp.UpnpListener;
import com.bwssystems.HABridge.upnp.UpnpSettingsResource; import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
import com.bwssystems.vera.VeraInfo; import com.bwssystems.harmony.HarmonyServer;
public class HABridge { public class HABridge {
@@ -34,13 +34,18 @@ public class HABridge {
public static void main(String[] args) { public static void main(String[] args) {
Logger log = LoggerFactory.getLogger(HABridge.class); Logger log = LoggerFactory.getLogger(HABridge.class);
DeviceResource theResources; DeviceResource theResources;
HarmonyServer myHarmonyServer;
HueMulator theHueMulator; HueMulator theHueMulator;
UpnpSettingsResource theSettingResponder; UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener; UpnpListener theUpnpListener;
InetAddress address; InetAddress address;
String addressString; String addressString;
BridgeSettings bridgeSettings; BridgeSettings bridgeSettings;
Version theVersion;
theVersion = new Version();
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting setup....");
//get ip address for upnp requests //get ip address for upnp requests
try { try {
address = InetAddress.getLocalHost(); address = InetAddress.getLocalHost();
@@ -51,31 +56,44 @@ public class HABridge {
} }
bridgeSettings = new BridgeSettings(); bridgeSettings = new BridgeSettings();
bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString)); bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", "data/device.db")); bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000")); bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100")); bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
bridgeSettings.setHarmonyAddress(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS));
bridgeSettings.setHarmonyUser(System.getProperty("harmony.user", Configuration.DEFAULT_HARMONY_USER));
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_HARMONY_PWD));
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
bridgeSettings.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "false")));
// sparkjava config directive to set ip address for the web server to listen on // sparkjava config directive to set ip address for the web server to listen on
// ipAddress("0.0.0.0"); // not used // ipAddress("0.0.0.0"); // not used
// sparkjava config directive to set port for the web server to listen on // sparkjava config directive to set port for the web server to listen on
bridgeSettings.setServerPort(System.getProperty("server.port", "8080"));
port(Integer.valueOf(bridgeSettings.getServerPort())); port(Integer.valueOf(bridgeSettings.getServerPort()));
// sparkjava config directive to set html static file location for Jetty // sparkjava config directive to set html static file location for Jetty
staticFileLocation("/public"); staticFileLocation("/public");
log.info("Starting setup...."); //setup the harmony connection if available
try {
myHarmonyServer = HarmonyServer.setup(bridgeSettings);
} catch (Exception e) {
log.error("Cannot get harmony client setup, Exiting with message: " + e.getMessage(), e);
return;
}
// setup the class to handle the resource setup rest api // setup the class to handle the resource setup rest api
theResources = new DeviceResource(bridgeSettings); theResources = new DeviceResource(bridgeSettings, theVersion, myHarmonyServer.getMyHarmony());
// setup the class to handle the hue emulator rest api // setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(theResources.getDeviceRepository()); theHueMulator = new HueMulator(theResources.getDeviceRepository(), myHarmonyServer.getMyHarmony());
theHueMulator.setupServer();
// setup the class to handle the upnp response rest api // setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings); theSettingResponder = new UpnpSettingsResource(bridgeSettings);
theSettingResponder.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete // wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization(); awaitInitialization();
// start the upnp ssdp discovery listener // start the upnp ssdp discovery listener
theUpnpListener = new UpnpListener(bridgeSettings); theUpnpListener = new UpnpListener(bridgeSettings);
log.info("Done setup, application to run....");
theUpnpListener.startListening(); theUpnpListener.startListening();
} }
} }

View 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;
}
}

View File

@@ -1,43 +0,0 @@
package com.bwssystems.HABridge.api;
/**
* Created by arm on 4/13/15.
*/
public class Device {
private String name;
private String deviceType;
private String offUrl;
private String onUrl;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getOffUrl() {
return offUrl;
}
public void setOffUrl(String offUrl) {
this.offUrl = offUrl;
}
public String getOnUrl() {
return onUrl;
}
public void setOnUrl(String onUrl) {
this.onUrl = onUrl;
}
}

View File

@@ -0,0 +1,19 @@
package com.bwssystems.HABridge.api;
public class UserCreateRequest {
private String devicetype;
private String username;
public String getDevicetype() {
return devicetype;
}
public void setDevicetype(String devicetype) {
this.devicetype = devicetype;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}

View File

@@ -1,10 +1,5 @@
package com.bwssystems.HABridge.api.hue; package com.bwssystems.HABridge.api.hue;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** /**
* Created by arm on 4/14/15. * Created by arm on 4/14/15.
*/ */
@@ -16,7 +11,6 @@ public class DeviceResponse {
private String manufacturername; private String manufacturername;
private String uniqueid; private String uniqueid;
private String swversion; private String swversion;
private Map<String, String> pointsymbol;
public DeviceState getState() { public DeviceState getState() {
return state; return state;
@@ -74,24 +68,6 @@ public class DeviceResponse {
this.swversion = swversion; this.swversion = swversion;
} }
public Map<String, String> getPointsymbol() {
Map<String, String> dummyValue = new HashMap<>();
dummyValue.put("1", "none");
dummyValue.put("2", "none");
dummyValue.put("3", "none");
dummyValue.put("4", "none");
dummyValue.put("5", "none");
dummyValue.put("6", "none");
dummyValue.put("7", "none");
dummyValue.put("8", "none");
return dummyValue;
}
public void setPointsymbol(Map<String, String> pointsymbol) {
this.pointsymbol = pointsymbol;
}
public static DeviceResponse createResponse(String name, String id){ public static DeviceResponse createResponse(String name, String id){
DeviceState deviceState = new DeviceState(); DeviceState deviceState = new DeviceState();
DeviceResponse response = new DeviceResponse(); DeviceResponse response = new DeviceResponse();
@@ -101,21 +77,13 @@ public class DeviceResponse {
deviceState.setEffect("none"); deviceState.setEffect("none");
deviceState.setAlert("none"); deviceState.setAlert("none");
deviceState.setBri(254); deviceState.setBri(254);
deviceState.setHue(15823);
deviceState.setSat(88);
deviceState.setCt(313);
List<Double> xv = new LinkedList<>();
xv.add(Double.valueOf("0.4255"));
xv.add(Double.valueOf("0.3998"));
deviceState.setXy(xv);
deviceState.setColormode("ct");
response.setName(name); response.setName(name);
response.setUniqueid(id); response.setUniqueid(id);
response.setManufacturername("Philips"); response.setManufacturername("Philips");
response.setType("Extended color light"); response.setType("Dimmable light");
response.setModelid("LCT001"); response.setModelid("LWB004");
response.setSwversion("65003148"); response.setSwversion("66012040");
return response; return response;
} }

View File

@@ -1,6 +1,5 @@
package com.bwssystems.HABridge.api.hue; package com.bwssystems.HABridge.api.hue;
import java.util.List;
/** /**
* Created by arm on 4/14/15. * Created by arm on 4/14/15.
@@ -8,14 +7,9 @@ import java.util.List;
public class DeviceState { public class DeviceState {
private boolean on; private boolean on;
private int bri = 255; private int bri = 255;
private int hue;
private int sat;
private String effect; private String effect;
private int ct;
private String alert; private String alert;
private String colormode;
private boolean reachable; private boolean reachable;
private List<Double> xy;
public boolean isOn() { public boolean isOn() {
return on; return on;
@@ -33,22 +27,6 @@ public class DeviceState {
this.bri = bri; this.bri = bri;
} }
public int getHue() {
return hue;
}
public void setHue(int hue) {
this.hue = hue;
}
public int getSat() {
return sat;
}
public void setSat(int sat) {
this.sat = sat;
}
public String getEffect() { public String getEffect() {
return effect; return effect;
} }
@@ -57,14 +35,6 @@ public class DeviceState {
this.effect = effect; this.effect = effect;
} }
public int getCt() {
return ct;
}
public void setCt(int ct) {
this.ct = ct;
}
public String getAlert() { public String getAlert() {
return alert; return alert;
} }
@@ -73,14 +43,6 @@ public class DeviceState {
this.alert = alert; this.alert = alert;
} }
public String getColormode() {
return colormode;
}
public void setColormode(String colormode) {
this.colormode = colormode;
}
public boolean isReachable() { public boolean isReachable() {
return reachable; return reachable;
} }
@@ -89,14 +51,6 @@ public class DeviceState {
this.reachable = reachable; this.reachable = reachable;
} }
public List<Double> getXy() {
return xy;
}
public void setXy(List<Double> xy) {
this.xy = xy;
}
@Override @Override
public String toString() { public String toString() {
return "DeviceState{" + return "DeviceState{" +

View File

@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.api.hue; package com.bwssystems.HABridge.api.hue;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.DeviceResponse;
@@ -9,12 +10,46 @@ import com.bwssystems.HABridge.api.hue.DeviceResponse;
*/ */
public class HueApiResponse { public class HueApiResponse {
private Map<String, DeviceResponse> lights; private Map<String, DeviceResponse> lights;
private Map<String, String> scenes;
private Map<String, String> groups;
private HueConfig config;
public Map<String, DeviceResponse> getLights() { public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
super();
this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid));
this.setGroups(new HashMap<>());
this.setScenes(new HashMap<>());
}
public Map<String, DeviceResponse> getLights() {
return lights; return lights;
} }
public void setLights(Map<String, DeviceResponse> lights) { public void setLights(Map<String, DeviceResponse> lights) {
this.lights = lights; this.lights = lights;
} }
public Map<String, String> getScenes() {
return scenes;
}
public void setScenes(Map<String, String> scenes) {
this.scenes = scenes;
}
public Map<String, String> getGroups() {
return groups;
}
public void setGroups(Map<String, String> groups) {
this.groups = groups;
}
public HueConfig getConfig() {
return config;
}
public void setConfig(HueConfig config) {
this.config = config;
}
} }

View File

@@ -0,0 +1,234 @@
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
{
private Boolean portalservices;
private String gateway;
private String mac;
private String swversion;
private String apiversion;
private Boolean linkbutton;
private String ipaddress;
private Integer proxyport;
private Swupdate swupdate;
private String netmask;
private String name;
private Boolean dhcp;
private String UTC;
private String proxyaddress;
private String localtime;
private String timezone;
private String zigbeechannel;
private Map<String, WhitelistEntry> whitelist;
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
HueConfig aConfig = new HueConfig();
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(ipaddress);
aConfig.setSwversion("01005215");
aConfig.setLinkbutton(false);
aConfig.setIpaddress(ipaddress);
aConfig.setProxyport(0);
aConfig.setSwupdate(Swupdate.createSwupdate());
aConfig.setNetmask("255.255.255.0");
aConfig.setName(name);
aConfig.setDhcp(true);
aConfig.setUtc(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");
}
return sb.toString();
}
public Boolean getPortalservices() {
return portalservices;
}
public void setPortalservices(Boolean portalservices) {
this.portalservices = portalservices;
}
public String getGateway() {
return gateway;
}
public void setGateway(String gateway) {
this.gateway = gateway;
}
public String getMac() {
return mac;
}
public void setMac(String mac) {
this.mac = mac;
}
public String getSwversion() {
return swversion;
}
public void setSwversion(String swversion) {
this.swversion = swversion;
}
public Boolean getLinkbutton() {
return linkbutton;
}
public void setLinkbutton(Boolean linkbutton) {
this.linkbutton = linkbutton;
}
public String getIpaddress() {
return ipaddress;
}
public void setIpaddress(String ipaddress) {
this.ipaddress = ipaddress;
}
public Integer getProxyport() {
return proxyport;
}
public void setProxyport(Integer proxyport) {
this.proxyport = proxyport;
}
public Swupdate getSwupdate() {
return swupdate;
}
public void setSwupdate(Swupdate swupdate) {
this.swupdate = swupdate;
}
public String getNetmask() {
return netmask;
}
public void setNetmask(String netmask) {
this.netmask = netmask;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getDhcp() {
return dhcp;
}
public void setDhcp(Boolean dhcp) {
this.dhcp = dhcp;
}
public String getUtc() {
return UTC;
}
public void setUtc(String utc) {
this.UTC = utc;
}
public String getProxyaddress() {
return proxyaddress;
}
public void setProxyaddress(String proxyaddress) {
this.proxyaddress = proxyaddress;
}
public Map<String, WhitelistEntry> getWhitelist() {
return whitelist;
}
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
this.whitelist = whitelist;
}
public String getApiversion() {
return apiversion;
}
public void setApiversion(String apiversion) {
this.apiversion = apiversion;
}
public String getLocaltime() {
return localtime;
}
public void setLocaltime(String localtime) {
this.localtime = localtime;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public String getZigbeechannel() {
return zigbeechannel;
}
public void setZigbeechannel(String zigbeechannel) {
this.zigbeechannel = zigbeechannel;
}
}

View File

@@ -0,0 +1,52 @@
package com.bwssystems.HABridge.api.hue;
public class Swupdate
{
private String text;
private Boolean notify;
private Integer updatestate;
private String url;
public static Swupdate createSwupdate() {
Swupdate aSwupdate = new Swupdate();
aSwupdate.setNotify(false);
aSwupdate.setText("");
aSwupdate.setUpdatestate(0);
aSwupdate.setUrl("");
return aSwupdate;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Boolean getNotify() {
return notify;
}
public void setNotify(Boolean notify) {
this.notify = notify;
}
public Integer getUpdatestate() {
return updatestate;
}
public void setUpdatestate(Integer updatestate) {
this.updatestate = updatestate;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

View File

@@ -0,0 +1,49 @@
package com.bwssystems.HABridge.api.hue;
import java.text.SimpleDateFormat;
import java.util.Date;
public class WhitelistEntry
{
private String lastUseDate;
private String createDate;
private String name;
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
public static WhitelistEntry createEntry(String devicetype) {
WhitelistEntry anEntry = new WhitelistEntry();
anEntry.setName(devicetype);
anEntry.setCreateDate(getCurrentDate());
anEntry.setLastUseDate(getCurrentDate());
return anEntry;
}
public static String getCurrentDate() {
return dateFormat.format(new Date());
}
public String getLastUseDate() {
return lastUseDate;
}
public void setLastUseDate(String lastUseDate) {
this.lastUseDate = lastUseDate;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -5,9 +5,15 @@ package com.bwssystems.HABridge.dao;
public class DeviceDescriptor{ public class DeviceDescriptor{
private String id; private String id;
private String name; private String name;
private String mapId;
private String mapType;
private String deviceType; private String deviceType;
private String offUrl; private String offUrl;
private String onUrl; private String onUrl;
private String httpVerb;
private String contentType;
private String contentBody;
private String contentBodyOff;
public String getName() { public String getName() {
return name; return name;
@@ -17,7 +23,23 @@ public class DeviceDescriptor{
this.name = name; this.name = name;
} }
public String getDeviceType() { public String getMapId() {
return mapId;
}
public void setMapId(String mapId) {
this.mapId = mapId;
}
public String getMapType() {
return mapType;
}
public void setMapType(String mapType) {
this.mapType = mapType;
}
public String getDeviceType() {
return deviceType; return deviceType;
} }
@@ -48,4 +70,38 @@ public class DeviceDescriptor{
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public String getHttpVerb() {
return httpVerb;
}
public void setHttpVerb(String httpVerb) {
this.httpVerb = httpVerb;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getContentBody() {
return contentBody;
}
public void setContentBody(String contentBody) {
this.contentBody = contentBody;
}
public String getContentBodyOff() {
return contentBodyOff;
}
public void setContentBodyOff(String contentBodyOff) {
this.contentBodyOff = contentBodyOff;
}
} }

View File

@@ -3,6 +3,7 @@ package com.bwssystems.HABridge.dao;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@@ -43,7 +44,7 @@ public class DeviceRepository {
DeviceDescriptor theDevice = null; DeviceDescriptor theDevice = null;
while (theIterator.hasNext()) { while (theIterator.hasNext()) {
theDevice = theIterator.next(); theDevice = theIterator.next();
put(Integer.parseInt(theDevice.getId()), theDevice); put(theDevice.getId(), theDevice);
} }
} }
} }
@@ -62,20 +63,20 @@ public class DeviceRepository {
return devices.get(id); return devices.get(id);
} }
private void put(int id, DeviceDescriptor aDescriptor) { private void put(String id, DeviceDescriptor aDescriptor) {
devices.put(String.valueOf(id), aDescriptor); devices.put(id, aDescriptor);
} }
public void save(DeviceDescriptor aDescriptor) { public void save(DeviceDescriptor aDescriptor) {
int id = random.nextInt(Integer.MAX_VALUE);
if(aDescriptor.getId() != null) if(aDescriptor.getId() != null)
devices.remove(aDescriptor.getId()); devices.remove(aDescriptor.getId());
else else
aDescriptor.setId(String.valueOf(id)); aDescriptor.setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
put(id, aDescriptor); put(aDescriptor.getId(), aDescriptor);
JsonTransformer aRenderer = new JsonTransformer(); JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(findAll()); String jsonValue = aRenderer.render(findAll());
repositoryWriter(jsonValue, repositoryPath); repositoryWriter(jsonValue, repositoryPath);
log.debug("Save device: " + aDescriptor.getName());
} }
public String delete(DeviceDescriptor aDescriptor) { public String delete(DeviceDescriptor aDescriptor) {
@@ -106,7 +107,14 @@ public class DeviceRepository {
} }
try { try {
Path target = null;
if(Files.exists(filePath)) {
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE); Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
if(target != null)
Files.delete(target);
} catch (IOException e) { } catch (IOException e) {
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e); log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
} }
@@ -116,7 +124,7 @@ public class DeviceRepository {
String content = null; String content = null;
if(Files.notExists(filePath) || !Files.isReadable(filePath)){ if(Files.notExists(filePath) || !Files.isReadable(filePath)){
log.error("Error reading the file: " + filePath + " - Does not exist or is not readable. "); log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
return null; return null;
} }
@@ -170,6 +178,12 @@ public class DeviceRepository {
} else if (name.equals("name")) { } else if (name.equals("name")) {
deviceEntry.setName(reader.nextString()); deviceEntry.setName(reader.nextString());
log.debug("Read a Device - device json name: " + deviceEntry.getName()); log.debug("Read a Device - device json name: " + deviceEntry.getName());
} else if (name.equals("mapType")) {
deviceEntry.setMapType(reader.nextString());
log.debug("Read a Device - device json name: " + deviceEntry.getMapType());
} else if (name.equals("mapId")) {
deviceEntry.setMapId(reader.nextString());
log.debug("Read a Device - device json name: " + deviceEntry.getMapId());
} else if (name.equals("deviceType")) { } else if (name.equals("deviceType")) {
deviceEntry.setDeviceType(reader.nextString()); deviceEntry.setDeviceType(reader.nextString());
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType()); log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
@@ -179,6 +193,18 @@ public class DeviceRepository {
} else if (name.equals("onUrl")) { } else if (name.equals("onUrl")) {
deviceEntry.setOnUrl(reader.nextString()); deviceEntry.setOnUrl(reader.nextString());
log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl()); log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl());
} else if (name.equals("httpVerb")) {
deviceEntry.setHttpVerb(reader.nextString());
log.debug("Read a Device - device json httpVerb:" + deviceEntry.getHttpVerb());
} else if (name.equals("contentType")) {
deviceEntry.setContentType(reader.nextString());
log.debug("Read a Device - device json contentType:" + deviceEntry.getContentType());
} else if (name.equals("contentBody")) {
deviceEntry.setContentBody(reader.nextString());
log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody());
} else if (name.equals("contentBodyOff")) {
deviceEntry.setContentBodyOff(reader.nextString());
log.debug("Read a Device - device json contentBodyOff:" + deviceEntry.getContentBodyOff());
} else { } else {
reader.skipValue(); reader.skipValue();
} }

View File

@@ -1,19 +1,26 @@
package com.bwssystems.HABridge.devicemanagmeent; package com.bwssystems.HABridge.devicemanagmeent;
import static spark.Spark.get; import static spark.Spark.get;
import static spark.Spark.options;
import static spark.Spark.post; import static spark.Spark.post;
import static spark.Spark.put; import static spark.Spark.put;
import static spark.Spark.delete; import static spark.Spark.delete;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.apache.http.HttpStatus;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings; import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.JsonTransformer; import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.Version;
import com.bwssystems.HABridge.dao.DeviceDescriptor; import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository; import com.bwssystems.HABridge.dao.DeviceRepository;
import com.bwssystems.harmony.HarmonyHandler;
import com.bwssystems.luupRequests.Sdata; import com.bwssystems.luupRequests.Sdata;
import com.bwssystems.vera.VeraInfo; import com.bwssystems.vera.VeraInfo;
import com.google.gson.Gson; import com.google.gson.Gson;
@@ -27,12 +34,16 @@ public class DeviceResource {
private DeviceRepository deviceRepository; private DeviceRepository deviceRepository;
private VeraInfo veraInfo; private VeraInfo veraInfo;
private Version version;
private HarmonyHandler myHarmonyHandler;
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHandler myHarmony) {
public DeviceResource(BridgeSettings theSettings) {
super(); super();
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb()); this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
veraInfo = new VeraInfo(theSettings.getVeraAddress()); this.veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
this.myHarmonyHandler = myHarmony;
this.version = theVersion;
setupEndpoints(); setupEndpoints();
} }
@@ -41,41 +52,73 @@ public class DeviceResource {
} }
private void setupEndpoints() { private void setupEndpoints() {
log.debug("Setting up endpoints"); log.info("HABridge device management service started.... ");
// http://ip_address:port/api/devices CORS request
options(API_CONTEXT, "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
post(API_CONTEXT, "application/json", (request, response) -> { post(API_CONTEXT, "application/json", (request, response) -> {
log.debug("Create a Device - request body: " + request.body()); log.debug("Create a Device - request body: " + request.body());
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class); DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
DeviceDescriptor deviceEntry = new DeviceDescriptor(); if(device.getContentBody() != null ) {
deviceEntry.setName(device.getName()); if (device.getContentType() == null || device.getHttpVerb() == null || !supportedVerbs.contains(device.getHttpVerb().toLowerCase())) {
log.debug("Create a Device - device json name: " + deviceEntry.getName()); device = null;
deviceEntry.setDeviceType(device.getDeviceType()); response.status(HttpStatus.SC_BAD_REQUEST);
log.debug("Create a Device - device json type:" + deviceEntry.getDeviceType()); log.debug("Bad http verb in create a Device: " + request.body());
deviceEntry.setOnUrl(device.getOnUrl()); return device;
log.debug("Create a Device - device json on URL:" + deviceEntry.getOnUrl()); }
deviceEntry.setOffUrl(device.getOffUrl()); }
log.debug("Create a Device - device json off URL:" + deviceEntry.getOffUrl());
deviceRepository.save(deviceEntry); deviceRepository.save(device);
log.debug("Created a Device"); log.debug("Created a Device: " + request.body());
response.status(201); response.header("Access-Control-Allow-Origin", request.headers("Origin"));
return deviceEntry; response.status(HttpStatus.SC_CREATED);
return device;
}, new JsonTransformer()); }, new JsonTransformer());
// http://ip_address:port/api/devices/:id CORS request
options(API_CONTEXT + "/:id", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
put (API_CONTEXT + "/:id", "application/json", (request, response) -> { put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Saved a Device"); log.debug("Edit a Device - request body: " + request.body());
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class); DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id")); DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
if(deviceEntry == null){ if(deviceEntry == null){
return null; log.debug("Could not save an edited Device Id: " + request.params(":id"));
response.status(HttpStatus.SC_BAD_REQUEST);
} }
else
{
log.debug("Saving an edited Device: " + deviceEntry.getName());
deviceEntry.setName(device.getName()); deviceEntry.setName(device.getName());
deviceEntry.setDeviceType(device.getDeviceType()); if (device.getDeviceType() != null)
deviceEntry.setOnUrl(device.getOnUrl()); deviceEntry.setDeviceType(device.getDeviceType());
deviceEntry.setOffUrl(device.getOffUrl()); deviceEntry.setMapId(device.getMapId());
deviceEntry.setMapType(device.getMapType());
deviceEntry.setOnUrl(device.getOnUrl());
deviceEntry.setOffUrl(device.getOffUrl());
deviceEntry.setHttpVerb(device.getHttpVerb());
deviceEntry.setContentType(device.getContentType());
deviceEntry.setContentBody(device.getContentBody());
deviceEntry.setContentBodyOff(device.getContentBodyOff());
deviceRepository.save(deviceEntry); deviceRepository.save(deviceEntry);
response.status(HttpStatus.SC_OK);
}
return deviceEntry; return deviceEntry;
}, new JsonTransformer()); }, new JsonTransformer());
@@ -85,34 +128,49 @@ public class DeviceResource {
JsonTransformer aRenderer = new JsonTransformer(); JsonTransformer aRenderer = new JsonTransformer();
String theStream = aRenderer.render(deviceList); String theStream = aRenderer.render(deviceList);
log.debug("The Device List: " + theStream); log.debug("The Device List: " + theStream);
response.status(HttpStatus.SC_OK);
return deviceList; return deviceList;
}, new JsonTransformer()); }, new JsonTransformer());
get (API_CONTEXT + "/:id", "application/json", (request, response) -> { get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Get a device"); log.debug("Get a device");
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id")); DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
if(descriptor == null){ if(descriptor == null)
return null; response.status(HttpStatus.SC_NOT_FOUND);
} else
response.status(HttpStatus.SC_OK);
return descriptor; return descriptor;
}, new JsonTransformer()); }, new JsonTransformer());
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> { delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Delete a device"); String anId = request.params(":id");
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id")); log.debug("Delete a device: " + anId);
if(deleted == null){ DeviceDescriptor deleted = deviceRepository.findOne(anId);
return null; if(deleted == null)
response.status(HttpStatus.SC_NOT_FOUND);
else
{
deviceRepository.delete(deleted);
response.status(HttpStatus.SC_OK);
} }
deviceRepository.delete(deleted);
return null; return null;
}, new JsonTransformer()); }, new JsonTransformer());
get (API_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
log.debug("Get HA Bridge version: v" + version.getVersion());
response.status(HttpStatus.SC_OK);
return "{\"version\":\"" + version.getVersion() + "\"}";
});
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> { get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
log.debug("Get vera devices"); log.debug("Get vera devices");
Sdata sData = veraInfo.getSdata(); Sdata sData = veraInfo.getSdata();
if(sData == null){ if(sData == null){
return null; response.status(HttpStatus.SC_NOT_FOUND);
return null;
} }
response.status(HttpStatus.SC_OK);
return sData.getDevices(); return sData.getDevices();
}, new JsonTransformer()); }, new JsonTransformer());
@@ -120,10 +178,42 @@ public class DeviceResource {
log.debug("Get vera scenes"); log.debug("Get vera scenes");
Sdata sData = veraInfo.getSdata(); Sdata sData = veraInfo.getSdata();
if(sData == null){ if(sData == null){
response.status(HttpStatus.SC_NOT_FOUND);
return null; return null;
} }
response.status(HttpStatus.SC_OK);
return sData.getScenes(); return sData.getScenes();
}, new JsonTransformer()); }, new JsonTransformer());
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
log.debug("Get harmony activities");
if(myHarmonyHandler == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getActivities();
}, new JsonTransformer());
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
log.debug("Get harmony current activity");
if(myHarmonyHandler == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getCurrentActivity();
}, new JsonTransformer());
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
log.debug("Get harmony devices");
if(myHarmonyHandler == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getDevices();
}, new JsonTransformer());
} }
} }

View File

@@ -1,20 +1,34 @@
package com.bwssystems.HABridge.hue; package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.JsonTransformer; import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.api.UserCreateRequest;
import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.api.hue.DeviceState; import com.bwssystems.HABridge.api.hue.DeviceState;
import com.bwssystems.HABridge.api.hue.HueApiResponse; import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.bwssystems.HABridge.dao.*; import com.bwssystems.HABridge.dao.*;
import com.bwssystems.harmony.ButtonPress;
import com.bwssystems.harmony.HarmonyHandler;
import com.bwssystems.harmony.RunActivity;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import net.java.dev.eval.Expression;
import static spark.Spark.get; import static spark.Spark.get;
import static spark.Spark.options;
import static spark.Spark.post; import static spark.Spark.post;
import static spark.Spark.put; import static spark.Spark.put;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
@@ -22,6 +36,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -34,52 +49,145 @@ public class HueMulator {
private static final Logger log = LoggerFactory.getLogger(HueMulator.class); private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}"; private static final String INTENSITY_PERCENT = "${intensity.percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}"; private static final String INTENSITY_BYTE = "${intensity.byte}";
private static final String INTENSITY_MATH = "${intensity.math(";
private static final String INTENSITY_MATH_VALUE = "X";
private static final String INTENSITY_MATH_CLOSE = ")}";
private static final String HUE_CONTEXT = "/api"; private static final String HUE_CONTEXT = "/api";
private DeviceRepository repository; private DeviceRepository repository;
private HarmonyHandler myHarmony;
private HttpClient httpClient; private HttpClient httpClient;
private ObjectMapper mapper; private ObjectMapper mapper;
public HueMulator(DeviceRepository aDeviceRepository){ public HueMulator(DeviceRepository aDeviceRepository, HarmonyHandler theHandler){
httpClient = HttpClients.createMinimal(); httpClient = HttpClients.createDefault();
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
repository = aDeviceRepository; repository = aDeviceRepository;
setupEndpoints(); myHarmony = theHandler;
} }
// This function sets up the sparkjava rest calls for the hue api // This function sets up the sparkjava rest calls for the hue api
private void setupEndpoints() { public void setupServer() {
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured log.info("Hue emulator service started....");
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> { get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
String userId = request.params(":userid"); String userId = request.params(":userid");
log.info("hue lights list requested: " + userId + " from " + request.ip()); log.debug("hue lights list requested: " + userId + " from " + request.ip());
List<DeviceDescriptor> deviceList = repository.findByDeviceType("switch"); List<DeviceDescriptor> deviceList = repository.findAll();
JsonTransformer aRenderer = new JsonTransformer(); Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
String theStream = aRenderer.render(deviceList);
log.debug("The Device List: " + theStream);
Map<String, String> deviceResponseMap = new HashMap<>();
for (DeviceDescriptor device : deviceList) { for (DeviceDescriptor device : deviceList) {
deviceResponseMap.put(device.getId(), device.getName()); DeviceResponse deviceResponse = DeviceResponse.createResponse(device.getName(), device.getId());
deviceResponseMap.put(device.getId(), deviceResponse);
} }
response.status(200); response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
return deviceResponseMap; return deviceResponseMap;
} , new JsonTransformer()); } , new JsonTransformer());
// http://ip_address:port/api/* returns json object for a test call // http://ip_address:port/api CORS request
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> { options(HUE_CONTEXT, "application/json", (request, response) -> {
response.status(200); response.status(HttpStatus.SC_OK);
return "[{\"success\":{\"username\":\"lights\"}}]"; 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;
log.debug("hue api user create requested: " + request.body() + " from " + request.ip());
if(request.body() != null && !request.body().isEmpty()) {
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
newUser = aNewUser.getUsername();
aDeviceType = aNewUser.getDevicetype();
}
if(newUser == null)
newUser = "lightssystem";
if(aDeviceType == null)
aDeviceType = "<not given>";
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
response.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 list of names of lights // 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(request.body() != null && !request.body().isEmpty()) {
aNewUser = new Gson().fromJson(request.body(), UserCreateRequest.class);
newUser = aNewUser.getUsername();
aDeviceType = aNewUser.getDevicetype();
}
if(newUser == null)
newUser = "lightssystem";
if(aDeviceType == null)
aDeviceType = "<not given>";
log.debug("HH trace: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
response.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/config returns json objects for the config when no user is given
get(HUE_CONTEXT + "/config", "application/json", (request, response) -> {
String userId = request.params(":userid");
log.debug("hue api config requested: " + userId + " from " + request.ip());
HueApiResponse apiResponse = new HueApiResponse("Philips hue", request.ip(), "My App", userId);
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;
});
// 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");
log.debug("hue api config requested: " + userId + " from " + request.ip());
HueApiResponse apiResponse = new HueApiResponse("Philips hue", request.ip(), "My App", userId);
response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
return apiResponse.getConfig();
}, new JsonTransformer());
// http://ip_address:port/api/{userId} returns json objects for the full state
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> { get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
String userId = request.params(":userid"); String userId = request.params(":userid");
log.info("hue api root requested: " + userId + " from " + request.ip()); log.debug("hue api full state requested: " + userId + " from " + request.ip());
List<DeviceDescriptor> descriptorList = repository.findByDeviceType("switch"); List<DeviceDescriptor> descriptorList = repository.findAll();
if (descriptorList == null) { if (descriptorList == null) {
response.status(404); response.status(HttpStatus.SC_NOT_FOUND);
return null; return null;
} }
Map<String, DeviceResponse> deviceList = new HashMap<>(); Map<String, DeviceResponse> deviceList = new HashMap<>();
@@ -89,32 +197,43 @@ public class HueMulator {
deviceList.put(descriptor.getId(), deviceResponse); deviceList.put(descriptor.getId(), deviceResponse);
} }
); );
HueApiResponse apiResponse = new HueApiResponse(); HueApiResponse apiResponse = new HueApiResponse("Philips hue", request.ip(), "My App", userId);
apiResponse.setLights(deviceList); apiResponse.setLights(deviceList);
response.status(200); response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
return apiResponse; return apiResponse;
}, new JsonTransformer()); }, new JsonTransformer());
// http://ip_address:port/api/{userId}/lights/{lightId} returns json object for a given light // http://ip_address:port/api/{userId}/lights/{lightId} returns json object for a given light
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> { get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
String userId = request.params(":userid"); String userId = request.params(":userid");
String lightId = request.params(":id"); String lightId = request.params(":id");
log.info("hue light requested: " + lightId + "for user: " + userId + " from " + request.ip()); log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + request.ip());
DeviceDescriptor device = repository.findOne(lightId); DeviceDescriptor device = repository.findOne(lightId);
if (device == null) { if (device == null) {
response.status(404); response.status(HttpStatus.SC_NOT_FOUND);
return null; return null;
} else { } else {
log.info("found device named: " + device.getName()); log.debug("found device named: " + device.getName());
} }
DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId()); DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId());
response.status(200); response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
return lightResponse; return lightResponse;
}, new JsonTransformer()); }, new JsonTransformer());
// http://ip_address:port/api/{userId}/lights/{lightId}/state uses json object to set the lights state // http://ip_address:port/api/:userid/lights/:id/state CORS request
options(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/api/{userId}/lights/{lightId}/state uses json object to set the lights state
put(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> { put(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
/** /**
* strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though * strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
@@ -122,69 +241,147 @@ public class HueMulator {
*/ */
String userId = request.params(":userid"); String userId = request.params(":userid");
String lightId = request.params(":id"); String lightId = request.params(":id");
log.info("hue state change requested: " + userId + " from " + request.ip()); log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
log.info("hue stage change body: " + request.body() );
DeviceState state = null; DeviceState state = null;
try { try {
state = mapper.readValue(request.body(), DeviceState.class); state = mapper.readValue(request.body(), DeviceState.class);
} catch (IOException e) { } catch (IOException e) {
log.info("object mapper barfed on input", e); log.error("Object mapper barfed on input of body.", e);
response.status(400); response.status(HttpStatus.SC_BAD_REQUEST);
return null; return null;
} }
DeviceDescriptor device = repository.findOne(lightId); DeviceDescriptor device = repository.findOne(lightId);
if (device == null) { if (device == null) {
response.status(404); response.status(HttpStatus.SC_NOT_FOUND);
log.error("Could not find devcie: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
return null; return null;
} }
String responseString; String responseString =null;
String url; String url = null;
if (state.isOn()) { if (state.isOn()) {
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]"; responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}";
url = device.getOnUrl(); url = device.getOnUrl();
} else { } else if (request.body().contains("false")) {
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]"; responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}";
url = device.getOffUrl(); url = device.getOffUrl();
} }
/* light weight templating here, was going to use free marker but it was a bit too if(request.body().contains("bri"))
* heavy for what we were trying to do. {
* if(url == null)
* currently provides only two variables: {
* intensity.byte : 0-255 brightness. this is raw from the echo url = device.getOnUrl();
* intensity.percent : 0-100, adjusted for the vera responseString = "[";
*/ }
if(url.contains(INTENSITY_BYTE)){ else
String intensityByte = String.valueOf(state.getBri()); responseString = responseString + ",";
url = url.replace(INTENSITY_BYTE, intensityByte);
}else if(url.contains(INTENSITY_PERCENT)){ responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
int percentBrightness = (int) Math.round(state.getBri()/255.0*100); }
String intensityPercent = String.valueOf(percentBrightness); else
url = url.replace(INTENSITY_PERCENT, intensityPercent); responseString = responseString + "]";
if(device.getDeviceType().toLowerCase().contains("activity"))
{
log.debug("executing activity to Harmony: " + url);
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
myHarmony.startActivity(anActivity);
}
else if(device.getDeviceType().toLowerCase().contains("button"))
{
log.debug("executing button press to Harmony: " + url);
ButtonPress aDeviceButton = new Gson().fromJson(url, ButtonPress.class);
myHarmony.pressButton(aDeviceButton);
}
else
{
log.debug("executing activity to Http " + (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)) {
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
log.error("Error on calling url to change device state: " + url);
return null;
}
} }
//make call response.header("Access-Control-Allow-Origin", request.headers("Origin"));
if(!doHttpGETRequest(url)){ response.type("application/json; charset=utf-8");
response.status(503); response.status(HttpStatus.SC_OK);
return null;
}
response.status(200);
return responseString; return responseString;
}); });
} }
/* light weight templating here, was going to use free marker but it was a bit too
* heavy for what we were trying to do.
*
* currently provides:
* intensity.byte : 0-255 brightness. this is raw from the echo
* intensity.percent : 0-100, adjusted for the vera
* intensity.math(X*1) : where X is the value from the interface call and can use net.java.dev.eval math
*/
protected String replaceIntensityValue(String request, int intensity){
if(request == null){
return "";
}
if(request.contains(INTENSITY_BYTE)){
String intensityByte = String.valueOf(intensity);
request = request.replace(INTENSITY_BYTE, intensityByte);
}else if(request.contains(INTENSITY_PERCENT)){
int percentBrightness = (int) Math.round(intensity/255.0*100);
String intensityPercent = String.valueOf(percentBrightness);
request = request.replace(INTENSITY_PERCENT, intensityPercent);
} else if(request.contains(INTENSITY_MATH)){
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
try {
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: " + String.valueOf(intensity));
Expression exp = new Expression(mathDescriptor);
BigDecimal result = exp.eval(variables);
Integer endResult = Math.round(result.floatValue());
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
} catch (Exception e) {
log.error("Could not execute Math: " + mathDescriptor, e);
} }
return request;
}
// This function executes the url from the device repository against the vera // This function executes the url from the device repository against the vera
protected boolean doHttpGETRequest(String url) { protected boolean doHttpRequest(String url, String httpVerb, String contentType, String body) {
log.info("calling GET on URL: " + url); HttpUriRequest request = null;
HttpGet httpGet = new HttpGet(url); if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
request = new HttpGet(url);
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
HttpPost postRequest = new HttpPost(url);
ContentType parsedContentType = ContentType.parse(contentType);
StringEntity requestBody = new StringEntity(body, parsedContentType);
postRequest.setEntity(requestBody);
request = postRequest;
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
HttpPut putRequest = new HttpPut(url);
ContentType parsedContentType = ContentType.parse(contentType);
StringEntity requestBody = new StringEntity(body, parsedContentType);
putRequest.setEntity(requestBody);
request = putRequest;
}
log.debug("Making outbound call in doHttpRequest: " + request);
try { try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(request);
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
log.info("GET on URL responded: " + response.getStatusLine().getStatusCode()); log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){ if(response.getStatusLine().getStatusCode() == 200){
return true; return true;
} }

View File

@@ -23,15 +23,21 @@ public class UpnpListener {
private String responseAddress; private String responseAddress;
private boolean strict;
private boolean traceupnp;
public UpnpListener(BridgeSettings theSettings) { public UpnpListener(BridgeSettings theSettings) {
super(); super();
upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort()); upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort());
httpServerPort = Integer.valueOf(theSettings.getServerPort()); httpServerPort = Integer.valueOf(theSettings.getServerPort());
responseAddress = theSettings.getUpnpConfigAddress(); responseAddress = theSettings.getUpnpConfigAddress();
strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp();
} }
public void startListening(){ public void startListening(){
log.info("Starting UPNP Discovery Listener"); log.info("UPNP Discovery Listener starting....");
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort); try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) { MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
@@ -46,7 +52,10 @@ public class UpnpListener {
while (addrs.hasMoreElements()) { while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement(); InetAddress addr = addrs.nextElement();
log.debug(name + " ... has addr " + addr); if(traceupnp)
log.info("Traceupnp: " + name + " ... has addr " + addr);
else
log.debug(name + " ... has addr " + addr);
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) { if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
IPsPerNic++; IPsPerNic++;
} }
@@ -54,23 +63,26 @@ public class UpnpListener {
log.debug("Checking " + name + " to our interface set"); log.debug("Checking " + name + " to our interface set");
if (IPsPerNic > 0) { if (IPsPerNic > 0) {
upnpMulticastSocket.joinGroup(socketAddress, xface); upnpMulticastSocket.joinGroup(socketAddress, xface);
log.debug("Adding " + name + " to our interface set"); if(traceupnp)
log.info("Traceupnp: Adding " + name + " to our interface set");
else
log.debug("Adding " + name + " to our interface set");
} }
} }
log.info("UPNP Discovery Listener running and ready....");
while(true){ //trigger shutdown here while(true){ //trigger shutdown here
byte[] buf = new byte[1024]; byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length); DatagramPacket packet = new DatagramPacket(buf, buf.length);
upnpMulticastSocket.receive(packet); upnpMulticastSocket.receive(packet);
String packetString = new String(packet.getData()); if(isSSDPDiscovery(packet)){
if(isSSDPDiscovery(packetString)){
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort()); sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
} }
} }
} catch (IOException e) { } catch (IOException e) {
log.error("UpnpListener encountered an error. Shutting down", e); log.error("UpnpListener encountered an error opening sockets. Shutting down", e);
} }
log.info("UPNP Discovery Listener Stopped"); log.info("UPNP Discovery Listener Stopped");
@@ -78,33 +90,54 @@ public class UpnpListener {
} }
/** /**
* very naive ssdp discovery packet detection * ssdp discovery packet detection
* @param body
* @return
*/ */
protected boolean isSSDPDiscovery(String body){ protected boolean isSSDPDiscovery(DatagramPacket packet){
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){ //Only respond to discover request for strict upnp form
return true; String packetString = new String(packet.getData());
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")){
if(traceupnp) {
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message.");
}
else {
log.debug("Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
log.debug("Found message to be an M-SEARCH message.");
}
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);
return true;
}
else if (!strict)
{
if(traceupnp)
log.info("Traceupnp: 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);
return false; return false;
} }
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" + String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" + "CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" + "EXT:\r\n" +
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" + "LOCATION: http://%s:%s/description.xml\r\n" +
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
"01-NLS: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n"; "USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException { protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString()); String discoveryResponse = null;
log.debug("sndUpnpResponse: " + discoveryResponse); discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
if(traceupnp)
log.info("Traceupnp: sendUpnpResponse: " + discoveryResponse);
else
log.debug("sendUpnpResponse: " + discoveryResponse);
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort); DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
socket.send(response); socket.send(response);
} }
protected String getRandomUUIDString(){
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
}
} }

View File

@@ -16,7 +16,9 @@ public class UpnpSettingsResource {
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class); private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
private String hueTemplate = "<?xml version=\"1.0\"?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n" private BridgeSettings theSettings;
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n" + "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string + "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n" "<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
@@ -25,8 +27,8 @@ public class UpnpSettingsResource {
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n" + "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n"
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n" + "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n"
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n" + "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
+ "<modelURL>http://www.bwssystems.com/ha-bridge</modelURL>\n" + "<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n"
+ "<serialNumber>01189998819991197253</serialNumber>\n" + "<serialNumber>0017880ae670</serialNumber>\n"
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n" + "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n" + "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n" + "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
@@ -40,26 +42,45 @@ public class UpnpSettingsResource {
public UpnpSettingsResource(BridgeSettings theSettings) { public UpnpSettingsResource(BridgeSettings theSettings) {
super(); super();
setupListener(theSettings); this.theSettings = theSettings;
} }
private void setupListener (BridgeSettings theSettings) { public void setupServer() {
// http://ip_address:port/upnp/:id/setup.xml which returns the xml configuration for the location of the hue emulator log.info("Hue description service started....");
get(UPNP_CONTEXT + "/:id/setup.xml", "application/xml", (request, response) -> { // http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
log.info("upnp device settings requested: " + request.params(":id") + " from " + request.ip()); get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
else
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
String portNumber = Integer.toString(request.port()); String portNumber = Integer.toString(request.port());
String filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress()); String filledTemplate = null;
log.debug("upnp device settings response: " + filledTemplate); filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
response.status(201); if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings response: " + filledTemplate);
else
log.debug("upnp device settings response: " + filledTemplate);
// response.header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
// response.header("Pragma", "no-cache");
// response.header("Expires", "Mon, 1 Aug 2011 09:00:00 GMT");
// response.header("Connection", "close"); // Not sure if the server will actually close the connections by just setting the header
// response.header("Access-Control-Max-Age", "0");
// response.header("Access-Control-Allow-Origin", "*");
// response.header("Access-Control-Allow-Credentials", "true");
// response.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
// response.header("Access-Control-Allow-Headers", "Content-Type");
// response.header("Content-Type", "application/xml; charset=utf-8");
response.type("application/xml; charset=utf-8");
response.status(200);
return filledTemplate; return filledTemplate;
} ); } );
// http://ip_address:port/upnp/settings which returns the bridge configuration settings // http://ip_address:port/upnp/settings which returns the bridge configuration settings
get(UPNP_CONTEXT + "/settings", "application/xml", (request, response) -> { get(UPNP_CONTEXT + "/settings", "application/json", (request, response) -> {
log.debug("bridge settings requested from " + request.ip()); log.debug("bridge settings requested from " + request.ip());
response.status(201); response.status(200);
return theSettings; return theSettings;
}, new JsonTransformer()); }, new JsonTransformer());

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -0,0 +1,81 @@
package com.bwssystems.harmony;
import static java.lang.String.format;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.google.inject.Guice;
import com.google.inject.Injector;
import net.whistlingfish.harmony.ActivityChangeListener;
import net.whistlingfish.harmony.HarmonyClient;
import net.whistlingfish.harmony.HarmonyClientModule;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.protocol.OAReplyProvider;
public class HarmonyServer {
@Inject
private HarmonyClient harmonyClient;
private HarmonyHandler myHarmony;
private DevModeResponse devResponse;
private OAReplyProvider dummyProvider;
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
public HarmonyServer() {
super();
myHarmony = null;
dummyProvider = null;
}
public static HarmonyServer setup(BridgeSettings bridgeSettings) throws Exception {
if(!bridgeSettings.isValidHarmony()) {
return new HarmonyServer();
}
Injector injector = null;
if(!bridgeSettings.isDevMode())
injector = Guice.createInjector(new HarmonyClientModule());
HarmonyServer mainObject = new HarmonyServer();
if(!bridgeSettings.isDevMode())
injector.injectMembers(mainObject);
mainObject.execute(bridgeSettings);
return mainObject;
}
private void execute(BridgeSettings mySettings) throws Exception {
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
String modeString = "";
if(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(mySettings.getHarmonyAddress(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
}
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
}
public HarmonyHandler getMyHarmony() {
return myHarmony;
}
}

View 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;
}
}

View File

@@ -26,14 +26,19 @@ public class VeraInfo {
private HttpClient httpClient; private HttpClient httpClient;
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json"; private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
private String veraAddressString; private String veraAddressString;
private Boolean validVera;
public VeraInfo(String addressString) { public VeraInfo(String addressString, Boolean isValidVera) {
super(); super();
httpClient = HttpClients.createMinimal(); httpClient = HttpClients.createMinimal();
veraAddressString = addressString; veraAddressString = addressString;
validVera = isValidVera;
} }
public Sdata getSdata() { public Sdata getSdata() {
if(!validVera)
return new Sdata();
String theUrl = "http://" + veraAddressString + SDATA_REQUEST; String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
String theData; String theData;
@@ -57,27 +62,37 @@ public class VeraInfo {
Device theDevice = null; Device theDevice = null;
while (theIterator.hasNext()) { while (theIterator.hasNext()) {
theDevice = theIterator.next(); theDevice = theIterator.next();
theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName()); if(theDevice.getRoom() != null && roomMap.get(theDevice.getRoom()) != null)
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName()); theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName());
else
theDevice.setRoom("no room");
if(theDevice.getCategory() != null && categoryMap.get(theDevice.getCategory()) != null)
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
else
theDevice.setCategory("<unknown>");
} }
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator(); ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
Scene theScene = null; Scene theScene = null;
while (theSecneIter.hasNext()) { while (theSecneIter.hasNext()) {
theScene = theSecneIter.next(); theScene = theSecneIter.next();
theScene.setRoom(roomMap.get(theScene.getRoom()).getName()); if(theScene.getRoom() != null && roomMap.get(theScene.getRoom()) != null)
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
else
theScene.setRoom("no room");
} }
} }
// This function executes the url against the vera // This function executes the url against the vera
protected String doHttpGETRequest(String url) { protected String doHttpGETRequest(String url) {
log.info("calling GET on URL: " + url); log.debug("calling GET on URL: " + url);
HttpGet httpGet = new HttpGet(url); HttpGet httpGet = new HttpGet(url);
try { try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
String theContent = EntityUtils.toString(response.getEntity()); //read content for data String theContent = EntityUtils.toString(response.getEntity()); //read content for data
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
log.info("GET on URL responded: " + response.getStatusLine().getStatusCode()); log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){ if(response.getStatusLine().getStatusCode() == 200){
return theContent; return theContent;
} }

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
body {
padding-top: 60px;
padding-bottom: 20px;
}
.sortorder:after {
content: '\25b2';
}
.sortorder.reverse:after {
content: '\25bc';
}

View File

@@ -5,12 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>HA Bridge</title> <title>HA Bridge</title>
<style> <link href="css/main.css" rel="stylesheet">
body {
padding-top: 60px;
padding-bottom: 20px;
}
</style>
<link href="css/bootstrap.min.css" rel="stylesheet"> <link href="css/bootstrap.min.css" rel="stylesheet">
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -21,7 +16,7 @@
<body> <body>
<nav class="navbar navbar-inverse navbar-fixed-top"> <nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container"> <div class="container" ng-controller="VersionController">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle"> <button type="button" class="navbar-toggle">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
@@ -35,13 +30,13 @@
<li class="active"><a href="#">Home</a></li> <li class="active"><a href="#">Home</a></li>
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li> <li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
<li class="dropdown"> <li class="dropdown">
<a id="dropdownMenu1" href="#" class="dropdown-toggle" <a id="dropdownMenu1" href="" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">About <span class="caret"></span></a> aria-expanded="false">About <span class="caret"></span></a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li> <li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li> <li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
<li><a href="#">HA Bridge Version 0.3.0</a></li> <li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@@ -18,6 +18,12 @@ app.config(function ($routeProvider) {
}).when('/verascenes', { }).when('/verascenes', {
templateUrl: 'views/verascene.html', templateUrl: 'views/verascene.html',
controller: 'AddingController' controller: 'AddingController'
}).when('/harmonydevices', {
templateUrl: 'views/harmonydevice.html',
controller: 'AddingController'
}).when('/harmonyactivities', {
templateUrl: 'views/harmonyactivity.html',
controller: 'AddingController'
}).otherwise({ }).otherwise({
templateUrl: 'views/configuration.html', templateUrl: 'views/configuration.html',
controller: 'ViewingController' controller: 'ViewingController'
@@ -26,6 +32,9 @@ app.config(function ($routeProvider) {
app.run( function (bridgeService) { app.run( function (bridgeService) {
bridgeService.loadBridgeSettings(); bridgeService.loadBridgeSettings();
bridgeService.updateShowVera();
bridgeService.updateShowHarmony();
bridgeService.getHABridgeVersion();
}); });
app.factory('BridgeSettings', function() { app.factory('BridgeSettings', function() {
@@ -36,6 +45,10 @@ app.factory('BridgeSettings', function() {
BridgeSettings.upnpdevicedb = ""; BridgeSettings.upnpdevicedb = "";
BridgeSettings.upnpresponseport = ""; BridgeSettings.upnpresponseport = "";
BridgeSettings.veraaddress = ""; BridgeSettings.veraaddress = "";
BridgeSettings.harmonyaddress = "";
BridgeSettings.upnpstrict = "";
BridgeSettings.traceupnp = "";
BridgeSettings.devmode = "";
BridgeSettings.setupnpconfigaddress = function(aconfigaddress){ BridgeSettings.setupnpconfigaddress = function(aconfigaddress){
BridgeSettings.upnpconfigaddress = aconfigaddress; BridgeSettings.upnpconfigaddress = aconfigaddress;
@@ -56,14 +69,26 @@ app.factory('BridgeSettings', function() {
BridgeSettings.setveraaddress = function(averaaddress){ BridgeSettings.setveraaddress = function(averaaddress){
BridgeSettings.veraaddress = averaaddress; BridgeSettings.veraaddress = averaaddress;
}; };
BridgeSettings.setharmonyaddress = function(aharmonyaddress){
BridgeSettings.harmonyaddress = aharmonyaddress;
};
BridgeSettings.setupnpstrict = function(aupnpstrict){
BridgeSettings.upnpstrict = aupnpstrict;
};
BridgeSettings.settraceupnp = function(atraceupnp){
BridgeSettings.traceupnp = atraceupnp;
};
BridgeSettings.setdevmode = function(adevmode){
BridgeSettings.devmode = adevmode;
};
return BridgeSettings; return BridgeSettings;
}); });
app.service('bridgeService', function ($http, BridgeSettings) { app.service('bridgeService', function ($http, $window, BridgeSettings) {
var self = this; var self = this;
self.BridgeSettings = BridgeSettings; self.BridgeSettings = BridgeSettings;
this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", devices: [], device: [], error: ""}; this.state = {base: window.location.origin + "/api/devices", upnpbase: window.location.origin + "/upnp/settings", huebase: window.location.origin + "/api", devices: [], device: [], error: "", showVera: false, showHarmony: false, habridgeversion: ""};
this.viewDevices = function () { this.viewDevices = function () {
this.state.error = ""; this.state.error = "";
@@ -75,8 +100,24 @@ app.service('bridgeService', function ($http, BridgeSettings) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; self.state.error = error.data.message;
} else { } else {
self.state.error = "If you're not seeing any devices, you may be running into problems with CORS. " + self.state.error = "Some error occurred.";
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag."; }
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); console.log(error);
} }
@@ -92,20 +133,50 @@ app.service('bridgeService', function ($http, BridgeSettings) {
self.BridgeSettings.setupnpdevicedb(response.data.upnpdevicedb); self.BridgeSettings.setupnpdevicedb(response.data.upnpdevicedb);
self.BridgeSettings.setupnpresponseport(response.data.upnpresponseport); self.BridgeSettings.setupnpresponseport(response.data.upnpresponseport);
self.BridgeSettings.setveraaddress(response.data.veraaddress); self.BridgeSettings.setveraaddress(response.data.veraaddress);
self.BridgeSettings.setharmonyaddress(response.data.harmonyaddress);
self.BridgeSettings.settraceupnp(response.data.traceupnp);
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
self.BridgeSettings.setdevmode(response.data.devmode);
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
self.state.showVera = false;
else
self.state.showVera = true;
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
self.state.showHarmony = false;
else
self.state.showHarmony = true;
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Load Bridge Settings Error: " + error.data.message);
} else { } else {
self.state.error = "If you're not seeing any settings, you may be running into problems with CORS. " + $window.alert("Load Bridge Settings Error: unknown");
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
} }
console.log(error); console.log(error);
} }
); );
}; };
this.updateShowVera = function () {
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
this.state.showVera = false;
else
this.state.showVera = true;
return;
}
this.updateShowHarmony = function () {
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
this.state.showHarmony = false;
else
this.state.showHarmony = true;
return;
}
this.viewVeraDevices = function () { this.viewVeraDevices = function () {
this.state.error = "";
if(!this.state.showVera)
return;
this.state.error = ""; this.state.error = "";
return $http.get(this.state.base + "/vera/devices").then( return $http.get(this.state.base + "/vera/devices").then(
function (response) { function (response) {
@@ -113,70 +184,130 @@ app.service('bridgeService', function ($http, BridgeSettings) {
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Get Vera Devices Error: " + error.data.message);
} else { } else {
self.state.error = "If you're not seeing any address, you may be running into problems with CORS. " + $window.alert("Get Vera Devices Error: unknown");
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
} }
console.log(error);
} }
); );
}; };
this.viewVeraScenes = function () { this.viewVeraScenes = function () {
this.state.error = ""; this.state.error = "";
if(!this.state.showVera)
return;
return $http.get(this.state.base + "/vera/scenes").then( return $http.get(this.state.base + "/vera/scenes").then(
function (response) { function (response) {
self.state.verascenes = response.data; self.state.verascenes = response.data;
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Get Vera Scenes Error: " + error.data.message);
} else { } else {
self.state.error = "If you're not seeing any address, you may be running into problems with CORS. " + $window.alert("Get Vera Scenes Error: unknown");
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
} }
console.log(error);
} }
); );
}; };
this.addDevice = function (id, name, type, onUrl, offUrl) { this.viewHarmonyActivities = function () {
this.state.error = ""; this.state.error = "";
if (id) { if(!this.state.showHarmony)
var putUrl = this.state.base + "/" + id; 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) {
for(var i = 0; i < this.state.devices.length; i++) {
if(this.state.devices[i].mapId == id)
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, { return $http.put(putUrl, {
id: id, id: device.id,
name: name, name: device.name,
deviceType: "switch", mapId: device.mapId,
onUrl: onUrl, mapType: device.mapType,
offUrl: offUrl deviceType: device.deviceType,
onUrl: device.onUrl,
offUrl: device.offUrl,
httpVerb: device.httpVerb,
contentType: device.contentType,
contentBody: device.contentBody,
contentBodyOff: device.contentBodyOff
}).then( }).then(
function (response) { function (response) {
self.viewDevices(); self.viewDevices();
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Edit Device Error: " + error.data.message);
} }
console.log(error); $window.alert("Edit Device Error: unknown");
} }
); );
} else { } else {
if(device.deviceType == null || device.deviceType == "")
device.deviceType = "switch";
if(device.httpVerb != null && device.httpVerb != "")
device.deviceType = "custom";
return $http.post(this.state.base, { return $http.post(this.state.base, {
name: name, name: device.name,
deviceType: "switch", mapId: device.mapId,
onUrl: onUrl, mapType: device.mapType,
offUrl: offUrl deviceType: device.deviceType,
onUrl: device.onUrl,
offUrl: device.offUrl,
httpVerb: device.httpVerb,
contentType: device.contentType,
contentBody: device.contentBody,
contentBodyOff: device.contentBodyOff
}).then( }).then(
function (response) { function (response) {
self.viewDevices(); self.viewDevices();
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Add new Device Error: " + error.data.message);
} }
console.log(error); $window.alert("Add new Device Error: unknown");
} }
); );
} }
@@ -192,55 +323,133 @@ app.service('bridgeService', function ($http, BridgeSettings) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; self.state.error = error.data.message;
} }
console.log(error); $window.alert("Delete Device Error: unknown");
} }
); );
}; };
this.editDevice = function (id, name, onUrl, offUrl) { this.deleteDeviceByMapId = function (id) {
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl}; for(var i = 0; i < this.state.devices.length; i++) {
if(this.state.devices[i].mapId == id)
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;
}
}; };
}); });
app.controller('ViewingController', function ($scope, $location, bridgeService, BridgeSettings) { app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, BridgeSettings) {
$scope.BridgeSettings = bridgeService.BridgeSettings; $scope.BridgeSettings = bridgeService.BridgeSettings;
bridgeService.viewDevices(); bridgeService.viewDevices();
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
bridgeService.updateShowVera();
bridgeService.updateShowHarmony();
$scope.visible = false;
$scope.imgUrl = "glyphicon glyphicon-plus";
$scope.predicate = '';
$scope.reverse = true;
$scope.order = function(predicate) {
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.predicate = predicate;
};
$scope.deleteDevice = function (device) { $scope.deleteDevice = function (device) {
bridgeService.deleteDevice(device.id); bridgeService.deleteDevice(device.id);
}; };
$scope.testUrl = function (url) { $scope.testUrl = function (device, type) {
window.open(url, "_blank"); bridgeService.testUrl(device, type);
}; };
$scope.setBridgeUrl = function (url) { $scope.setBridgeUrl = function (url) {
bridgeService.state.base = url; bridgeService.state.base = url;
bridgeService.viewDevices(); bridgeService.viewDevices();
}; };
$scope.editDevice = function (device) { $scope.editDevice = function (device) {
bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl); bridgeService.editDevice(device);
$location.path('/editdevice'); $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, bridgeService, BridgeSettings) { app.controller('AddingController', function ($scope, $location, $http, bridgeService, BridgeSettings) {
$scope.device = {id: "", name: "", type: "switch", onUrl: "", offUrl: ""}; $scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
$scope.vera = {base: "", port: "3480", id: ""}; $scope.vera = {base: "", port: "3480", id: ""};
$scope.vera.base = "http://" + BridgeSettings.veraaddress; $scope.vera.base = "http://" + BridgeSettings.veraaddress;
bridgeService.device = $scope.device; bridgeService.device = $scope.device;
bridgeService.viewVeraDevices(); bridgeService.viewVeraDevices();
bridgeService.viewVeraScenes(); bridgeService.viewVeraScenes();
bridgeService.viewHarmonyActivities();
bridgeService.viewHarmonyDevices();
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
bridgeService.updateShowVera();
bridgeService.updateShowHarmony();
$scope.device = bridgeService.state.device; $scope.device = bridgeService.state.device;
$scope.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 = "";
$scope.order = function(predicate) {
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.predicate = predicate;
};
$scope.buildUrlsUsingDevice = function () { $scope.buildUrlsUsingDevice = function (dim_control) {
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.deviceType = "switch";
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" $scope.device.mapType = "veraDevice";
+ $scope.vera.id; $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="
+ $scope.vera.id
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
+ dim_control;
else
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
+ $scope.vera.id;
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
+ $scope.vera.id; + $scope.vera.id;
@@ -250,6 +459,9 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.deviceType = "scene";
$scope.device.mapType = "veraScene";
$scope.device.mapId = $scope.vera.id;
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
+ $scope.vera.id; + $scope.vera.id;
@@ -258,14 +470,24 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
+ $scope.vera.id; + $scope.vera.id;
}; };
$scope.buildDeviceUrls = function (veradevice) { $scope.buildDeviceUrls = function (veradevice, dim_control) {
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.deviceType = "switch";
$scope.device.name = veradevice.name; $scope.device.name = veradevice.name;
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.mapType = "veraDevice";
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" $scope.device.mapId = veradevice.id;
+ 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="
+ veradevice.id
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
+ dim_control;
else
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
+ veradevice.id;
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
+ veradevice.id; + veradevice.id;
@@ -275,7 +497,10 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.deviceType = "scene";
$scope.device.name = verascene.name; $scope.device.name = verascene.name;
$scope.devoce.mapType = "veraScene";
$scope.device.mapId = verascene.id;
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
+ verascene.id; + verascene.id;
@@ -284,26 +509,134 @@ app.controller('AddingController', function ($scope, bridgeService, BridgeSettin
+ verascene.id; + verascene.id;
}; };
$scope.testUrl = function (url) { $scope.buildActivityUrls = function (harmonyactivity) {
window.open(url, "_blank"); $scope.device.deviceType = "activity";
$scope.device.name = harmonyactivity.label;
$scope.device.mapType = "harmonyActivity";
$scope.device.mapId = harmonyactivity.id;
$scope.device.onUrl = "{\"name\":\"" + harmonyactivity.id + "\"}";
$scope.device.offUrl = "{\"name\":\"-1\"}";
};
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
$scope.device.deviceType = "button";
$scope.device.name = harmonydevice.label;
$scope.device.mapType = "harmonyButton";
$scope.device.mapId = harmonydevice.id + "-" + onbutton + "-" + offbutton;
$scope.device.onUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + onbutton + "\"}";
$scope.device.offUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + offbutton + "\"}";
};
$scope.testUrl = function (device, type) {
bridgeService.testUrl(device, type);
}; };
$scope.addDevice = function () { $scope.addDevice = function () {
bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl).then( bridgeService.addDevice($scope.device).then(
function () { function () {
$scope.device.id = ""; $scope.device.id = "";
$scope.device.mapType = null;
$scope.device.mapId = null;
$scope.device.name = ""; $scope.device.name = "";
$scope.device.onUrl = ""; $scope.device.onUrl = "";
$scope.device.deviceType = "switch"; $scope.device.deviceType = "switch";
$scope.device.offUrl = ""; $scope.device.offUrl = "";
$scope.device.httpVerb = null;
$scope.device.contentType = null;
$scope.device.contentBody = null;
$scope.device.contentBodyOff = null;
$location.path('/#');
}, },
function (error) { function (error) {
} }
); );
} }
$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) {
bridgeService.deleteDeviceByMapId(id);
};
}); });
app.filter('availableId', 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)){
out.push(input[i]);
}
}
return out;
}
});
app.filter('unavailableId', 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)){
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) { app.controller('ErrorsController', function ($scope, bridgeService) {
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
}); });
app.controller('VersionController', function ($scope, bridgeService) {
$scope.bridge = bridgeService.state;
});

View File

@@ -1,17 +1,68 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#">Configuration</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<h2>Configuration <a class="btn btn-primary pull-right" href="#/editor"><i
class="icon-plis-sign icon-white"></i> Manual Add</a> <div ng-controller="ErrorsController">
<a class="btn btn-primary pull-right" href="#/verascenes"><i <div ng-if="bridge.error"
class="icon-plis-sign icon-white"></i> Vera Scenes</a> class="alert alert-warning alert-dismissible" role="alert">
<a class="btn btn-primary pull-right" href="#/veradevices"><i <button type="button" class="close" data-dismiss="alert"
class="icon-plis-sign icon-white"></i> Vera Devices</a> aria-label="Close">
</h2> <span aria-hidden="true">&times;</span>
</button>
<h2 ng-show='bridge.error != ""'>ERROR</h2>
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Current devices</h2>
</div>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>
<a href="" ng-click="order('id')">ID</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span></th>
<th>
<a href="" ng-click="order('name')">Name</a>
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span></th>
<th>
<a href="" ng-click="order('deviceType')">Type</a>
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices | orderBy:predicate:reverse">
<td>{{device.id}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'on')">Test ON</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'off')">Test OFF</button>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</td>
</tr>
</table>
</div>
<div class="panel panel-default bridgeServer"> <div class="panel panel-default bridgeServer">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Bridge settings</h1> <h1 class="panel-title">Bridge settings <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
</div> </div>
<div class="panel-body"> <div ng-if="visible" class="animate-if" class="panel-body">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
@@ -55,51 +106,22 @@
<td>vera.address</td> <td>vera.address</td>
<td>{{BridgeSettings.veraaddress}}</td> <td>{{BridgeSettings.veraaddress}}</td>
</tr> </tr>
<tr>
<td>harmony.address</td>
<td>{{BridgeSettings.harmonyaddress}}</td>
</tr>
<tr>
<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> </table>
</div> </div>
</div> </div>
<div ng-controller="ErrorsController">
<div ng-if="bridge.error"
class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert"
aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h2 ng-show='bridge.error != ""'>ERROR</h2>
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Current devices</h2>
</div>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices">
<td>{{device.id}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device.onUrl)">Test ON</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device.offUrl)">Test OFF</button>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</td>
</tr>
</table>
</div>

View File

@@ -1,11 +1,16 @@
<h2> <ul class="nav nav-pills" role="tablist">
Device Editor <a class="btn btn-primary pull-right" href="/"> <li role="presentation"><a href="#">Configuration</a></li>
Configuration</a> <li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
</h2> <li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li 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 panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading"> <div class="panel-heading">
<h2 class="panel-title">Add a new device</h2> <h2 class="panel-title">Edit a device</h2>
</div> </div>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
@@ -22,26 +27,115 @@
Update Device</button> Update Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-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 <label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-on-url" <textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"> ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label> for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"> ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
</label>
<div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
<option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select>
</div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
<option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select>
</div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button>
</div> </div>
</form> </form>
</li> </li>

View File

@@ -1,9 +1,13 @@
<h2> <ul class="nav nav-pills" role="tablist">
Manual Add <a class="btn btn-primary pull-right" href="/"> <li role="presentation"><a href="#">Configuration</a></li>
Configuration</a> <li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
</h2> <li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li 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"> <div class="panel-heading">
<h2 class="panel-title">Generate a new device/scene/control point</h2> <h2 class="panel-title">Generate a new device/scene/control point</h2>
</div> </div>
@@ -40,11 +44,25 @@
<input type="text" class="form-control" id="vera-id" <input type="text" class="form-control" id="vera-id"
ng-model="vera.id" placeholder="ID"> ng-model="vera.id" placeholder="ID">
</div> </div>
<button type="submit" ng-click="buildUrlsUsingDevice()" </div>
class="col-xs-4 col-sm-2 btn btn-success">Generate Device <div class="form-group">
<label class="col-xs-2 col-sm-2 control-label" for="device-dim-control">Device Dim Control</label>
<div class="col-xs-10 col-sm-2">
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity..byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</div>
</div>
<div class="form-group">
<button type="submit" ng-click="buildUrlsUsingDevice(device_dim_control)"
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device
URLs</button> URLs</button>
<button type="submit" ng-click="buildUrlsUsingScene()" <button type="submit" ng-click="buildUrlsUsingScene()"
class="col-xs-4 col-sm-2 btn btn-success">Generate Scene class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Scene
URLs</button> URLs</button>
</div> </div>
</form> </form>
@@ -59,6 +77,7 @@
<li class="list-group-item"> <li class="list-group-item">
<form class="form-horizontal" ng-submit="addDevice()"> <form class="form-horizontal" ng-submit="addDevice()">
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
</label> </label>
@@ -68,28 +87,93 @@
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
Add Device</button> Add Device</button>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On <label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-on-url" <textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"> ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label> for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"> ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
</label>
<div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
<option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select>
</div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
<option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select>
</div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div 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>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button>
</div> </div>
</form> </form>
</li> </li>

View File

@@ -0,0 +1,117 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Configuration</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading">
<h2 class="panel-title">Harmony Activity List</h2>
</div>
<ul class="list-group">
<li class="list-group-item">
<p class="text-muted">You can select a Harmony Activity and generate
the add activity box selections automatically.</p>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>
<a href="" ng-click="order('label')">Name</a>
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableId | orderBy:predicate:reverse">
<td>{{harmonyactivity.label}}</td>
<td>{{harmonyactivity.id}}</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildActivityUrls(harmonyactivity)">Generate
Activity URLs</button>
</td>
</tr>
</table>
</li>
</ul>
<div 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>Actions</th>
</tr>
</thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableId | orderBy:predicate:reverse">
<td>{{harmonyactivity.label}}</td>
<td>{{harmonyactivity.id}}</td>
<td><button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(harmonyactivity.id)">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>

View File

@@ -0,0 +1,140 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Configuration</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading">
<h2 class="panel-title">Harmony Device List</h2>
</div>
<ul class="list-group">
<li class="list-group-item">
<p class="text-muted">You can select a Harmony Device and Button and generate
the add button box selections automatically.</p>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>
<a href="" ng-click="order('label')">Name</a>
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>On Button</th>
<th>Off Button</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
<td>{{harmonydevice.label}}</td>
<td>{{harmonydevice.id}}</td>
<td>
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
<optgroup ng-repeat="ctrlon in harmonydevice.controlGroup" label="{{ctrlon.name}}">
<option ng-repeat="funcon in ctrlon.function">{{funcon.name}}</option>
</optgroup >
</select>
</td>
<td>
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
<optgroup ng-repeat="ctrloff in harmonydevice.controlGroup" label="{{ctrloff.name}}">
<option ng-repeat="funcoff in ctrloff.function">{{funcoff.name}}</option>
</optgroup >
</select>
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Generate
Button URLs</button>
</td>
</tr>
</table>
</li>
</ul>
<div 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('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.mapId}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(device.mapId)">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>

View File

@@ -1,7 +1,11 @@
<h2> <ul class="nav nav-pills" role="tablist">
Vera Device <a class="btn btn-primary pull-right" href="/"> <li role="presentation"><a href="#">Configuration</a></li>
Configuration</a> <li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
</h2> <li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li 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" ng-if="!bridge.error"> <div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading"> <div class="panel-heading">
@@ -10,32 +14,91 @@
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<p class="text-muted">You can select a Vera device and generate <p class="text-muted">You can select a Vera device and generate
the add device box selections automatically.</p> the add device box selections automatically.</p><p>Also, use this select menu for which type of dim
control you would like to be generated:
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity..byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>
<th>Id</th> <a href="" ng-click="order('name')">Name</a>
<th>Category</th> <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
<th>Room</th> </th>
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('category')">Category</a>
<span class="sortorder" ng-show="predicate === 'category'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('room')">Room</a>
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="veradevice in bridge.veradevices"> <tr ng-repeat="veradevice in bridge.veradevices | availableId | orderBy:predicate:reverse">
<td>{{veradevice.name}}</td> <td>{{veradevice.name}}</td>
<td>{{veradevice.id}}</td> <td>{{veradevice.id}}</td>
<td>{{veradevice.category}}</td> <td>{{veradevice.category}}</td>
<td>{{veradevice.room}}</td> <td>{{veradevice.room}}</td>
<td> <td>
<button class="btn btn-success" type="submit" <button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(veradevice)">Generate ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
Device URLs</button> Device URLs</button>
</td> </td>
</tr> </tr>
</table> </table>
</li> </li>
</ul> </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 | unavailableId | 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(harmonyactivity.id)">Delete</button>
</td>
</tr>
</table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading"> <div class="panel-heading">
@@ -56,26 +119,24 @@
Add Device</button> Add Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On <label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-on-url" <textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"> ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label> for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"> ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button>
</div> </div>
</form> </form>
</li> </li>

View File

@@ -1,7 +1,11 @@
<h2> <ul class="nav nav-pills" role="tablist">
Vera Scene <a class="btn btn-primary pull-right" href="/"> <li role="presentation"><a href="#">Configuration</a></li>
Configuration</a> <li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
</h2> <li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
<li 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" ng-if="!bridge.error"> <div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading"> <div class="panel-heading">
@@ -10,18 +14,27 @@
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<p class="text-muted">You can select a Vera scene and generate <p class="text-muted">You can select a Vera scene and generate
the add device box selections automatically.</p> the add scene box selections automatically.</p>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>
<th>Id</th> <a href="" ng-click="order('name')">Name</a>
<th>Room</th> <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('room')">Room</a>
<span class="sortorder" ng-show="predicate === 'room'" ng-class="{reverse:reverse}"></span>
</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="verascene in bridge.verascenes"> <tr ng-repeat="verascene in bridge.verascenes | availableId | orderBy:predicate:reverse">
<td>{{verascene.name}}</td> <td>{{verascene.name}}</td>
<td>{{verascene.id}}</td> <td>{{verascene.id}}</td>
<td>{{verascene.room}}</td> <td>{{verascene.room}}</td>
@@ -34,6 +47,41 @@
</table> </table>
</li> </li>
</ul> </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 | unavailableId | 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(harmonyactivity.id)">Delete</button>
</td>
</tr>
</table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default bridgeServer" ng-if="!bridge.error">
<div class="panel-heading"> <div class="panel-heading">
@@ -54,26 +102,24 @@
Add Scene</button> Add Scene</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On <label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-on-url" <textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"> ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label> for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"> ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div> </div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button>
</div> </div>
</form> </form>
</li> </li>

View File

@@ -0,0 +1,3 @@
version=${project.version}
groupId=${project.groupId}
artifactId=${project.artifactId}

View File

@@ -1,29 +0,0 @@
package com.test;
import java.net.InetAddress;
import java.util.Arrays;
public class TestBean {
public static void main(String[] args) {
try {
InetAddress address = InetAddress.getLocalHost();
System.out.println("Using InetAddress");
System.out.println("Host Address: "+ address.getHostAddress());
System.out.println("Host Name: "+ address.getHostName());
System.out.println("Address List: "+ Arrays.toString(InetAddress.getAllByName(address.getHostName())));
System.out.println("CanonicalHostName: "+ address.getCanonicalHostName());
System.out.println("Address: "+ address.getAddress());
System.out.println("LocalHost: "+ address.getLocalHost());
System.out.println("LoopbackAddress: "+ address.getLoopbackAddress());
String os = "os.name";
String version = "os.version";
String arch = "os.arch";
System.out.println("Name of the OS: "+ System.getProperty(os));
System.out.println("Version of the OS: "+ System.getProperty(version));
System.out.println("Architecture of the OS: "+ System.getProperty(arch));
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,14 +0,0 @@
package demo;
import com.bwssystems.HABridge.HABridge;
/*
* Dummy test holder
*/
public class DemoApplicationTests {
public void contextLoads() {
}
}