Compare commits

..

11 Commits

Author SHA1 Message Date
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
23 changed files with 417 additions and 170 deletions

2
.gitignore vendored
View File

@@ -10,3 +10,5 @@ data
.idea .idea
/target/ /target/
/.settings/ /.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>

View File

@@ -1,5 +1,5 @@
# ha-bridge # ha-bridge
Emulates philips hue api to other home automation gateways. The Amazon echo now supports wemo and philips hue. Emulates Philips Hue api to other home automation gateways such as an Amazon Echo. The Bridge has helpers to build devices for the gateway for the Vera, Vera Lite or Vera Edge. Alternatively the Bridge supports custom calls as well. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol.
## Build ## Build
To customize and build it yourself, build a new jar with maven: To customize and build it yourself, build a new jar with maven:
``` ```
@@ -9,13 +9,13 @@ Otherwise go to http://www.bwssystems.com/apps.html to download the latest jar f
## Run ## Run
Then locate the jar and start the server with: Then locate the jar and start the server with:
``` ```
java -jar -Dvera.address=192.168.X.Y ha-bridge-0.X.Y.jar java -jar -Dvera.address=X.Y.Z.A ha-bridge-0.X.Y.jar
``` ```
## Available Arguments ## Available Arguments
### -Dvera.address=`<ip address>` ### -Dvera.address=`<ip address>`
The argument for the vera address should be given as it the system does not have a way to find the address. Supply -Dvera.address=X.Y.Z.A on the command line to provide it. The argument for the vera address should be given as it the system does not have a way to find the address. Supply -Dvera.address=X.Y.Z.A on the command line to provide it. If a vera is not used, do not set it.
### -Dupnp.config.address=`<ip address>` ### -Dupnp.config.address=`<ip address>`
The server defaults to the first available address on the host. Replace the -Dupnp.config.address=`<ip address>` value with the server ipv4 address you would like to use. The server defaults to the first available address on the host. Replace the -Dupnp.config.address=`<ip address>` value with the server ipv4 address you would like to use as the address that any upnp device will call after discovery.
### -Dserver.port=`<port>` ### -Dserver.port=`<port>`
The server defaults to running on port 8080. If you're already running a server (like openHAB) on 8080, -Dserver.port=`<port>` on the command line. The server defaults to running on port 8080. If you're already running a server (like openHAB) on 8080, -Dserver.port=`<port>` on the command line.
### -Dupnp.device.db=`<filepath>` ### -Dupnp.device.db=`<filepath>`
@@ -23,11 +23,11 @@ The default location for the db to contain the devices as they are added is "dat
### -Dupnp.response.port=`<port>` ### -Dupnp.response.port=`<port>`
The upnp response port that will be used. The default is 50000. The upnp response port that will be used. The default is 50000.
### -Dupnp.strict=`<true|false>` ### -Dupnp.strict=`<true|false>`
Upnp has been very closed on this platform to try and respond as a hue and there is now a setting to control if it is more open or strict, Add -Dupnp.strict=`<true|false>` to your command line to have the emulator respond to what it thinks is an echo to a hue or any other device. The default is upnp.strict=false. Upnp has been very closed on this platform to try and respond as a hue and there is now a setting to control if it is more open or strict, Add -Dupnp.strict=`<true|false>` to your command line to have the emulator respond to what it thinks is an echo to a hue or any other device. The default is upnp.strict=true.
### -Dtrace.upnp=`<true|false>` ### -Dtrace.upnp=`<true|false>`
Turn on tracing for upnp discovery messages. The default is false. Turn on tracing for upnp discovery messages. The default is false.
### -Dvtwo.compatibility=`<true|false>` ### -Dvtwo.compatibility=`<true|false>`
Turns on compatibility for upnp detection and response as it was in the original version of amazon-echo-ha-bridge. The default is true. Turns on compatibility for upnp detection and response as it was in the original version of amazon-echo-ha-bridge. The default is false.
## Web Config ## Web Config
Configure by going to the url for the host you are running on or localhost with port you have assigned: Configure by going to the url for the host you are running on or localhost with port you have assigned:
``` ```
@@ -44,8 +44,8 @@ POST http://host:8080/api/devices
"offUrl" : "http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41" "offUrl" : "http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41"
} }
``` ```
## Dimming ## Dimming and value passing control
Dimming is also supported by using the expessions ${intensity.percent} or ${intensity.byte} for 0-100 and 0-255 respectively. Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 or custom values using ${intensity.math(<your expression using "X" as the value to operate on>)} i.e. "${intensity.math(X/4)}".
e.g. e.g.
``` ```
{ {
@@ -61,9 +61,10 @@ See the echo's documentation for the dimming phrase.
added optional fields added optional fields
* contentType (currently un-validated) * contentType (currently un-validated)
* httpVerb (POST/PUT/GET only supported) * httpVerb (POST/PUT/GET only supported)
* contentBody your post/put body here * contentBody your post/put body for onUrl here
* contentBodyOff your post/put body for offUrl here
This will allow control of any other application that may need more then GET. This will allow control of any other application that may need more then GET. You can also use the dimming and value control commands within the URLs as well.
e.g: e.g:
``` ```
{ {
@@ -73,10 +74,12 @@ e.g:
"onUrl": "http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}", "onUrl": "http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}",
"contentType" : "application/json", "contentType" : "application/json",
"httpVerb":"POST", "httpVerb":"POST",
"contentBody" : "{\"fooBar\":\"baz\"}" "contentBody" : "{\"fooBar\":\"baz_on\"}"
"contentBodyOff" : "{\"fooBar\":\"baz_off\"}"
} }
``` ```
Anything that takes an action as a result of an HTTP request will probably work - like putting Vera in and out of night mode: ## Custom Usage URLs
Anything that takes an action as a result of an HTTP request will probably work and you can also use the dimming and value control commands within the URLs as well - like putting Vera in and out of night mode:
``` ```
{ {
"name": "night mode", "name": "night mode",

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>0.4.4</version> <version>0.4.10</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>
@@ -53,6 +53,11 @@
<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>
</dependencies> </dependencies>
<build> <build>

View File

@@ -61,4 +61,9 @@ public class BridgeSettings {
this.vtwocompatibility = vtwocompatibility; this.vtwocompatibility = vtwocompatibility;
} }
public Boolean isValidVera() {
if(this.veraaddress.contains(Configuration.DEFAULT_VERA_ADDRESS))
return false;
return true;
}
} }

View File

@@ -0,0 +1,8 @@
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 DFAULT_WEB_PORT = "8080";
}

View File

@@ -40,6 +40,7 @@ public class HABridge {
String addressString; String addressString;
BridgeSettings bridgeSettings; BridgeSettings bridgeSettings;
log.info("HA Bridge (v0.4.10) starting setup....");
//get ip address for upnp requests //get ip address for upnp requests
try { try {
address = InetAddress.getLocalHost(); address = InetAddress.getLocalHost();
@@ -51,27 +52,28 @@ public class HABridge {
bridgeSettings = new BridgeSettings(); bridgeSettings = new BridgeSettings();
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString)); bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", "data/device.db")); bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000")); bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100")); bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "false"))); bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false"))); bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
bridgeSettings.setVtwocompatibility(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "true"))); bridgeSettings.setVtwocompatibility(Boolean.parseBoolean(System.getProperty("vtwo.compatibility", "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")); bridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DFAULT_WEB_PORT));
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 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);
// 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());
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();

View File

@@ -1,8 +1,6 @@
package com.bwssystems.HABridge.api.hue; package com.bwssystems.HABridge.api.hue;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -75,17 +73,20 @@ public class DeviceResponse {
} }
public Map<String, String> getPointsymbol() { public Map<String, String> getPointsymbol() {
Map<String, String> dummyValue = new HashMap<>(); if(pointsymbol == null)
dummyValue.put("1", "none"); {
dummyValue.put("2", "none"); pointsymbol = new HashMap<>();
dummyValue.put("3", "none"); pointsymbol.put("1", "none");
dummyValue.put("4", "none"); pointsymbol.put("2", "none");
dummyValue.put("5", "none"); pointsymbol.put("3", "none");
dummyValue.put("6", "none"); pointsymbol.put("4", "none");
dummyValue.put("7", "none"); pointsymbol.put("5", "none");
dummyValue.put("8", "none"); pointsymbol.put("6", "none");
pointsymbol.put("7", "none");
pointsymbol.put("8", "none");
}
return dummyValue; return pointsymbol;
} }
public void setPointsymbol(Map<String, String> pointsymbol) { public void setPointsymbol(Map<String, String> pointsymbol) {
@@ -101,20 +102,13 @@ public class DeviceResponse {
deviceState.setEffect("none"); deviceState.setEffect("none");
deviceState.setAlert("none"); deviceState.setAlert("none");
deviceState.setBri(254); deviceState.setBri(254);
deviceState.setHue(15823); deviceState.setSat(254);
deviceState.setSat(88);
deviceState.setCt(313);
List<Double> xv = new LinkedList<>();
xv.add(Double.valueOf("0.4255"));
xv.add(Double.valueOf("0.3998"));
deviceState.setXy(xv);
deviceState.setColormode("ct");
response.setName(name); response.setName(name);
response.setUniqueid(id); response.setUniqueid(id);
response.setManufacturername("Philips"); response.setManufacturername("Philips");
response.setType("Extended color light"); response.setType("Dimmable light");
response.setModelid("LCT001"); response.setModelid("LWB004");
response.setSwversion("65003148"); response.setSwversion("65003148");
return response; return response;

View File

@@ -11,6 +11,7 @@ public class DeviceDescriptor{
private String httpVerb; private String httpVerb;
private String contentType; private String contentType;
private String contentBody; private String contentBody;
private String contentBodyOff;
public String getName() { public String getName() {
return name; return name;
@@ -76,5 +77,13 @@ public class DeviceDescriptor{
this.contentBody = 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;
@@ -106,7 +107,14 @@ public class DeviceRepository {
} }
try { try {
Path target = null;
if(Files.exists(filePath)) {
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE); Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
if(target != null)
Files.delete(target);
} catch (IOException e) { } catch (IOException e) {
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e); log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
} }
@@ -116,7 +124,7 @@ public class DeviceRepository {
String content = null; String content = null;
if(Files.notExists(filePath) || !Files.isReadable(filePath)){ if(Files.notExists(filePath) || !Files.isReadable(filePath)){
log.error("Error reading the file: " + filePath + " - Does not exist or is not readable. "); log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
return null; return null;
} }
@@ -188,6 +196,9 @@ public class DeviceRepository {
} else if (name.equals("contentBody")) { } else if (name.equals("contentBody")) {
deviceEntry.setContentBody(reader.nextString()); deviceEntry.setContentBody(reader.nextString());
log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody()); log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody());
} else if (name.equals("contentBodyOff")) {
deviceEntry.setContentBodyOff(reader.nextString());
log.debug("Read a Device - device json contentBodyOff:" + deviceEntry.getContentBodyOff());
} else { } else {
reader.skipValue(); reader.skipValue();
} }

View File

@@ -36,7 +36,7 @@ public class DeviceResource {
public DeviceResource(BridgeSettings theSettings) { public DeviceResource(BridgeSettings theSettings) {
super(); super();
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb()); deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
veraInfo = new VeraInfo(theSettings.getVeraAddress()); veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
setupEndpoints(); setupEndpoints();
} }
@@ -86,6 +86,7 @@ public class DeviceResource {
deviceEntry.setHttpVerb(device.getHttpVerb()); deviceEntry.setHttpVerb(device.getHttpVerb());
deviceEntry.setContentType(device.getContentType()); deviceEntry.setContentType(device.getContentType());
deviceEntry.setContentBody(device.getContentBody()); deviceEntry.setContentBody(device.getContentBody());
deviceEntry.setContentBodyOff(device.getContentBodyOff());
deviceRepository.save(deviceEntry); deviceRepository.save(deviceEntry);
response.status(HttpStatus.SC_OK); response.status(HttpStatus.SC_OK);

View File

@@ -10,6 +10,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import net.java.dev.eval.Expression;
import static spark.Spark.get; import static spark.Spark.get;
import static spark.Spark.post; import static spark.Spark.post;
import static spark.Spark.put; import static spark.Spark.put;
@@ -30,6 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -42,6 +45,9 @@ 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;
@@ -54,11 +60,10 @@ public class HueMulator {
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();
} }
// This function sets up the sparkjava rest calls for the hue api // This function sets up the sparkjava rest calls for the hue api
private void setupEndpoints() { public void setupServer() {
log.info("Hue emulator service started...."); log.info("Hue emulator service started....");
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured // http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> { get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
@@ -205,8 +210,12 @@ public class HueMulator {
} }
//quick template //quick template
String body;
url = replaceIntensityValue(url, state.getBri()); url = replaceIntensityValue(url, state.getBri());
String body = replaceIntensityValue(device.getContentBody(), state.getBri()); if (state.isOn())
body = replaceIntensityValue(device.getContentBody(), state.getBri());
else
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
//make call //make call
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){ if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE); response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
@@ -223,9 +232,10 @@ public class HueMulator {
/* light weight templating here, was going to use free marker but it was a bit too /* light weight templating here, was going to use free marker but it was a bit too
* heavy for what we were trying to do. * heavy for what we were trying to do.
* *
* currently provides only two variables: * currently provides:
* intensity.byte : 0-255 brightness. this is raw from the echo * intensity.byte : 0-255 brightness. this is raw from the echo
* intensity.percent : 0-100, adjusted for the vera * intensity.percent : 0-100, adjusted for the vera
* intensity.math(X*1) : where X is the value from the interface call and can use net.java.dev.eval math
*/ */
protected String replaceIntensityValue(String request, int intensity){ protected String replaceIntensityValue(String request, int intensity){
if(request == null){ if(request == null){
@@ -238,7 +248,20 @@ public class HueMulator {
int percentBrightness = (int) Math.round(intensity/255.0*100); int percentBrightness = (int) Math.round(intensity/255.0*100);
String intensityPercent = String.valueOf(percentBrightness); String intensityPercent = String.valueOf(percentBrightness);
request = request.replace(INTENSITY_PERCENT, intensityPercent); request = request.replace(INTENSITY_PERCENT, intensityPercent);
} } else if(request.contains(INTENSITY_MATH)){
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
try {
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: " + String.valueOf(intensity));
Expression exp = new Expression(mathDescriptor);
BigDecimal result = exp.eval(variables);
Integer endResult = Math.round(result.floatValue());
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
} catch (Exception e) {
log.error("Could not execute Math: " + mathDescriptor, e);
} }
return request; return request;
} }

View File

@@ -90,10 +90,9 @@ public class UpnpSettingsResource {
public UpnpSettingsResource(BridgeSettings theSettings) { public UpnpSettingsResource(BridgeSettings theSettings) {
super(); super();
this.theSettings = theSettings; this.theSettings = theSettings;
setupListener(this.theSettings);
} }
private void setupListener (BridgeSettings theSettings) { public void setupServer() {
log.info("Hue description service started...."); log.info("Hue description service started....");
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator // http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> { get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {

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;

View File

@@ -30,13 +30,13 @@
<li class="active"><a href="#">Home</a></li> <li class="active"><a href="#">Home</a></li>
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li> <li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
<li class="dropdown"> <li class="dropdown">
<a id="dropdownMenu1" href="#" class="dropdown-toggle" <a id="dropdownMenu1" href="" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">About <span class="caret"></span></a> aria-expanded="false">About <span class="caret"></span></a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li> <li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li> <li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
<li><a href="#">HA Bridge Version 0.4.4</a></li> <li><a href="">HA Bridge Version 0.4.10</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@@ -26,6 +26,7 @@ app.config(function ($routeProvider) {
app.run( function (bridgeService) { app.run( function (bridgeService) {
bridgeService.loadBridgeSettings(); bridgeService.loadBridgeSettings();
bridgeService.updateShowVera();
}); });
app.factory('BridgeSettings', function() { app.factory('BridgeSettings', function() {
@@ -72,10 +73,10 @@ app.factory('BridgeSettings', function() {
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", devices: [], device: [], error: "", showVera: false};
this.viewDevices = function () { this.viewDevices = function () {
this.state.error = ""; this.state.error = "";
@@ -107,20 +108,34 @@ app.service('bridgeService', function ($http, BridgeSettings) {
self.BridgeSettings.settraceupnp(response.data.traceupnp); self.BridgeSettings.settraceupnp(response.data.traceupnp);
self.BridgeSettings.setupnpstrict(response.data.upnpstrict); self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
self.BridgeSettings.setvtwocompatibility(response.data.vtwocompatibility); self.BridgeSettings.setvtwocompatibility(response.data.vtwocompatibility);
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
self.state.showVera = false;
else
self.state.showVera = 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.viewVeraDevices = function () { this.viewVeraDevices = function () {
this.state.error = "";
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
return;
this.state.error = ""; this.state.error = "";
return $http.get(this.state.base + "/vera/devices").then( return $http.get(this.state.base + "/vera/devices").then(
function (response) { function (response) {
@@ -128,35 +143,33 @@ 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(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
return;
return $http.get(this.state.base + "/vera/scenes").then( return $http.get(this.state.base + "/vera/scenes").then(
function (response) { function (response) {
self.state.verascenes = response.data; self.state.verascenes = response.data;
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Get Vera Scenes Error: " + error.data.message);
} else { } else {
self.state.error = "If you're not seeing any address, you may be running into problems with CORS. " + $window.alert("Get Vera Scenes Error: unknown");
"You can work around this by running a fresh launch of Chrome with the --disable-web-security flag.";
} }
console.log(error);
} }
); );
}; };
this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody) { this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
this.state.error = ""; this.state.error = "";
if (id) { if (id) {
var putUrl = this.state.base + "/" + id; var putUrl = this.state.base + "/" + id;
@@ -168,19 +181,22 @@ app.service('bridgeService', function ($http, BridgeSettings) {
offUrl: offUrl, offUrl: offUrl,
httpVerb: httpVerb, httpVerb: httpVerb,
contentType: contentType, contentType: contentType,
contentBody: contentBody contentBody: contentBody,
contentBodyOff: contentBodyOff
}).then( }).then(
function (response) { function (response) {
self.viewDevices(); self.viewDevices();
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Edit Device Error: " + error.data.message);
} }
console.log(error); $window.alert("Edit Device Error: unknown");
} }
); );
} else { } else {
if(type == null || type == "")
type = "switch";
return $http.post(this.state.base, { return $http.post(this.state.base, {
name: name, name: name,
deviceType: type, deviceType: type,
@@ -188,16 +204,17 @@ app.service('bridgeService', function ($http, BridgeSettings) {
offUrl: offUrl, offUrl: offUrl,
httpVerb: httpVerb, httpVerb: httpVerb,
contentType: contentType, contentType: contentType,
contentBody: contentBody contentBody: contentBody,
contentBodyOff: contentBodyOff
}).then( }).then(
function (response) { function (response) {
self.viewDevices(); self.viewDevices();
}, },
function (error) { function (error) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; $window.alert("Add new Device Error: " + error.data.message);
} }
console.log(error); $window.alert("Add new Device Error: unknown");
} }
); );
} }
@@ -213,21 +230,22 @@ app.service('bridgeService', function ($http, BridgeSettings) {
if (error.data) { if (error.data) {
self.state.error = error.data.message; self.state.error = error.data.message;
} }
console.log(error); $window.alert("Delete Device Error: unknown");
} }
); );
}; };
this.editDevice = function (id, name, onUrl, offUrl, httpVerb, contentType, contentBody) { this.editDevice = function (id, name, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl, httpVerb: httpVerb, contentType: contentType, contentBody: contentBody}; self.state.device = {id: id, name: name, onUrl: onUrl, offUrl: offUrl, httpVerb: httpVerb, contentType: contentType, contentBody: contentBody, contentBodyOff: contentBodyOff};
}; };
}); });
app.controller('ViewingController', function ($scope, $location, bridgeService, BridgeSettings) { app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, BridgeSettings) {
$scope.BridgeSettings = bridgeService.BridgeSettings; $scope.BridgeSettings = bridgeService.BridgeSettings;
bridgeService.viewDevices(); bridgeService.viewDevices();
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
bridgeService.updateShowVera();
$scope.predicate = ''; $scope.predicate = '';
$scope.reverse = true; $scope.reverse = true;
$scope.order = function(predicate) { $scope.order = function(predicate) {
@@ -237,20 +255,63 @@ app.controller('ViewingController', function ($scope, $location, bridgeService,
$scope.deleteDevice = function (device) { $scope.deleteDevice = function (device) {
bridgeService.deleteDevice(device.id); bridgeService.deleteDevice(device.id);
}; };
$scope.testUrl = function (url) { $scope.testUrl = function (device, type) {
window.open(url, "_blank"); if(type == "on") {
if(device.httpVerb == "PUT")
$http.put(device.onUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else if(device.httpVerb == "POST")
$http.post(device.onUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else
window.open(device.onUrl, "_blank");
}
else {
if(device.httpVerb == "PUT")
$http.put(device.offUrl, device.contentBodyOff).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else if(device.httpVerb == "POST")
$http.post(device.offUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else
window.open(device.offUrl, "_blank");
}
}; };
$scope.setBridgeUrl = function (url) { $scope.setBridgeUrl = function (url) {
bridgeService.state.base = url; bridgeService.state.base = url;
bridgeService.viewDevices(); bridgeService.viewDevices();
}; };
$scope.editDevice = function (device) { $scope.editDevice = function (device) {
bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl, device.httpVerb, device.contentType, device.contentBody); bridgeService.editDevice(device.id, device.name, device.onUrl, device.offUrl, device.httpVerb, device.contentType, device.contentBody, device.contentBodyOff);
$location.path('/editdevice'); $location.path('/editdevice');
}; };
}); });
app.controller('AddingController', function ($scope, $location, bridgeService, BridgeSettings) { app.controller('AddingController', function ($scope, $location, $http, bridgeService, BridgeSettings) {
$scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""}; $scope.device = {id: "", name: "", deviceType: "switch", onUrl: "", offUrl: ""};
$scope.vera = {base: "", port: "3480", id: ""}; $scope.vera = {base: "", port: "3480", id: ""};
@@ -259,21 +320,30 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
bridgeService.viewVeraDevices(); bridgeService.viewVeraDevices();
bridgeService.viewVeraScenes(); bridgeService.viewVeraScenes();
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
bridgeService.updateShowVera();
$scope.device = bridgeService.state.device; $scope.device = bridgeService.state.device;
$scope.predicate = ''; $scope.predicate = '';
$scope.reverse = true; $scope.reverse = true;
$scope.device_dim_control = "";
$scope.order = function(predicate) { $scope.order = function(predicate) {
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false; $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.predicate = predicate; $scope.predicate = predicate;
}; };
$scope.buildUrlsUsingDevice = function () { $scope.buildUrlsUsingDevice = function (dim_control) {
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" $scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ $scope.vera.id; + "/data_request?id=action&output_format=json&DeviceNum="
+ $scope.vera.id
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
+ dim_control;
else
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
+ $scope.vera.id;
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
+ $scope.vera.id; + $scope.vera.id;
@@ -292,15 +362,22 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
+ $scope.vera.id; + $scope.vera.id;
}; };
$scope.buildDeviceUrls = function (veradevice) { $scope.buildDeviceUrls = function (veradevice, dim_control) {
if ($scope.vera.base.indexOf("http") < 0) { if ($scope.vera.base.indexOf("http") < 0) {
$scope.vera.base = "http://" + $scope.vera.base; $scope.vera.base = "http://" + $scope.vera.base;
} }
$scope.device.deviceType = "switch"; $scope.device.deviceType = "switch";
$scope.device.name = veradevice.name; $scope.device.name = veradevice.name;
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" $scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ veradevice.id; + "/data_request?id=action&output_format=json&DeviceNum="
+ veradevice.id
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
+ dim_control;
else
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
+ veradevice.id;
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port $scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
+ veradevice.id; + veradevice.id;
@@ -321,11 +398,54 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
}; };
$scope.testUrl = function (url) { $scope.testUrl = function (url) {
window.open(url, "_blank"); if(type == "on") {
if(device.httpVerb == "PUT")
$http.put(device.onUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else if(device.httpVerb == "POST")
$http.post(device.onUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else
window.open(device.onUrl, "_blank");
}
else {
if(device.httpVerb == "PUT")
$http.put(device.offUrl, device.contentBodyOff).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else if(device.httpVerb == "POST")
$http.post(device.offUrl, device.contentBody).then(
function (response) {
$window.alert("Request Exceuted: " + response.statusText);
},
function (error) {
$window.alert("Request Error: " + error.data.message);
}
);
else
window.open(device.offUrl, "_blank");
}
}; };
$scope.addDevice = function () { $scope.addDevice = function () {
bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl, $scope.device.httpVerb, $scope.device.contentType, $scope.device.contentBody).then( bridgeService.addDevice($scope.device.id, $scope.device.name, $scope.device.deviceType, $scope.device.onUrl, $scope.device.offUrl, $scope.device.httpVerb, $scope.device.contentType, $scope.device.contentBody, $scope.device.contentBodyOff).then(
function () { function () {
$scope.device.id = ""; $scope.device.id = "";
$scope.device.name = ""; $scope.device.name = "";
@@ -335,6 +455,7 @@ app.controller('AddingController', function ($scope, $location, bridgeService, B
$scope.device.httpVerb = null; $scope.device.httpVerb = null;
$scope.device.contentType = null; $scope.device.contentType = null;
$scope.device.contentBody = null; $scope.device.contentBody = null;
$scope.device.contentBodyOff = null;
$location.path('/#'); $location.path('/#');
}, },
function (error) { function (error) {

View File

@@ -1,7 +1,7 @@
<ul class="nav nav-pills" role="tablist"> <ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#">Configuration</a></li> <li role="presentation" class="active"><a href="#">Configuration</a></li>
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li> <li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul> </ul>
@@ -107,9 +107,9 @@
<td>{{device.deviceType}}</td> <td>{{device.deviceType}}</td>
<td> <td>
<button class="btn btn-info" type="submit" <button class="btn btn-info" type="submit"
ng-click="testUrl(device.onUrl)">Test ON</button> ng-click="testUrl(device, 'on')">Test ON</button>
<button class="btn btn-info" type="submit" <button class="btn btn-info" type="submit"
ng-click="testUrl(device.offUrl)">Test OFF</button> ng-click="testUrl(device, 'off')">Test OFF</button>
<button class="btn btn-warning" type="submit" <button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button> ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit" <button class="btn btn-danger" type="submit"

View File

@@ -1,7 +1,7 @@
<ul class="nav nav-pills" role="tablist"> <ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Configuration</a></li> <li role="presentation"><a href="#">Configuration</a></li>
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li> <li role="presentation"><a href="#/editor">Manual Add</a></li>
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li> <li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
</ul> </ul>
@@ -35,7 +35,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button> ng-click="testUrl(device, 'on')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -49,7 +49,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button> ng-click="testUrl(device, 'off')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -58,30 +58,60 @@
</label> </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-http-verb" <select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
ng-model="device.httpVerb" placeholder="Http Verb, i.e. GET/PUT/POST"> <option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Name <label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
</label> </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-content-type" <select name="device-content-type" id="device-content-type" ng-model="device.contentType">
ng-model="device.contentType" placeholder="Content type, i.e. application/json"> <option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-content-body">Content Body </label> for="device-content-body">Content Body On</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body" <textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body for specific GET/PUT/POST type"></textarea> ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>

View File

@@ -1,7 +1,7 @@
<ul class="nav nav-pills" role="tablist"> <ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Configuration</a></li> <li role="presentation"><a href="#">Configuration</a></li>
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li> <li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li> <li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
</ul> </ul>
@@ -44,7 +44,19 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" ng-click="buildUrlsUsingDevice()" <label class="col-xs-2 col-sm-2 control-label" for="device-dim-control">Device Dim Control</label>
<div class="col-xs-10 col-sm-2">
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity..byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</div>
</div>
<div class="form-group">
<button type="submit" ng-click="buildUrlsUsingDevice(device_dim_control)"
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device
URLs</button> URLs</button>
<button type="submit" ng-click="buildUrlsUsingScene()" <button type="submit" ng-click="buildUrlsUsingScene()"
@@ -86,7 +98,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button> ng-click="testUrl(device, 'on')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -100,7 +112,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button> ng-click="testUrl(device, 'off')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -109,30 +121,60 @@
</label> </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-http-verb" <select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
ng-model="device.httpVerb" placeholder="Http Verb, i.e. GET/PUT/POST"> <option value="">---Please select---</option> <!-- not selected / blank option -->
</div> <option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select>
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Name <label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
</label> </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-content-type" <select name="device-content-type" id="device-content-type" ng-model="device.contentType">
ng-model="device.contentType" placeholder="Content type, i.e. application/json"> <option value="">---Please select---</option> <!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" <label class="col-xs-12 col-sm-2 control-label"
for="device-content-body">Content Body </label> for="device-content-body">Content Body On</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body" <textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body for specific GET/PUT/POST type"></textarea> ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>

View File

@@ -12,8 +12,15 @@
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">
<p class="text-muted">You can select a Vera device and generate <p class="text-muted">You can select a Vera device and generate
the add device box selections automatically.</p> the add device box selections automatically.</p><p>Also, use this select menu for which type of dim
control you would like to be generated:
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity..byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -43,7 +50,7 @@
<td>{{veradevice.room}}</td> <td>{{veradevice.room}}</td>
<td> <td>
<button class="btn btn-success" type="submit" <button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(veradevice)">Generate ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
Device URLs</button> Device URLs</button>
</td> </td>
</tr> </tr>
@@ -80,7 +87,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button> ng-click="testUrl(device, 'on')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -94,7 +101,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button> ng-click="testUrl(device, 'off')">Test</button>
</div> </div>
</div> </div>
</form> </form>

View File

@@ -75,7 +75,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.onUrl)">Test</button> ng-click="testUrl(device, 'on')">Test</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -89,7 +89,7 @@
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
<button class="col-xs-4 col-sm-2 btn btn-success" type="button" <button class="col-xs-4 col-sm-2 btn btn-success" type="button"
ng-click="testUrl(device.offUrl)">Test</button> ng-click="testUrl(device, 'off')">Test</button>
</div> </div>
</div> </div>
</form> </form>

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() {
}
}