mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 08:13:23 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a59747bc9 | ||
|
|
53ec096c95 | ||
|
|
8ccb768391 | ||
|
|
9d84e2a180 | ||
|
|
6a5fae583f | ||
|
|
8d15d0a0fb | ||
|
|
d4b8b70a83 | ||
|
|
a276f97776 | ||
|
|
9438b25538 | ||
|
|
6c15ca2c3b | ||
|
|
39782fa339 | ||
|
|
d7e29e2ee5 | ||
|
|
6b4693eaaf | ||
|
|
7f816b03d5 | ||
|
|
ed3db4427b | ||
|
|
80ca8c3ca3 | ||
|
|
e43473734e | ||
|
|
8a468b8352 | ||
|
|
51ce10cfc7 | ||
|
|
b5f7144c9c | ||
|
|
86a931d383 | ||
|
|
3e890721c5 | ||
|
|
62d1c64a3d | ||
|
|
c025b186cd | ||
|
|
e999c3a969 | ||
|
|
351403e611 | ||
|
|
c773477a43 | ||
|
|
5d1f0ce3b6 | ||
|
|
7e0fd6c21b | ||
|
|
3bf52f5da0 | ||
|
|
bd856d8f9e | ||
|
|
73b2be752e | ||
|
|
dda7a7a34a | ||
|
|
9a1924422e |
87
README.md
87
README.md
@@ -21,10 +21,10 @@ Then locate the jar and start the server with:
|
||||
ATTENTION: This requires JDK 1.8 to run
|
||||
|
||||
```
|
||||
java -jar ha-bridge-W.X.Y.jar
|
||||
java -jar ha-bridge-2.5.0.jar
|
||||
```
|
||||
### Automation on Linux systems
|
||||
To have this conigured and running automatically ther eare a few resources to use. One is using Docker and a docker containerahs been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
|
||||
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
|
||||
|
||||
For next gen Linux systems, here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
|
||||
```
|
||||
@@ -35,11 +35,43 @@ After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.0.0.jar
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.5.0.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Basic script setup to run the bridge on a pi.
|
||||
|
||||
Create the directory and make sure that ha-bridge-2.5.0.jar is in your /home/pi/habridge directory.
|
||||
```
|
||||
pi@raspberrypi:~ $ mkdir habridge
|
||||
pi@raspberrypi:~ $ cd habridge
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v2.0.6/ha-bridge-2.5.0.jar
|
||||
```
|
||||
Edit the shell script for starting:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ nano starthabridge.sh
|
||||
```
|
||||
Then cut and past this, modify any locations that are not correct
|
||||
```
|
||||
cd /home/pi/habridge
|
||||
rm /home/pi/habridge/habridge-log.txt
|
||||
nohup java -jar /home/pi/habridge/ha-bridge-2.5.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
chmod 777 /home/pi/habridge/habridge-log.txt
|
||||
```
|
||||
Exit and save the file with ctrl-X and follow the prompts and then execute on the command line:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ chmod u+x starthabridge.sh
|
||||
```
|
||||
Then execute the script:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ ./starthabridge.sh
|
||||
```
|
||||
You should now be running the bridge. Check for errors:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ tail -f habridge-log.txt
|
||||
```
|
||||
## Available Arguments
|
||||
Arguments are now deprecated. The ha-bridge will use the old -D arguments and populate the configuration screen, Brisge Control Tab, which can now be saved to a file and will not be needed. There is only one optional argument that overrides and that is the location of the configuration file. The default is the relative path "data/habridge.config".
|
||||
### -Dconfig.file=`<filepath>`
|
||||
@@ -73,11 +105,11 @@ The default location for the db to contain the devices as they are added is "dat
|
||||
#### UPNP IP Address
|
||||
The server defaults to the first available address on the host if this is not given. This default may NOT be the correct IP that is your public IP for your host on the network. It is best to set this parameter to not have discovery issues. Replace this value with the server ipv4 address you would like to use as the address that any upnp device will call after discovery.
|
||||
#### Web Server Port
|
||||
The server defaults to running on port 8080. To override what the default is, specify a different number.
|
||||
The server defaults to running on port 8080. To override what the default is, specify a different number. ATTENTION: If you want to use any of the apps made for the Hue to control this bridge, you should set this port to 80.
|
||||
#### UPNP Response Port
|
||||
The upnp response port that will be used. The default is 50000.
|
||||
#### Vera Names and IP Addresses
|
||||
Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and devce/scene you configure.
|
||||
Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and device/scene you configure.
|
||||
#### Harmony Names and IP Addresses
|
||||
Provide IP Addresses of your Harmony Hubs that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the activity or buttons by the call it receives and send it to the target Harmony Hub and activity/button you configure.
|
||||
#### Harmony Username
|
||||
@@ -86,6 +118,12 @@ The user name of the MyHarmony.com account for the Harmony Hub. This needs to be
|
||||
The password for the user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub Features.
|
||||
#### Hue Names and IP Addresses
|
||||
Provide IP Addresses of your Hue Bridges that you want to proxy through the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will passthru the call it receives to the target Hue and device you configure.
|
||||
|
||||
Don't forget - You will need to push the link button when you got to the Hue Tab the first time ater the process comes up. (The user name is not persistent when the process comes up.)
|
||||
#### HAL Names and IP Addresses
|
||||
Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure.
|
||||
#### HAL Token
|
||||
The token you generate or give to a HAL and must be the same for all HAL's you have identified. This needs to be given if you are using the HAL features.
|
||||
#### Nest Username
|
||||
The user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account.
|
||||
#### Nest Password
|
||||
@@ -105,9 +143,9 @@ At the bottom of the screen is the "Bridge Settings Backup" which can be accesse
|
||||
### The Logs Tab
|
||||
This screen displays the last 512 or number of rows defined in the config screen of the log so you don't have to go to the output of your process. The `Update Log` button refreshes the log as this screen does not auto refresh. FYI, when the trace upnp setting is turned on in the configuration, the messages will show here.
|
||||
|
||||
The bottom part of the Logs Screen has configuration to change the logging levels as it is running. The ROOT is the basic setting and will turn on only top level logging. To set logging at a lower level, select the `Show All Loggers` checkbox and then you can set the explicit level on each of the processes components. The most helpful logger would be setting DBUG for com.bwssystems.HABridge.hue.HueMulator component. Changing this and then selecting the `Update Log Levels` button applies the new log settings.
|
||||
The bottom part of the Logs Screen has configuration to change the logging levels as it is running. The ROOT is the basic setting and will turn on only top level logging. To set logging at a lower level, select the `Show All Loggers` checkbox and then you can set the explicit level on each of the processes components. The most helpful logger would be setting DEBUG for com.bwssystems.HABridge.hue.HueMulator component. Changing this and then selecting the `Update Log Levels` button applies the new log settings.
|
||||
### Bridge Device Additions
|
||||
You must configure devices before you will have any thing for the Echo or other contoller that is connected to the ha-bridge to receive.
|
||||
You must configure devices before you will have any thing for the Echo or other controller that is connected to the ha-bridge to receive.
|
||||
#### Helpers
|
||||
The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest and Hue to create devices that the bridge will present.
|
||||
|
||||
@@ -117,7 +155,7 @@ The helper tabs will also show you what you have already configured for that tar
|
||||
#### The Manual Add Tab
|
||||
Another way to add a device is through the Manual Add Tab. This allows you to manually enter the name, the on and off URLs and select if there are custom handling with the type of call that can be made. This allows for control of anything that has a distinct request that can be executed so you are not limited to the Vera, Harmony, Nest or other Hue.
|
||||
|
||||
The format of these can be the default HTTP request which executes the URLs formatted as http://<your stuff here> as a GET. Other options to this are to select the HTTP Verb and add the data type and add a body that is passed with the request. Secure https is supported as well, just use https://<your secure call here>. When using POST and PUT, you have the ability to specify the body that will be sent with the request as well as the application type for the http call.
|
||||
The format of these can be the default HTTP request which executes the URLs formatted as `http://<your stuff here>` as a GET. Other options to this are to select the HTTP Verb and add the data type and add a body that is passed with the request. Secure https is supported as well, just use `https://<your secure call here>`. When using POST and PUT, you have the ability to specify the body that will be sent with the request as well as the application type for the http call.
|
||||
|
||||
Headers can be added as well using a Json construct [{"name":"header type name","value":"the header value"}] with the format example:
|
||||
```
|
||||
@@ -125,7 +163,7 @@ Headers can be added as well using a Json construct [{"name":"header type name",
|
||||
{"name":"Pragma","value":"no-cache"}]
|
||||
```
|
||||
|
||||
Another option that is detected by the bridge is to use UDP or TCP direct calls such as udp://<ip_address>:<port>/<your stuff here> to send a UDP request. TCP calls are handled the same way as tcp://<ip_address>:<port>/<your stuff here>. If your data for the UDP or TCP request is formatted as "0x00F009B9" lexical hex format, the bridge will convert the data into a binary stream to send.
|
||||
Another option that is detected by the bridge is to use UDP or TCP direct calls such as `udp://<ip_address>:<port>/<your stuff here>` to send a UDP request. TCP calls are handled the same way as `tcp://<ip_address>:<port>/<your stuff here>`. If your data for the UDP or TCP request is formatted as "0x00F009B9" lexical hex format, the bridge will convert the data into a binary stream to send.
|
||||
|
||||
You can also use the value replacement constructs within these statements. Such as using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}".
|
||||
Examples:
|
||||
@@ -138,10 +176,18 @@ http://192.168.1.1:8280/set/this
|
||||
ContentBody: {"someValue":"${intensity..byte}"}
|
||||
|
||||
udp://192.168.1.1:5000/0x45${intensity.percent}55
|
||||
|
||||
udp://192.168.2.2:6000/fireoffthismessage\n
|
||||
|
||||
tcp://192.168.3.3:9000/sendthismessage
|
||||
|
||||
tcp://192.168.4.4:10000/0x435f12dd${intensity.math((X -4)*50)}438c
|
||||
|
||||
tcp://192.168.5.5:110000/0x
|
||||
```
|
||||
|
||||
#### Multiple Call Construct
|
||||
Also available is the ability to specify multiple commands in the On URL, Dim URL and Off URL areas by adding Json constructs listed here.
|
||||
Also available is the ability to specify multiple commands in the On URL, Dim URL and Off URL areas by adding Json constructs listed here. This is only for the types of tcp, udp, http, https or a new exec type.
|
||||
Format Example in the URL areas:
|
||||
```
|
||||
[{"item":"http://192.168.1.1:8180/do/this/thing"},
|
||||
@@ -155,10 +201,11 @@ Format Example in the URL areas:
|
||||
[{"item":"udp://192.168.1.1:5000/0x450555"},
|
||||
{"item":"http://192.168.1.1:8180/do/this/thing"},
|
||||
{"item":"tcp://192.168.2.1/sendthisdata"},
|
||||
{"item":"https://192.168.12.1/do/this/secure/thing"}]
|
||||
{"item":"https://192.168.12.1/do/this/secure/thing"},
|
||||
{"item":"exec://notepad.exe"}]
|
||||
```
|
||||
#### Script or Command Execution
|
||||
The release as of v2.0.0 will no support the execution of a local script or program. This will blindly fire off a process to run and is bound by the privileges of the java process.
|
||||
The release as of v2.0.0 will now support the execution of a local script or program. This will blindly fire off a process to run and is bound by the privileges of the java process.
|
||||
|
||||
To configure this type of manual add, you will need to select the Device type of "Execute Script/Program".
|
||||
|
||||
@@ -175,6 +222,10 @@ OR
|
||||
|
||||
/home/me/startsomething.sh
|
||||
|
||||
OR
|
||||
|
||||
[{"item":"exec://notepad.exe"}]
|
||||
|
||||
```
|
||||
|
||||
Also, you may want to use the REST API's listed below to configure your devices.
|
||||
@@ -207,13 +258,15 @@ OFF Commands |
|
||||
DIM Commands |
|
||||
| Alexa, brighten `<Device Name>` to `<Position>`
|
||||
| Alexa, dim `<Device Name> to <Position>`
|
||||
| Alexa, brighten `<Device Name>`
|
||||
| Alexa, dim `<Device Name>`
|
||||
| Alexa, raise `<Device Name>` to `<Position>`
|
||||
| Alexa, lower `<Device Name>` to `<Position>`
|
||||
| Alexa, set `<Device Name>` to `<Position>`
|
||||
| Alexa, turn up `<Device Name>` to `<Position>`
|
||||
| Alexa, turn down `<Device Name>` to `<Position>`
|
||||
|
||||
To see what Alexa thinks you said, you can check in the home page for your alexa.
|
||||
To see what Alexa thinks you said, you can check in the home page for your Alexa.
|
||||
|
||||
To view or remove devices that Alexa knows about, you can use the mobile app `Menu / Settings / Connected Home` or go to http://echo.amazon.com/#cards.
|
||||
## Configuration REST API Usage
|
||||
@@ -254,7 +307,7 @@ contentBodyOff | string | This is the content body that you would like to send w
|
||||
}
|
||||
```
|
||||
#### Dimming Control Example
|
||||
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass trhough of the value.
|
||||
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value.
|
||||
e.g.
|
||||
```
|
||||
{
|
||||
@@ -862,7 +915,7 @@ rules | object | A collection of all rules and their attributes. This is not giv
|
||||
## UPNP Emulation of HUE
|
||||
This section will discuss the UPNP implementation of this bridge based as much as can be for the HUE.
|
||||
### UPNP listening
|
||||
The HA Bridge default UPNP listner is started on port 1900 on the upnp multicast address of 239.255.255.250. All ethernet interfaces that are active are bound to and the repsonse port is set to the one given on the command line above or the default of 50000.
|
||||
The HA Bridge default UPNP listener is started on port 1900 on the upnp multicast address of 239.255.255.250. All ethernet interfaces that are active are bound to and the response port is set to the one given on the command line above or the default of 50000.
|
||||
|
||||
The listener will respond to the following body packet that contain the following minimal information:
|
||||
|
||||
@@ -888,7 +941,7 @@ ST: urn:schemas-upnp-org:device:basic:1\r\n
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n
|
||||
```
|
||||
### UPNP description service
|
||||
The bridge provides the description service which is used by the calling app to interogate access details after it has decided the upnp multicast repsonse is the correct device.
|
||||
The bridge provides the description service which is used by the calling app to interogate access details after it has decided the upnp multicast response is the correct device.
|
||||
#### Get Description
|
||||
```
|
||||
GET http://host:8080/description.xml
|
||||
@@ -951,4 +1004,4 @@ To turn on debugging for the bridge, use the following extra parm in the command
|
||||
To turn on development mode so that it will not need an Harmony Hub for testing, use the following extra parm in the command line and the harmony ip and login info will not be needed:
|
||||
```
|
||||
java -jar -Ddev.mode=true ha-bridge-0.X.Y.jar
|
||||
```
|
||||
```
|
||||
|
||||
14
pom.xml
14
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<version>3.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
@@ -89,18 +89,8 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.2.4</version>
|
||||
<version>2.6.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cedarsoftware</groupId>
|
||||
<artifactId>json-io</artifactId>
|
||||
<version>4.1.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.eval</groupId>
|
||||
<artifactId>eval</artifactId>
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.bwssystems.util.JsonTransformer;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class BridgeSettings extends BackupHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
private BridgeSettingsDescriptor theBridgeSettings;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
|
||||
@@ -35,7 +36,6 @@ public class BridgeSettings extends BackupHandler {
|
||||
return theBridgeSettings;
|
||||
}
|
||||
public void buildSettings() {
|
||||
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
InetAddress address = null;
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
@@ -146,15 +146,22 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
||||
|
||||
if(theBridgeSettings.getNumberoflogmessages() == null)
|
||||
theBridgeSettings.setNumberoflogmessages(Configuration.NUMBER_OF_LOG_MESSAGES);
|
||||
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||
|
||||
if(theBridgeSettings.getNumberoflogmessages() <= 0)
|
||||
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||
|
||||
if(theBridgeSettings.getButtonsleep() == null)
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||
|
||||
if(theBridgeSettings.getButtonsleep() <= 0)
|
||||
if(theBridgeSettings.getButtonsleep() < 0)
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||
|
||||
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
||||
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
||||
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
||||
theBridgeSettings.setHalconfigured(theBridgeSettings.isValidHal());
|
||||
if(serverPortOverride != null)
|
||||
theBridgeSettings.setServerPort(serverPortOverride);
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
@@ -171,31 +178,17 @@ public class BridgeSettings extends BackupHandler {
|
||||
|
||||
private void _loadConfig(Path aPath) {
|
||||
String jsonContent = configReader(aPath);
|
||||
BridgeSettingsDescriptor aBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
|
||||
theBridgeSettings.setButtonsleep(aBridgeSettings.getButtonsleep());
|
||||
theBridgeSettings.setUpnpConfigAddress(aBridgeSettings.getUpnpConfigAddress());
|
||||
theBridgeSettings.setServerPort(aBridgeSettings.getServerPort());
|
||||
theBridgeSettings.setUpnpResponsePort(aBridgeSettings.getUpnpResponsePort());
|
||||
theBridgeSettings.setUpnpDeviceDb(aBridgeSettings.getUpnpDeviceDb());
|
||||
theBridgeSettings.setVeraAddress(aBridgeSettings.getVeraAddress());
|
||||
theBridgeSettings.setHarmonyAddress(aBridgeSettings.getHarmonyAddress());
|
||||
theBridgeSettings.setHarmonyUser(aBridgeSettings.getHarmonyUser());
|
||||
theBridgeSettings.setHarmonyPwd(aBridgeSettings.getHarmonyPwd());
|
||||
theBridgeSettings.setUpnpStrict(aBridgeSettings.isUpnpStrict());
|
||||
theBridgeSettings.setTraceupnp(aBridgeSettings.isTraceupnp());
|
||||
theBridgeSettings.setNestuser(aBridgeSettings.getNestuser());
|
||||
theBridgeSettings.setNestpwd(aBridgeSettings.getNestpwd());
|
||||
theBridgeSettings.setVeraconfigured(aBridgeSettings.isValidVera());
|
||||
theBridgeSettings.setHarmonyconfigured(aBridgeSettings.isValidHarmony());
|
||||
theBridgeSettings.setNestConfigured(aBridgeSettings.isValidNest());
|
||||
theBridgeSettings.setNumberoflogmessages(aBridgeSettings.getNumberoflogmessages());
|
||||
theBridgeSettings.setFarenheit(aBridgeSettings.isFarenheit());
|
||||
theBridgeSettings.setHueaddress(aBridgeSettings.getHueaddress());
|
||||
theBridgeSettings.setHueconfigured(aBridgeSettings.isValidHue());
|
||||
try {
|
||||
theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
|
||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||
theBridgeSettings.setConfigfile(aPath.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void save(BridgeSettingsDescriptor newBridgeSettings) {
|
||||
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
log.debug("Save HA Bridge settings.");
|
||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
@@ -206,7 +199,6 @@ public class BridgeSettings extends BackupHandler {
|
||||
|
||||
|
||||
private void configWriter(String content, Path filePath) {
|
||||
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||
log.error("Error file is not writable: " + filePath);
|
||||
return;
|
||||
@@ -235,8 +227,6 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
|
||||
private String configReader(Path filePath) {
|
||||
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
|
||||
String content = null;
|
||||
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
||||
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
|
||||
public class BridgeSettingsDescriptor {
|
||||
private String upnpconfigaddress;
|
||||
@@ -24,6 +27,11 @@ public class BridgeSettingsDescriptor {
|
||||
private Integer numberoflogmessages;
|
||||
private IpList hueaddress;
|
||||
private boolean hueconfigured;
|
||||
private IpList haladdress;
|
||||
private String haltoken;
|
||||
private boolean halconfigured;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
private boolean settingsChanged;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
@@ -33,7 +41,10 @@ public class BridgeSettingsDescriptor {
|
||||
this.veraconfigured = false;
|
||||
this.harmonyconfigured = false;
|
||||
this.hueconfigured = false;
|
||||
this.halconfigured = false;
|
||||
this.farenheit = true;
|
||||
this.whitelist = null;
|
||||
this.settingsChanged = false;
|
||||
}
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
@@ -167,6 +178,36 @@ public class BridgeSettingsDescriptor {
|
||||
public void setHueconfigured(boolean hueconfigured) {
|
||||
this.hueconfigured = hueconfigured;
|
||||
}
|
||||
public IpList getHaladdress() {
|
||||
return haladdress;
|
||||
}
|
||||
public void setHaladdress(IpList haladdress) {
|
||||
this.haladdress = haladdress;
|
||||
}
|
||||
public String getHaltoken() {
|
||||
return haltoken;
|
||||
}
|
||||
public void setHaltoken(String haltoken) {
|
||||
this.haltoken = haltoken;
|
||||
}
|
||||
public boolean isHalconfigured() {
|
||||
return halconfigured;
|
||||
}
|
||||
public void setHalconfigured(boolean halconfigured) {
|
||||
this.halconfigured = halconfigured;
|
||||
}
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
}
|
||||
public boolean isSettingsChanged() {
|
||||
return settingsChanged;
|
||||
}
|
||||
public void setSettingsChanged(boolean settingsChanged) {
|
||||
this.settingsChanged = settingsChanged;
|
||||
}
|
||||
public Boolean isValidVera() {
|
||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
@@ -202,4 +243,14 @@ public class BridgeSettingsDescriptor {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public Boolean isValidHal() {
|
||||
if(this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getHaladdress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.bwssystems.HABridge.hue.HueMulator;
|
||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||
import com.bwssystems.NestBridge.NestHome;
|
||||
import com.bwssystems.hal.HalHome;
|
||||
import com.bwssystems.harmony.HarmonyHome;
|
||||
import com.bwssystems.hue.HueHome;
|
||||
|
||||
@@ -36,6 +37,7 @@ public class HABridge {
|
||||
HarmonyHome harmonyHome;
|
||||
NestHome nestHome;
|
||||
HueHome hueHome;
|
||||
HalHome halHome;
|
||||
HueMulator theHueMulator;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
@@ -66,8 +68,10 @@ public class HABridge {
|
||||
nestHome = new NestHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
//setup the hue passtrhu configuration if available
|
||||
hueHome = new HueHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
//setup the hal configuration if available
|
||||
halHome = new HalHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
// setup the class to handle the resource setup rest api
|
||||
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome);
|
||||
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome);
|
||||
// setup the class to handle the hue emulator rest api
|
||||
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome);
|
||||
theHueMulator.setupServer();
|
||||
@@ -83,7 +87,8 @@ public class HABridge {
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
||||
else
|
||||
bridgeSettings.getBridgeControl().setStop(true);
|
||||
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
bridgeSettings.getBridgeControl().setReinit(false);
|
||||
stop();
|
||||
nestHome.closeTheNest();
|
||||
|
||||
@@ -11,6 +11,7 @@ public class DeviceResponse {
|
||||
private String name;
|
||||
private String modelid;
|
||||
private String manufacturername;
|
||||
private String luminaireuniqueid;
|
||||
private String uniqueid;
|
||||
private String swversion;
|
||||
|
||||
@@ -70,7 +71,15 @@ public class DeviceResponse {
|
||||
this.swversion = swversion;
|
||||
}
|
||||
|
||||
public static DeviceResponse createResponse(DeviceDescriptor device){
|
||||
public String getLuminaireuniqueid() {
|
||||
return luminaireuniqueid;
|
||||
}
|
||||
|
||||
public void setLuminaireuniqueid(String luminaireuniqueid) {
|
||||
this.luminaireuniqueid = luminaireuniqueid;
|
||||
}
|
||||
|
||||
public static DeviceResponse createResponse(DeviceDescriptor device){
|
||||
DeviceResponse response = new DeviceResponse();
|
||||
response.setState(device.getDeviceState());
|
||||
|
||||
@@ -80,6 +89,7 @@ public class DeviceResponse {
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB004");
|
||||
response.setSwversion("66012040");
|
||||
response.setLuminaireuniqueid(null);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
// import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class DeviceTypes {
|
||||
private Boolean bridge;
|
||||
private String[] lights;
|
||||
public Boolean getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
public void setBridge(Boolean bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
public String[] getLights() {
|
||||
return lights;
|
||||
}
|
||||
public void setLights(String[] lights) {
|
||||
this.lights = lights;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class GroupResponse {
|
||||
private DeviceState action;
|
||||
private String[] lights;
|
||||
private String name;
|
||||
public DeviceState getAction() {
|
||||
return action;
|
||||
}
|
||||
public void setAction(DeviceState action) {
|
||||
this.action = action;
|
||||
}
|
||||
public String[] getLights() {
|
||||
return lights;
|
||||
}
|
||||
public void setLights(String[] lights) {
|
||||
this.lights = lights;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static GroupResponse createGroupResponse(String[] theLights) {
|
||||
GroupResponse theResponse = new GroupResponse();
|
||||
theResponse.setAction(DeviceState.createDeviceState());
|
||||
theResponse.setName("Lightset 0");
|
||||
theResponse.setLights(theLights);
|
||||
return theResponse;
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ public class HueApiResponse {
|
||||
private Map<String, JsonObject> rules;
|
||||
private HueConfig config;
|
||||
|
||||
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
||||
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
|
||||
super();
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid));
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist));
|
||||
this.setRules(new HashMap<>());
|
||||
this.setSensors(new HashMap<>());
|
||||
this.setSchedules(new HashMap<>());
|
||||
|
||||
@@ -6,7 +6,6 @@ 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;
|
||||
|
||||
@@ -29,18 +28,22 @@ public class HueConfig
|
||||
private String localtime;
|
||||
private String timezone;
|
||||
private String zigbeechannel;
|
||||
private String modelid;
|
||||
private String bridgeid;
|
||||
private Boolean factorynew;
|
||||
private String replacesbridgeid;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
|
||||
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) {
|
||||
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
|
||||
HueConfig aConfig = new HueConfig();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
aConfig.setMac(HueConfig.getMacAddress(ipaddress));
|
||||
aConfig.setApiversion("1.4.0");
|
||||
aConfig.setApiversion("1.10.0");
|
||||
aConfig.setPortalservices(false);
|
||||
aConfig.setGateway(ipaddress);
|
||||
aConfig.setSwversion("01005215");
|
||||
aConfig.setSwversion("01028090");
|
||||
aConfig.setLinkbutton(false);
|
||||
aConfig.setIpaddress(ipaddress);
|
||||
aConfig.setProxyport(0);
|
||||
@@ -53,8 +56,10 @@ public class HueConfig
|
||||
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.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
|
||||
aConfig.setModelid("BSB002");
|
||||
aConfig.setFactorynew(false);
|
||||
aConfig.setReplacesbridgeid(null);
|
||||
aConfig.setWhitelist(awhitelist);
|
||||
|
||||
return aConfig;
|
||||
@@ -235,4 +240,36 @@ public class HueConfig
|
||||
public void setZigbeechannel(String zigbeechannel) {
|
||||
this.zigbeechannel = zigbeechannel;
|
||||
}
|
||||
|
||||
public String getModelid() {
|
||||
return modelid;
|
||||
}
|
||||
|
||||
public void setModelid(String modelid) {
|
||||
this.modelid = modelid;
|
||||
}
|
||||
|
||||
public String getBridgeid() {
|
||||
return bridgeid;
|
||||
}
|
||||
|
||||
public void setBridgeid(String bridgeid) {
|
||||
this.bridgeid = bridgeid;
|
||||
}
|
||||
|
||||
public Boolean getFactorynew() {
|
||||
return factorynew;
|
||||
}
|
||||
|
||||
public void setFactorynew(Boolean factorynew) {
|
||||
this.factorynew = factorynew;
|
||||
}
|
||||
|
||||
public String getReplacesbridgeid() {
|
||||
return replacesbridgeid;
|
||||
}
|
||||
|
||||
public void setReplacesbridgeid(String replacesbridgeid) {
|
||||
this.replacesbridgeid = replacesbridgeid;
|
||||
}
|
||||
}
|
||||
|
||||
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueError {
|
||||
|
||||
private HueErrorDetails error;
|
||||
|
||||
public HueError(HueErrorDetails error) {
|
||||
super();
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public HueErrorDetails getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(HueErrorDetails error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueErrorDetails {
|
||||
private String type;
|
||||
private String address;
|
||||
private String description;
|
||||
private String method_name;
|
||||
private String resource_name;
|
||||
private String value;
|
||||
public HueErrorDetails(String type, String address, String description, String method_name, String resource_name,
|
||||
String value) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.description = description;
|
||||
this.method_name = method_name;
|
||||
this.resource_name = resource_name;
|
||||
this.value = value;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public String getMethod_name() {
|
||||
return method_name;
|
||||
}
|
||||
public void setMethod_name(String method_name) {
|
||||
this.method_name = method_name;
|
||||
}
|
||||
public String getResource_name() {
|
||||
return resource_name;
|
||||
}
|
||||
public void setResource_name(String resource_name) {
|
||||
this.resource_name = resource_name;
|
||||
}
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HueErrorResponse {
|
||||
private ArrayList<HueError> theErrors;
|
||||
|
||||
public HueErrorResponse() {
|
||||
super();
|
||||
theErrors = new ArrayList<HueError>();
|
||||
}
|
||||
|
||||
public void addError(HueError anError) {
|
||||
theErrors.add(anError);
|
||||
}
|
||||
|
||||
public HueError[] getTheErrors() {
|
||||
HueError theList[] = new HueError[theErrors.size()];
|
||||
theList = theErrors.toArray(theList);
|
||||
return theList;
|
||||
}
|
||||
|
||||
public void setTheErrors(ArrayList<HueError> theErrors) {
|
||||
this.theErrors = theErrors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
public class HuePublicConfig
|
||||
{
|
||||
private String name;
|
||||
private String apiversion;
|
||||
private String swversion;
|
||||
private String mac;
|
||||
private String bridgeid;
|
||||
private String replacesbridgeid;
|
||||
private Boolean factorynew;
|
||||
private String modelid;
|
||||
|
||||
public static HuePublicConfig createConfig(String name, String ipaddress) {
|
||||
HuePublicConfig aConfig = new HuePublicConfig();
|
||||
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
|
||||
aConfig.setApiversion("1.10.0");
|
||||
aConfig.setSwversion("01028090");
|
||||
aConfig.setName(name);
|
||||
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
|
||||
aConfig.setModelid("BSB002");
|
||||
aConfig.setFactorynew(false);
|
||||
aConfig.setReplacesbridgeid(null);
|
||||
|
||||
return aConfig;
|
||||
}
|
||||
|
||||
private static String getMacAddress(String addr)
|
||||
{
|
||||
InetAddress ip;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
|
||||
ip = InetAddress.getByName(addr);
|
||||
|
||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||
}
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (SocketException e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (Exception e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected static String getBridgeIdFromMac(String macAddr, String ipAddr)
|
||||
{
|
||||
StringTokenizer st = new StringTokenizer(macAddr, ":");
|
||||
String bridgeId = "";
|
||||
String port = null;
|
||||
while(st.hasMoreTokens()) {
|
||||
bridgeId = bridgeId + st.nextToken();
|
||||
}
|
||||
if(ipAddr.contains(":")) {
|
||||
port = ipAddr.substring(ipAddr.indexOf(":"));
|
||||
BigInteger bigInt = BigInteger.valueOf(Integer.getInteger(port).intValue());
|
||||
byte[] theBytes = bigInt.toByteArray();
|
||||
bridgeId = bridgeId + DatatypeConverter.printHexBinary(theBytes);
|
||||
}
|
||||
else
|
||||
bridgeId = bridgeId + "0800";
|
||||
return bridgeId;
|
||||
}
|
||||
|
||||
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 String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public String getApiversion() {
|
||||
return apiversion;
|
||||
}
|
||||
|
||||
public void setApiversion(String apiversion) {
|
||||
this.apiversion = apiversion;
|
||||
}
|
||||
|
||||
|
||||
public String getModelid() {
|
||||
return modelid;
|
||||
}
|
||||
|
||||
public void setModelid(String modelid) {
|
||||
this.modelid = modelid;
|
||||
}
|
||||
|
||||
public String getBridgeid() {
|
||||
return bridgeid;
|
||||
}
|
||||
|
||||
public void setBridgeid(String bridgeid) {
|
||||
this.bridgeid = bridgeid;
|
||||
}
|
||||
|
||||
public Boolean getFactorynew() {
|
||||
return factorynew;
|
||||
}
|
||||
|
||||
public void setFactorynew(Boolean factorynew) {
|
||||
this.factorynew = factorynew;
|
||||
}
|
||||
|
||||
public String getReplacesbridgeid() {
|
||||
return replacesbridgeid;
|
||||
}
|
||||
|
||||
public void setReplacesbridgeid(String replacesbridgeid) {
|
||||
this.replacesbridgeid = replacesbridgeid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
// import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
*/
|
||||
public class StateChangeBody {
|
||||
private boolean on;
|
||||
private int bri;
|
||||
private int hue;
|
||||
private int sat;
|
||||
private String effect;
|
||||
private int ct;
|
||||
private String alert;
|
||||
private List<Double> xy;
|
||||
private int transitiontime;
|
||||
private int bri_inc;
|
||||
private int hue_inc;
|
||||
private int sat_inc;
|
||||
private List<Double> xy_inc;
|
||||
private int ct_inc;
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(boolean on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public int getBri() {
|
||||
return bri;
|
||||
}
|
||||
|
||||
public void setBri(int 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() {
|
||||
return effect;
|
||||
}
|
||||
|
||||
public void setEffect(String effect) {
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public int getCt() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
public void setCt(int ct) {
|
||||
this.ct = ct;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return alert;
|
||||
}
|
||||
|
||||
public void setAlert(String alert) {
|
||||
this.alert = alert;
|
||||
}
|
||||
|
||||
public List<Double> getXy() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXy(List<Double> xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
public int getTransitiontime() {
|
||||
return transitiontime;
|
||||
}
|
||||
|
||||
public void setTransitiontime(int transitiontime) {
|
||||
this.transitiontime = transitiontime;
|
||||
}
|
||||
|
||||
public int getBri_inc() {
|
||||
return bri_inc;
|
||||
}
|
||||
|
||||
public void setBri_inc(int bri_inc) {
|
||||
this.bri_inc = bri_inc;
|
||||
}
|
||||
|
||||
public int getHue_inc() {
|
||||
return hue_inc;
|
||||
}
|
||||
|
||||
public void setHue_inc(int hue_inc) {
|
||||
this.hue_inc = hue_inc;
|
||||
}
|
||||
|
||||
public int getSat_inc() {
|
||||
return sat_inc;
|
||||
}
|
||||
|
||||
public void setSat_inc(int sat_inc) {
|
||||
this.sat_inc = sat_inc;
|
||||
}
|
||||
|
||||
public List<Double> getXy_inc() {
|
||||
return xy_inc;
|
||||
}
|
||||
|
||||
public void setXy_inc(List<Double> xy_inc) {
|
||||
this.xy_inc = xy_inc;
|
||||
}
|
||||
|
||||
public int getCt_inc() {
|
||||
return ct_inc;
|
||||
}
|
||||
|
||||
public void setCt_inc(int ct_inc) {
|
||||
this.ct_inc = ct_inc;
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,36 @@ package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class Swupdate
|
||||
{
|
||||
private Integer updatestate;
|
||||
private Boolean checkforupdate;
|
||||
private DeviceTypes devicetypes;
|
||||
private String text;
|
||||
private Boolean notify;
|
||||
private Integer updatestate;
|
||||
private String url;
|
||||
|
||||
public static Swupdate createSwupdate() {
|
||||
Swupdate aSwupdate = new Swupdate();
|
||||
aSwupdate.setUpdatestate(0);
|
||||
aSwupdate.setCheckforupdate(false);
|
||||
aSwupdate.setDevicetypes(new DeviceTypes());
|
||||
aSwupdate.setNotify(false);
|
||||
aSwupdate.setText("");
|
||||
aSwupdate.setUpdatestate(0);
|
||||
aSwupdate.setUrl("");
|
||||
return aSwupdate;
|
||||
}
|
||||
|
||||
public Boolean getCheckforupdate() {
|
||||
return checkforupdate;
|
||||
}
|
||||
public void setCheckforupdate(Boolean checkforupdate) {
|
||||
this.checkforupdate = checkforupdate;
|
||||
}
|
||||
public DeviceTypes getDevicetypes() {
|
||||
return devicetypes;
|
||||
}
|
||||
public void setDevicetypes(DeviceTypes devicetypes) {
|
||||
this.devicetypes = devicetypes;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||
import com.bwssystems.HABridge.dao.ErrorMessage;
|
||||
import com.bwssystems.NestBridge.NestHome;
|
||||
import com.bwssystems.hal.HalHome;
|
||||
import com.bwssystems.harmony.HarmonyHome;
|
||||
import com.bwssystems.hue.HueHome;
|
||||
import com.bwssystems.luupRequests.Device;
|
||||
@@ -40,9 +41,10 @@ public class DeviceResource {
|
||||
private HarmonyHome myHarmonyHome;
|
||||
private NestHome nestHome;
|
||||
private HueHome hueHome;
|
||||
private HalHome halHome;
|
||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||
|
||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome) {
|
||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, HalHome aHalHome) {
|
||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
|
||||
if(theSettings.isValidVera())
|
||||
@@ -64,7 +66,13 @@ public class DeviceResource {
|
||||
this.hueHome = aHueHome;
|
||||
else
|
||||
this.hueHome = null;
|
||||
setupEndpoints();
|
||||
|
||||
if(theSettings.isValidHal())
|
||||
this.halHome = aHalHome;
|
||||
else
|
||||
this.halHome = null;
|
||||
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
public DeviceRepository getDeviceRepository() {
|
||||
@@ -262,6 +270,16 @@ public class DeviceResource {
|
||||
return hueHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/hal/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get hal items");
|
||||
if(halHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return new ErrorMessage("A Hal is not available.");
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return halHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||
log.debug("Get backup filenames");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
|
||||
@@ -6,7 +6,14 @@ import com.bwssystems.HABridge.api.NameValue;
|
||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
import com.bwssystems.HABridge.api.hue.GroupResponse;
|
||||
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorDetails;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||
import com.bwssystems.HABridge.api.hue.StateChangeBody;
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
import com.bwssystems.HABridge.dao.*;
|
||||
import com.bwssystems.NestBridge.NestInstruction;
|
||||
import com.bwssystems.NestBridge.NestHome;
|
||||
@@ -20,8 +27,6 @@ import com.bwssystems.hue.HueHome;
|
||||
import com.bwssystems.hue.HueUtil;
|
||||
import com.bwssystems.nest.controller.Nest;
|
||||
import com.bwssystems.util.JsonTransformer;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import net.java.dev.eval.Expression;
|
||||
@@ -61,8 +66,12 @@ import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
@@ -89,7 +98,6 @@ public class HueMulator implements HueErrorStringSet {
|
||||
private SSLContext sslcontext;
|
||||
private SSLConnectionSocketFactory sslsf;
|
||||
private RequestConfig globalConfig;
|
||||
private ObjectMapper mapper;
|
||||
private BridgeSettingsDescriptor bridgeSettings;
|
||||
private byte[] sendData;
|
||||
private String hueUser;
|
||||
@@ -114,8 +122,6 @@ public class HueMulator implements HueErrorStringSet {
|
||||
.setDefaultRequestConfig(globalConfig)
|
||||
.build();
|
||||
|
||||
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
repository = aDeviceRepository;
|
||||
if(theBridgeSettings.isValidHarmony())
|
||||
this.myHarmonyHome = theHarmonyHome;
|
||||
@@ -137,20 +143,146 @@ public class HueMulator implements HueErrorStringSet {
|
||||
// This function sets up the sparkjava rest calls for the hue api
|
||||
public void setupServer() {
|
||||
log.info("Hue emulator service started....");
|
||||
// http://ip_address:port/api/{userId}/groups returns json objects of all groups configured
|
||||
get(HUE_CONTEXT + "/:userid/groups", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue groups list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/groups/{groupId} returns json object for specified group. Only 0 is supported
|
||||
get(HUE_CONTEXT + "/:userid/groups/:groupid", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
String groupId = request.params(":groupid");
|
||||
log.debug("hue group 0 list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
if(groupId.equalsIgnoreCase("0")) {
|
||||
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||
String[] theList = new String[deviceList.size()];
|
||||
int i = 0;
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
theList[i] = device.getId();
|
||||
i++;
|
||||
}
|
||||
GroupResponse theResponse = GroupResponse.createGroupResponse(theList);
|
||||
return new Gson().toJson(theResponse, GroupResponse.class);
|
||||
}
|
||||
|
||||
return "[{\"error\":{\"type\":\"3\", \"address\": \"/api/" + userId + "/groups/" + "0" + "\",\"description\": \"Object not found\"}}]";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/scenes returns json objects of all scenes configured
|
||||
get(HUE_CONTEXT + "/:userid/scenes", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue scenes list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/schedules returns json objects of all schedules configured
|
||||
get(HUE_CONTEXT + "/:userid/schedules", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue schedules list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/sensors returns json objects of all sensors configured
|
||||
get(HUE_CONTEXT + "/:userid/sensors", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue sensors list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/rules returns json objects of all rules configured
|
||||
get(HUE_CONTEXT + "/:userid/rules", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue rules list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/resourcelinks returns json objects of all resourcelinks configured
|
||||
get(HUE_CONTEXT + "/:userid/resourcelinks", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue resourcelinks list requested: " + userId + " from " + request.ip());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
return "{}";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
|
||||
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
if(bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue lights list requested: " + userId + " from " + request.ip());
|
||||
log.debug("hue lights list requested: " + userId + " from " + request.ip());
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.status(HttpStatus.SC_OK);
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return theErrorResp.getTheErrors();
|
||||
}
|
||||
|
||||
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(device);
|
||||
deviceResponseMap.put(device.getId(), deviceResponse);
|
||||
}
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return deviceResponseMap;
|
||||
} , new JsonTransformer());
|
||||
|
||||
@@ -179,8 +311,9 @@ public class HueMulator implements HueErrorStringSet {
|
||||
aDeviceType = aNewUser.getDevicetype();
|
||||
}
|
||||
if(newUser == null)
|
||||
newUser = "lightssystem";
|
||||
newUser = getNewUserID();
|
||||
|
||||
validateWhitelistUser(newUser, false);
|
||||
if(aDeviceType == null)
|
||||
aDeviceType = "<not given>";
|
||||
if(bridgeSettings.isTraceupnp())
|
||||
@@ -217,43 +350,47 @@ public class HueMulator implements HueErrorStringSet {
|
||||
aDeviceType = aNewUser.getDevicetype();
|
||||
}
|
||||
if(newUser == null)
|
||||
newUser = "lightssystem";
|
||||
|
||||
newUser = getNewUserID();
|
||||
validateWhitelistUser(newUser, false);
|
||||
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
|
||||
// http://ip_address:port/api/config returns json objects for the public config when no user is given
|
||||
get(HUE_CONTEXT + "/config", "application/json", (request, response) -> {
|
||||
if(bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api/config config requested: <no_user> from " + request.ip());
|
||||
log.debug("hue api config requested: <no_user> from " + request.ip());
|
||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", "none");
|
||||
log.debug("hue api public config requested, from " + request.ip());
|
||||
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue", bridgeSettings.getUpnpConfigAddress());
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.status(HttpStatus.SC_OK);
|
||||
// String responseString = null;
|
||||
// responseString = "[{\"swversion\":\"" + apiResponse.getConfig().getSwversion() + "\",\"apiversion\":\"" + apiResponse.getConfig().getApiversion() + "\",\"name\":\"" + apiResponse.getConfig().getName() + "\",\"mac\":\"" + apiResponse.getConfig().getMac() + "\"}]";
|
||||
// return responseString;
|
||||
return apiResponse.getConfig();
|
||||
return apiResponse;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/api/{userId}/config returns json objects for the config
|
||||
get(HUE_CONTEXT + "/:userid/config", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.status(HttpStatus.SC_OK);
|
||||
if(bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + request.ip());
|
||||
log.debug("hue api config requested: " + userId + " from " + request.ip());
|
||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId);
|
||||
log.debug("hue api config requested: " + userId + " from " + request.ip());
|
||||
if(validateWhitelistUser(userId, true) == null) {
|
||||
log.debug("Valudate user, No User supplied, returning public config");
|
||||
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue", bridgeSettings.getUpnpConfigAddress());
|
||||
return apiResponse;
|
||||
}
|
||||
|
||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getWhitelist());
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return apiResponse.getConfig();
|
||||
}, new JsonTransformer());
|
||||
|
||||
@@ -261,24 +398,29 @@ public class HueMulator implements HueErrorStringSet {
|
||||
// http://ip_address:port/api/{userId} returns json objects for the full state
|
||||
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
||||
List<DeviceDescriptor> descriptorList = repository.findAll();
|
||||
if (descriptorList == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return null;
|
||||
}
|
||||
Map<String, DeviceResponse> deviceList = new HashMap<>();
|
||||
|
||||
descriptorList.forEach(descriptor -> {
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(descriptor);
|
||||
deviceList.put(descriptor.getId(), deviceResponse);
|
||||
}
|
||||
);
|
||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId);
|
||||
apiResponse.setLights(deviceList);
|
||||
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
log.debug("hue api full state requested: " + userId + " from " + request.ip());
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return theErrorResp.getTheErrors();
|
||||
}
|
||||
|
||||
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getWhitelist());
|
||||
Map<String, DeviceResponse> deviceList = new HashMap<>();
|
||||
List<DeviceDescriptor> descriptorList = repository.findAll();
|
||||
if (descriptorList != null) {
|
||||
descriptorList.forEach(descriptor -> {
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(descriptor);
|
||||
deviceList.put(descriptor.getId(), deviceResponse);
|
||||
}
|
||||
);
|
||||
apiResponse.setLights(deviceList);
|
||||
}
|
||||
|
||||
return apiResponse;
|
||||
}, new JsonTransformer());
|
||||
|
||||
@@ -286,18 +428,28 @@ public class HueMulator implements HueErrorStringSet {
|
||||
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
String lightId = request.params(":id");
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + request.ip());
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return theErrorResp.getTheErrors();
|
||||
}
|
||||
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if (device == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object not found\"}}]";
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("3", "/api/" + userId + "/lights/" + lightId, "Object not found", null, null, null)));
|
||||
return theErrorResp.getTheErrors();
|
||||
} else {
|
||||
log.debug("found device named: " + device.getName());
|
||||
}
|
||||
DeviceResponse lightResponse = DeviceResponse.createResponse(device);
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return lightResponse;
|
||||
}, new JsonTransformer());
|
||||
|
||||
@@ -316,27 +468,65 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String userId = request.params(":userid");
|
||||
String lightId = request.params(":id");
|
||||
String responseString = null;
|
||||
StateChangeBody theStateChanges = null;
|
||||
DeviceState state = null;
|
||||
boolean stateHasBri = false;
|
||||
boolean stateHasBriInc = false;
|
||||
log.debug("Update state requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
try {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
} catch (IOException e) {
|
||||
log.warn("Object mapper barfed on input of body.", e);
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object mapper barfed on input of body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
theStateChanges = new Gson().fromJson(request.body(), StateChangeBody.class);
|
||||
if (theStateChanges == null) {
|
||||
log.warn("Could not parse state change body. Light state not changed.");
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not parse state change body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if (request.body().contains("\"bri\""))
|
||||
stateHasBri = true;
|
||||
if (request.body().contains("\"bri_inc\""))
|
||||
stateHasBriInc = true;
|
||||
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if (device == null) {
|
||||
log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||
device.setDeviceState(state);
|
||||
state = device.getDeviceState();
|
||||
if(state == null)
|
||||
state = DeviceState.createDeviceState();
|
||||
state.fillIn();
|
||||
if(stateHasBri)
|
||||
{
|
||||
if(theStateChanges.getBri() > 0 && !state.isOn())
|
||||
state.setOn(true);
|
||||
}
|
||||
else if(stateHasBriInc) {
|
||||
if((state.getBri() + theStateChanges.getBri_inc()) > 0 && !state.isOn())
|
||||
state.setOn(true);
|
||||
else if((state.getBri() + theStateChanges.getBri_inc()) <= 0 && state.isOn())
|
||||
state.setOn(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (theStateChanges.isOn()) {
|
||||
if(state.getBri() <= 0)
|
||||
state.setBri(255);
|
||||
} else {
|
||||
state.setBri(0);
|
||||
}
|
||||
}
|
||||
device.getDeviceState().setBri(calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc));
|
||||
responseString = this.formatSuccessHueResponse(theStateChanges, request.body(), lightId);
|
||||
|
||||
return responseString;
|
||||
});
|
||||
@@ -361,32 +551,49 @@ public class HueMulator implements HueErrorStringSet {
|
||||
String responseString = null;
|
||||
String url = null;
|
||||
NameValue[] theHeaders = null;
|
||||
StateChangeBody theStateChanges = null;
|
||||
DeviceState state = null;
|
||||
boolean stateHasBri = false;
|
||||
boolean stateHasBriInc = false;
|
||||
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
if(validateWhitelistUser(userId, false) == null) {
|
||||
log.debug("Valudate user, No User supplied");
|
||||
HueErrorResponse theErrorResp = new HueErrorResponse();
|
||||
theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null)));
|
||||
return new Gson().toJson(theErrorResp.getTheErrors());
|
||||
}
|
||||
|
||||
try {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
} catch (IOException e) {
|
||||
log.warn("Object mapper barfed on input of body.", e);
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object mapper barfed on input of body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
theStateChanges = new Gson().fromJson(request.body(), StateChangeBody.class);
|
||||
if (theStateChanges == null) {
|
||||
log.warn("Could not parse state change body. Light state not changed.");
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not parse state change body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if (request.body().contains("\"bri\""))
|
||||
stateHasBri = true;
|
||||
if (request.body().contains("\"bri_inc\""))
|
||||
stateHasBriInc = true;
|
||||
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if (device == null) {
|
||||
log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
state = device.getDeviceState();
|
||||
if(state == null)
|
||||
state = DeviceState.createDeviceState();
|
||||
state.fillIn();
|
||||
|
||||
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
|
||||
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||
if((device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||
{
|
||||
if(myHueHome != null) {
|
||||
url = device.getOnUrl();
|
||||
@@ -413,29 +620,49 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
myHueHome.setTheHUERegisteredUser(hueUser);
|
||||
}
|
||||
else if(!responseString.contains("[{\"error\":"))
|
||||
device.setDeviceState(state);
|
||||
}
|
||||
else
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"No HUE configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
|
||||
return responseString;
|
||||
if(responseString == null || !responseString.contains("[{\"error\":")) {
|
||||
state.setBri(calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc));
|
||||
device.setDeviceState(state);
|
||||
responseString = this.formatSuccessHueResponse(theStateChanges, request.body(), lightId);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if(request.body().contains("bri"))
|
||||
if(stateHasBri)
|
||||
{
|
||||
if(theStateChanges.getBri() > 0 && !state.isOn())
|
||||
state.setOn(true);
|
||||
|
||||
url = device.getDimUrl();
|
||||
|
||||
if(url == null || url.length() == 0)
|
||||
url = device.getOnUrl();
|
||||
}
|
||||
else if(stateHasBriInc) {
|
||||
if((state.getBri() + theStateChanges.getBri_inc()) > 0 && !state.isOn())
|
||||
state.setOn(true);
|
||||
else if((state.getBri() + theStateChanges.getBri_inc()) <= 0 && state.isOn())
|
||||
state.setOn(false);
|
||||
|
||||
url = device.getDimUrl();
|
||||
|
||||
if(url == null || url.length() == 0)
|
||||
url = device.getOnUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.isOn()) {
|
||||
if (theStateChanges.isOn()) {
|
||||
url = device.getOnUrl();
|
||||
state.setBri(255);
|
||||
} else if (request.body().contains("false")) {
|
||||
state.setOn(true);
|
||||
if(state.getBri() <= 0)
|
||||
state.setBri(255);
|
||||
} else {
|
||||
url = device.getOffUrl();
|
||||
state.setOn(false);
|
||||
state.setBri(0);
|
||||
}
|
||||
}
|
||||
@@ -447,7 +674,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||
if((device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||
{
|
||||
log.debug("executing HUE api request to change activity to Harmony: " + url);
|
||||
if(myHarmonyHome != null)
|
||||
@@ -467,7 +694,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
}
|
||||
}
|
||||
else if(device.getDeviceType().toLowerCase().contains("button") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||
else if((device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||
{
|
||||
log.debug("executing HUE api request to button press(es) to Harmony: " + url);
|
||||
if(myHarmonyHome != null)
|
||||
@@ -497,7 +724,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
|
||||
}
|
||||
}
|
||||
else if(device.getDeviceType().toLowerCase().contains("home") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestHomeAway")))
|
||||
else if((device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestHomeAway")))
|
||||
{
|
||||
log.debug("executing HUE api request to set away for nest home: " + url);
|
||||
if(theNest == null)
|
||||
@@ -510,7 +737,7 @@ public class HueMulator implements HueErrorStringSet {
|
||||
theNest.getHome(homeAway.getName()).setAway(homeAway.getAway());
|
||||
}
|
||||
}
|
||||
else if(device.getDeviceType().toLowerCase().contains("thermo") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestThermoSet")))
|
||||
else if((device.getMapType() != null && device.getMapType().equalsIgnoreCase("nestThermoSet")))
|
||||
{
|
||||
log.debug("executing HUE api request to set thermostat for nest: " + url);
|
||||
if(theNest == null)
|
||||
@@ -523,9 +750,9 @@ public class HueMulator implements HueErrorStringSet {
|
||||
if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
|
||||
if(request.body().contains("bri")) {
|
||||
if(bridgeSettings.isFarenheit())
|
||||
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false)) - 32.0)/1.8));
|
||||
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false)) - 32.0)/1.8));
|
||||
else
|
||||
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false))));
|
||||
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false))));
|
||||
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
|
||||
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
|
||||
}
|
||||
@@ -557,18 +784,19 @@ public class HueMulator implements HueErrorStringSet {
|
||||
if( i > 0) {
|
||||
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||
}
|
||||
try {
|
||||
log.debug("Executing request: " + callItems[i].getItem());
|
||||
Process p = Runtime.getRuntime().exec(replaceIntensityValue(callItems[i].getItem(), state.getBri(), false));
|
||||
log.debug("Process running: " + p.isAlive());
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not execute request: " + callItems[i].getItem(), e);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
String intermediate;
|
||||
if(callItems[i].getItem().contains("exec://"))
|
||||
intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
|
||||
else
|
||||
intermediate = callItems[i].getItem();
|
||||
String anError = doExecRequest(intermediate, calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), lightId);
|
||||
if(anError != null) {
|
||||
responseString = anError;
|
||||
i = callItems.length+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // This section allows the usage of http/tcp/udp calls in a given set of items
|
||||
else // This section allows the usage of http/tcp/udp/exec calls in a given set of items
|
||||
{
|
||||
log.debug("executing HUE api request for network call: " + url);
|
||||
if(!url.startsWith("[")) {
|
||||
@@ -583,51 +811,61 @@ public class HueMulator implements HueErrorStringSet {
|
||||
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||
}
|
||||
try {
|
||||
String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||
String hostAddr = null;
|
||||
String port = null;
|
||||
if(hostPortion.contains(":")) {
|
||||
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||
port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||
if(callItems[i].getItem().contains("udp://") || callItems[i].getItem().contains("tcp://")) {
|
||||
String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||
String hostAddr = null;
|
||||
String port = null;
|
||||
if(hostPortion.contains(":")) {
|
||||
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||
port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||
}
|
||||
else
|
||||
hostAddr = hostPortion;
|
||||
InetAddress IPAddress = InetAddress.getByName(hostAddr);;
|
||||
if(theUrlBody.startsWith("0x")) {
|
||||
theUrlBody = replaceIntensityValue(theUrlBody, calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), true);
|
||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||
}
|
||||
else {
|
||||
theUrlBody = replaceIntensityValue(theUrlBody, calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false);
|
||||
sendData = theUrlBody.getBytes();
|
||||
}
|
||||
if(callItems[i].getItem().contains("udp://")) {
|
||||
log.debug("executing HUE api request to UDP: " + callItems[i].getItem());
|
||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||
responseSocket.send(sendPacket);
|
||||
responseSocket.close();
|
||||
}
|
||||
else if(callItems[i].getItem().contains("tcp://"))
|
||||
{
|
||||
log.debug("executing HUE api request to TCP: " + callItems[i].getItem());
|
||||
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||
outToClient.write(sendData);
|
||||
outToClient.flush();
|
||||
dataSendSocket.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
hostAddr = hostPortion;
|
||||
InetAddress IPAddress = InetAddress.getByName(hostAddr);;
|
||||
if(theUrlBody.startsWith("0x")) {
|
||||
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), true);
|
||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||
}
|
||||
else {
|
||||
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), false);
|
||||
sendData = theUrlBody.getBytes();
|
||||
}
|
||||
if(callItems[i].getItem().contains("udp://")) {
|
||||
log.debug("executing HUE api request to UDP: " + callItems[i].getItem());
|
||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||
responseSocket.send(sendPacket);
|
||||
responseSocket.close();
|
||||
}
|
||||
else if(callItems[i].getItem().contains("tcp://"))
|
||||
{
|
||||
log.debug("executing HUE api request to TCP: " + callItems[i].getItem());
|
||||
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||
outToClient.write(sendData);
|
||||
outToClient.flush();
|
||||
dataSendSocket.close();
|
||||
else if(callItems[i].getItem().contains("exec://")) {
|
||||
String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
|
||||
String anError = doExecRequest(intermediate, calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), lightId);
|
||||
if(anError != null) {
|
||||
responseString = anError;
|
||||
i = callItems.length+1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + callItems[i].getItem());
|
||||
|
||||
String anUrl = replaceIntensityValue(callItems[i].getItem(), state.getBri(), false);
|
||||
String anUrl = replaceIntensityValue(callItems[i].getItem(), calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false);
|
||||
String body;
|
||||
if (state.isOn())
|
||||
body = replaceIntensityValue(device.getContentBody(), state.getBri(), false);
|
||||
body = replaceIntensityValue(device.getContentBody(), calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false);
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri(), false);
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc), false);
|
||||
// make call
|
||||
if (doHttpRequest(anUrl, device.getHttpVerb(), device.getContentType(), body, theHeaders) == null) {
|
||||
log.warn("Error on calling url to change device state: " + anUrl);
|
||||
@@ -643,13 +881,31 @@ public class HueMulator implements HueErrorStringSet {
|
||||
}
|
||||
}
|
||||
|
||||
if(!responseString.contains("[{\"error\":")) {
|
||||
if(responseString == null || !responseString.contains("[{\"error\":")) {
|
||||
state.setBri(calculateIntensity(state, theStateChanges, stateHasBri, stateHasBriInc));
|
||||
device.setDeviceState(state);
|
||||
responseString = this.formatSuccessHueResponse(theStateChanges, request.body(), lightId);
|
||||
}
|
||||
return responseString;
|
||||
});
|
||||
}
|
||||
|
||||
private int calculateIntensity(DeviceState state, StateChangeBody theChanges, boolean hasBri, boolean hasBriInc) {
|
||||
int setIntensity = state.getBri();
|
||||
if(hasBri) {
|
||||
setIntensity = theChanges.getBri();
|
||||
}
|
||||
else if(hasBriInc) {
|
||||
if((setIntensity + theChanges.getBri_inc()) < 0)
|
||||
setIntensity = 0;
|
||||
else if((setIntensity + theChanges.getBri_inc()) > 255)
|
||||
setIntensity = 255;
|
||||
else
|
||||
setIntensity = setIntensity + theChanges.getBri_inc();
|
||||
}
|
||||
return setIntensity;
|
||||
}
|
||||
|
||||
/* light weight templating here, was going to use free marker but it was a bit too
|
||||
* heavy for what we were trying to do.
|
||||
*
|
||||
@@ -750,84 +1006,200 @@ public class HueMulator implements HueErrorStringSet {
|
||||
response = httpClient.execute(request);
|
||||
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
if(response.getEntity() != null ) {
|
||||
try {
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
} catch(Exception e) {
|
||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if(theContent == null)
|
||||
theContent = "";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||
}
|
||||
return theContent;
|
||||
}
|
||||
|
||||
private String doExecRequest(String anItem, int intensity, String lightId) {
|
||||
log.debug("Executing request: " + anItem);
|
||||
String responseString = null;
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(replaceIntensityValue(anItem, intensity, false));
|
||||
log.debug("Process running: " + p.isAlive());
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not execute request: " + anItem, e);
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
private String formatSuccessHueResponse(DeviceState state, String body, String lightId) {
|
||||
private String formatSuccessHueResponse(StateChangeBody state, String body, String lightId) {
|
||||
|
||||
String responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
boolean justState = true;
|
||||
if(body.contains("bri"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(body.contains("ct"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/ct\":" + state.getCt() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(body.contains("xy"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/xy\":" + state.getXy() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(body.contains("hue"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/hue\":" + state.getHue() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(body.contains("sat"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/sat\":" + state.getSat() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(body.contains("colormode"))
|
||||
{
|
||||
if(justState)
|
||||
responseString = responseString + "true}}";
|
||||
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/colormode\":" + state.getColormode() + "}}";
|
||||
justState = false;
|
||||
}
|
||||
|
||||
if(justState)
|
||||
String responseString = "[";
|
||||
boolean notFirstChange = false;
|
||||
if(body.contains("\"on\""))
|
||||
{
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
if (state.isOn()) {
|
||||
responseString = responseString + "true}}";
|
||||
state.setBri(255);
|
||||
} else if (body.contains("false")) {
|
||||
} else {
|
||||
responseString = responseString + "false}}";
|
||||
state.setBri(0);
|
||||
}
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"bri\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"bri_inc\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri_inc\":" + state.getBri_inc() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"ct\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct\":" + state.getCt() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"xy\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/xy\":" + state.getXy() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"hue\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue\":" + state.getHue() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"sat\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat\":" + state.getSat() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"ct_inc\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct_inc\":" + state.getCt_inc() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"xy_inc\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/xy_inc\":" + state.getXy_inc() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"hue_inc\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue_inc\":" + state.getHue_inc() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"sat_inc\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat_inc\":" + state.getSat_inc() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"effect\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/effect\":" + state.getEffect() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"transitiontime\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/transitiontime\":" + state.getTransitiontime() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
if(body.contains("\"alert\""))
|
||||
{
|
||||
if(notFirstChange)
|
||||
responseString = responseString + ",";
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/alert\":" + state.getAlert() + "}}";
|
||||
notFirstChange = true;
|
||||
}
|
||||
|
||||
responseString = responseString + "]";
|
||||
|
||||
return responseString;
|
||||
|
||||
}
|
||||
|
||||
private String getNewUserID() {
|
||||
UUID uid = UUID.randomUUID();
|
||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
||||
String newUser = "";
|
||||
while(st.hasMoreTokens()) {
|
||||
newUser = newUser + st.nextToken();
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
private String validateWhitelistUser(String aUser, boolean strict) {
|
||||
if(aUser == null ||aUser.equalsIgnoreCase("undefined") || aUser.equalsIgnoreCase("null") || aUser.equalsIgnoreCase(""))
|
||||
return null;
|
||||
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if(bridgeSettings.getWhitelist() != null) {
|
||||
Set<String> theUserIds = bridgeSettings.getWhitelist().keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while(userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
if(validUser.equals(aUser))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && strict)
|
||||
return null;
|
||||
|
||||
if(!found) {
|
||||
if(bridgeSettings.getWhitelist() == null) {
|
||||
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
|
||||
bridgeSettings.setWhitelist(awhitelist);
|
||||
}
|
||||
bridgeSettings.getWhitelist().put(aUser, WhitelistEntry.createEntry("auto insert user"));
|
||||
bridgeSettings.setSettingsChanged(true);
|
||||
|
||||
}
|
||||
return aUser;
|
||||
}
|
||||
@Override
|
||||
public void setErrorString(String anError) {
|
||||
errorString = anError;
|
||||
|
||||
@@ -22,6 +22,21 @@ public class UpnpListener {
|
||||
private boolean strict;
|
||||
private boolean traceupnp;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private boolean discoveryTemplateLatest;
|
||||
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.10.0\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||
private String discoveryTemplateOld = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||
|
||||
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
|
||||
super();
|
||||
@@ -31,6 +46,7 @@ public class UpnpListener {
|
||||
strict = theSettings.isUpnpStrict();
|
||||
traceupnp = theSettings.isTraceupnp();
|
||||
bridgeControl = theControl;
|
||||
discoveryTemplateLatest = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@@ -189,16 +205,12 @@ public class UpnpListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||
String discoveryResponse = null;
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||
if(discoveryTemplateLatest)
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||
else
|
||||
discoveryResponse = String.format(discoveryTemplateOld, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort);
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
|
||||
else
|
||||
|
||||
@@ -15,26 +15,51 @@ public class UpnpSettingsResource {
|
||||
|
||||
private BridgeSettingsDescriptor 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"
|
||||
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
|
||||
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
||||
+ "<friendlyName>HA-Bridge (%s)</friendlyName>\n"
|
||||
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n"
|
||||
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n"
|
||||
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n"
|
||||
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
|
||||
+ "<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n"
|
||||
+ "<serialNumber>0017880ae670</serialNumber>\n"
|
||||
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
|
||||
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
|
||||
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
|
||||
+ "<SCPDURL>(null)</SCPDURL>\n" + "</service>\n" + "</serviceList>\n"
|
||||
+ "<presentationURL>index.html</presentationURL>\n" + "<iconList>\n" + "<icon>\n"
|
||||
+ "<mimetype>image/png</mimetype>\n" + "<height>48</height>\n" + "<width>48</width>\n"
|
||||
+ "<depth>24</depth>\n" + "<url>hue_logo_0.png</url>\n" + "</icon>\n" + "<icon>\n"
|
||||
+ "<mimetype>image/png</mimetype>\n" + "<height>120</height>\n" + "<width>120</width>\n"
|
||||
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
|
||||
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"
|
||||
+ "<URLBase>http://%s:%s/</URLBase>\n"
|
||||
+ "<device>\n"
|
||||
+ "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
||||
+ "<friendlyName>Philips hue (%s)</friendlyName>\n"
|
||||
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n"
|
||||
+ "<manufacturerURL>http://www.philips.com</manufacturerURL>\n"
|
||||
+ "<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>\n"
|
||||
+ "<modelName>Philips hue bridge 2015</modelName>\n"
|
||||
+ "<modelNumber>BSB002</modelNumber>\n"
|
||||
+ "<modelURL>http://www.meethue.com</modelURL>\n"
|
||||
+ "<serialNumber>0017880ae670</serialNumber>\n"
|
||||
+ "<UDN>uuid:2f402f80-da50-11e1-9b23-001788102201</UDN>\n"
|
||||
+ "<serviceList>\n"
|
||||
+ "<service>\n"
|
||||
+ "<serviceType>(null)</serviceType>\n"
|
||||
+ "<serviceId>(null)</serviceId>\n"
|
||||
+ "<controlURL>(null)</controlURL>\n"
|
||||
+ "<eventSubURL>(null)</eventSubURL>\n"
|
||||
+ "<SCPDURL>(null)</SCPDURL>\n"
|
||||
+ "</service>\n"
|
||||
+ "</serviceList>\n"
|
||||
+ "<presentationURL>index.html</presentationURL>\n"
|
||||
+ "<iconList>\n"
|
||||
+ "<icon>\n"
|
||||
+ "<mimetype>image/png</mimetype>\n"
|
||||
+ "<height>48</height>\n"
|
||||
+ "<width>48</width>\n"
|
||||
+ "<depth>24</depth>\n"
|
||||
+ "<url>hue_logo_0.png</url>\n"
|
||||
+ "</icon>\n"
|
||||
+ "<icon>\n"
|
||||
+ "<mimetype>image/png</mimetype>\n"
|
||||
+ "<height>120</height>\n"
|
||||
+ "<width>120</width>\n"
|
||||
+ "<depth>24</depth>\n"
|
||||
+ "<url>hue_logo_3.png</url>\n"
|
||||
+ "</icon>\n"
|
||||
+ "</iconList>\n"
|
||||
+ "</device>\n"
|
||||
+ "</root>\n";
|
||||
|
||||
public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) {
|
||||
@@ -47,9 +72,9 @@ public class UpnpSettingsResource {
|
||||
// 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) -> {
|
||||
if(theSettings.isTraceupnp())
|
||||
log.info("Traceupnp: upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
||||
log.info("Traceupnp: upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
|
||||
else
|
||||
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port());
|
||||
log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
|
||||
String portNumber = Integer.toString(request.port());
|
||||
String filledTemplate = null;
|
||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||
@@ -72,5 +97,17 @@ public class UpnpSettingsResource {
|
||||
|
||||
return filledTemplate;
|
||||
} );
|
||||
// http://ip_adress:port/favicon.ico
|
||||
get("/favicon.ico", "application/xml; charset=utf-8", (request, response) -> {
|
||||
return "";
|
||||
} );
|
||||
// http://ip_adress:port/hue_logo_0.png
|
||||
get("/hue_logo_0.png", "application/xml; charset=utf-8", (request, response) -> {
|
||||
return "";
|
||||
} );
|
||||
// http://ip_adress:port/hue_logo_3.png
|
||||
get("/hue_logo_3.png", "application/xml; charset=utf-8", (request, response) -> {
|
||||
return "";
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class DeviceElements {
|
||||
@SerializedName(value="DeviceElements", alternate={"SceneElements", "GroupElements", "HVACElements", "MacroElements", "IrElements", "IrButtons"})
|
||||
private List<DeviceName> DeviceElements;
|
||||
|
||||
public List<DeviceName> getDeviceElements() {
|
||||
return DeviceElements;
|
||||
}
|
||||
|
||||
public void setDeviceElements(List<DeviceName> deviceElements) {
|
||||
DeviceElements = deviceElements;
|
||||
}
|
||||
}
|
||||
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class DeviceName {
|
||||
@SerializedName(value="DeviceName", alternate={"SceneName", "GroupName", "HVACName", "MacroName", "IrName", "IrButton"})
|
||||
private String DeviceName;
|
||||
|
||||
public String getDeviceName() {
|
||||
return DeviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
DeviceName = deviceName;
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
public class HalDevice {
|
||||
private String haldevicetype;
|
||||
private String haldevicename;
|
||||
private String haladdress;
|
||||
private String halname;
|
||||
private DeviceElements buttons;
|
||||
public String getHaldevicetype() {
|
||||
return haldevicetype;
|
||||
}
|
||||
public void setHaldevicetype(String haldevicetype) {
|
||||
this.haldevicetype = haldevicetype;
|
||||
}
|
||||
public String getHaldevicename() {
|
||||
return haldevicename;
|
||||
}
|
||||
public void setHaldevicename(String haldevicename) {
|
||||
this.haldevicename = haldevicename;
|
||||
}
|
||||
public String getHaladdress() {
|
||||
return haladdress;
|
||||
}
|
||||
public void setHaladdress(String haladdress) {
|
||||
this.haladdress = haladdress;
|
||||
}
|
||||
public String getHalname() {
|
||||
return halname;
|
||||
}
|
||||
public void setHalname(String halname) {
|
||||
this.halname = halname;
|
||||
}
|
||||
public DeviceElements getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
public void setButtons(DeviceElements buttons) {
|
||||
this.buttons = buttons;
|
||||
}
|
||||
}
|
||||
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class HalHome {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||
private Map<String, HalInfo> hals;
|
||||
|
||||
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
super();
|
||||
hals = new HashMap<String, HalInfo>();
|
||||
if(!bridgeSettings.isValidHal())
|
||||
return;
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aHal = theList.next();
|
||||
try {
|
||||
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get harmony client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<HalDevice> getDevices() {
|
||||
log.debug("consolidating devices for hues");
|
||||
List<HalDevice> theResponse = null;
|
||||
Iterator<String> keys = hals.keySet().iterator();
|
||||
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = hals.get(key).getLights();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else {
|
||||
log.warn("Cannot get lights for Hal with name: " + key + ", skipping this HAL.");
|
||||
continue;
|
||||
}
|
||||
theResponse = hals.get(key).getAppliances();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get appliances for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getTheatre();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get theatre for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getCustom();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get custom for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getHVAC();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get HVAC for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getHome(key);
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Homes for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getGroups();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Groups for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getMacros();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Macros for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getScenes();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Scenes for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getButtons();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Buttons for Hal with name: " + key);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
||||
Iterator<HalDevice> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
HalDevice theDevice = devices.next();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype());
|
||||
aNewHalDevice.setHaldevicename(theDevice.getHaldevicename());
|
||||
aNewHalDevice.setButtons(theDevice.getButtons());
|
||||
aNewHalDevice.setHaladdress(hals.get(theKey).getHalAddress().getIp());
|
||||
aNewHalDevice.setHalname(theKey);
|
||||
theDeviceList.add(aNewHalDevice);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
@@ -0,0 +1,206 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.util.TextStringFormatter;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HalInfo {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalInfo.class);
|
||||
private static final String DEVICE_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType=";
|
||||
private static final String HVAC_REQUEST = "/HVACData!HVACCmd=GetNames";
|
||||
private static final String GROUP_REQUEST = "/GroupData!GroupCmd=GetNames";
|
||||
private static final String MACRO_REQUEST = "/MacroData!MacroCmd=GetNames";
|
||||
private static final String SCENE_REQUEST = "/SceneData!SceneCmd=GetNames";
|
||||
private static final String IRDATA_REQUEST = "/IrData!IRCmd=GetNames";
|
||||
private static final String IRBUTTON_REQUEST = "/IrData!IRCmd=GetButtons!IrDevice=";
|
||||
private static final String TOKEN_REQUEST = "?Token=";
|
||||
private static final String LIGHT_REQUEST = "Light";
|
||||
private static final String APPL_REQUEST = "Appl";
|
||||
// private static final String VIDEO_REQUEST = "Video";
|
||||
private static final String THEATRE_REQUEST = "Theatre";
|
||||
private static final String CUSTOM_REQUEST = "Custom";
|
||||
private static final String HVAC_TYPE = "HVAC";
|
||||
private static final String HOME_TYPE = "Home";
|
||||
private static final String GROUP_TYPE = "Group";
|
||||
private static final String MACRO_TYPE = "Macro";
|
||||
private static final String SCENE_TYPE = "Scene";
|
||||
private static final String IRDATA_TYPE = "IrData";
|
||||
private HttpClient httpClient;
|
||||
private NamedIP halAddress;
|
||||
private String theToken;
|
||||
|
||||
public HalInfo(NamedIP addressName, String aGivenToken) {
|
||||
super();
|
||||
httpClient = HttpClients.createDefault();
|
||||
halAddress = addressName;
|
||||
theToken = aGivenToken;
|
||||
}
|
||||
|
||||
public List<HalDevice> getLights() {
|
||||
return getHalDevices(DEVICE_REQUEST + LIGHT_REQUEST + TOKEN_REQUEST, LIGHT_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getAppliances() {
|
||||
return getHalDevices(DEVICE_REQUEST + APPL_REQUEST + TOKEN_REQUEST, APPL_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getTheatre() {
|
||||
return getHalDevices(DEVICE_REQUEST + THEATRE_REQUEST + TOKEN_REQUEST, THEATRE_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getCustom() {
|
||||
return getHalDevices(DEVICE_REQUEST + CUSTOM_REQUEST + TOKEN_REQUEST, CUSTOM_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getHVAC() {
|
||||
return getHalDevices(HVAC_REQUEST + TOKEN_REQUEST, HVAC_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getGroups() {
|
||||
return getHalDevices(GROUP_REQUEST + TOKEN_REQUEST, GROUP_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getMacros() {
|
||||
return getHalDevices(MACRO_REQUEST + TOKEN_REQUEST, MACRO_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getScenes() {
|
||||
return getHalDevices(SCENE_REQUEST + TOKEN_REQUEST, SCENE_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getButtons() {
|
||||
List<HalDevice> irDataDevices = getHalDevices(IRDATA_REQUEST + TOKEN_REQUEST, IRDATA_TYPE);
|
||||
|
||||
return getDeviceButtons(irDataDevices);
|
||||
}
|
||||
|
||||
public List<HalDevice> getHome(String theDeviceName) {
|
||||
List<HalDevice> deviceList = null;
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(HOME_TYPE);
|
||||
aNewHalDevice.setHaldevicename(theDeviceName);
|
||||
deviceList.add(aNewHalDevice);
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private List<HalDevice> getHalDevices(String apiType, String deviceType) {
|
||||
DeviceElements theHalApiResponse = null;
|
||||
List<HalDevice> deviceList = null;
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
||||
theData = doHttpGETRequest(theUrl);
|
||||
if(theData != null) {
|
||||
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||
if(theHalApiResponse.getDeviceElements() == null) {
|
||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||
if(theStatus.getStatus() == null) {
|
||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
||||
}
|
||||
else {
|
||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: " + theStatus.getDescription());
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
|
||||
Iterator<DeviceName> theDeviceNames = theHalApiResponse.getDeviceElements().iterator();
|
||||
while(theDeviceNames.hasNext()) {
|
||||
DeviceName theDevice = theDeviceNames.next();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(deviceType);
|
||||
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||
deviceList.add(aNewHalDevice);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Get Hal device types " + deviceType + " for " + halAddress.getName() + " - returned null, no data.");
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private List<HalDevice> getDeviceButtons(List<HalDevice> theIrDevices) {
|
||||
DeviceElements theHalApiResponse = null;
|
||||
List<HalDevice> deviceList = null;
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
if(theIrDevices == null)
|
||||
return null;
|
||||
Iterator<HalDevice> theHalDevices = theIrDevices.iterator();
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
while (theHalDevices.hasNext()) {
|
||||
HalDevice theHalDevice = theHalDevices.next();
|
||||
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||
theData = doHttpGETRequest(theUrl);
|
||||
if (theData != null) {
|
||||
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||
if (theHalApiResponse.getDeviceElements() == null) {
|
||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||
if (theStatus.getStatus() == null) {
|
||||
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||
+ halAddress.getName() + " as response is not parsable.");
|
||||
} else {
|
||||
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||
+ halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: "
|
||||
+ theStatus.getDescription());
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
theHalDevice.setButtons(theHalApiResponse);
|
||||
deviceList.add(theHalDevice);
|
||||
|
||||
} else {
|
||||
log.warn("Get Hal buttons for IR Device " + theHalDevice.getHaldevicename() + " for "
|
||||
+ halAddress.getName() + " - returned null, no data.");
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
// This function executes the url against the hal
|
||||
protected String doHttpGETRequest(String url) {
|
||||
String theContent = null;
|
||||
log.debug("calling GET on URL: " + url);
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||
if(response.getStatusLine().getStatusCode() == 200){
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||
}
|
||||
return theContent;
|
||||
}
|
||||
|
||||
public NamedIP getHalAddress() {
|
||||
return halAddress;
|
||||
}
|
||||
|
||||
public void setHalAddress(NamedIP halAddress) {
|
||||
this.halAddress = halAddress;
|
||||
}
|
||||
|
||||
}
|
||||
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
public class StatusDescription {
|
||||
private String Status;
|
||||
private String Description;
|
||||
public String getStatus() {
|
||||
return Status;
|
||||
}
|
||||
public void setStatus(String status) {
|
||||
Status = status;
|
||||
}
|
||||
public String getDescription() {
|
||||
return Description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,7 @@ public class HueUtil {
|
||||
|
||||
public static final String registerWithHue(HttpClient anHttpClient, String ipAddress, String aName, String theUser, HueErrorStringSet errorStringSet) {
|
||||
UserCreateRequest theLogin = new UserCreateRequest();
|
||||
theLogin.setDevicetype("HA Bridge");
|
||||
if(theUser == null)
|
||||
theLogin.setUsername("habridge");
|
||||
else
|
||||
theLogin.setUsername(theUser);
|
||||
theLogin.setDevicetype("HABridge#MyMachine");
|
||||
HttpPost postRequest = new HttpPost("http://" + ipAddress + HUE_REQUEST);
|
||||
ContentType parsedContentType = ContentType.parse("application/json");
|
||||
StringEntity requestBody = new StringEntity(new Gson().toJson(theLogin), parsedContentType);
|
||||
|
||||
@@ -221,6 +221,9 @@ public final class TextStringFormatter {
|
||||
public static String forQuerySpace(String aURL) {
|
||||
return aURL.replace(" ", "\u0020");
|
||||
}
|
||||
public static String forQuerySpaceUrl(String aURL) {
|
||||
return aURL.replace(" ", "%20");
|
||||
}
|
||||
/**
|
||||
* Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.scrollableContainer {
|
||||
height: 800px;
|
||||
max-height: 436px; /* sets max-height value for all standards-compliant browsers */
|
||||
position: relative;
|
||||
padding-top: 35px;
|
||||
overflow: hidden;
|
||||
@@ -28,7 +28,8 @@
|
||||
}
|
||||
|
||||
.scrollArea {
|
||||
height: 100%;
|
||||
_height: expression( this.scrollHeight > 599 ? "600px" : "auto" ); /* sets max-height for IE6 */
|
||||
max-height: 400px; /* sets max-height value for all standards-compliant browsers */
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #d5d5d5;
|
||||
|
||||
@@ -34,6 +34,9 @@ app.config(function ($routeProvider) {
|
||||
}).when('/huedevices', {
|
||||
templateUrl: 'views/huedevice.html',
|
||||
controller: 'HueController'
|
||||
}).when('/haldevices', {
|
||||
templateUrl: 'views/haldevice.html',
|
||||
controller: 'HalController'
|
||||
}).otherwise({
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
@@ -45,9 +48,21 @@ app.run( function (bridgeService) {
|
||||
bridgeService.getHABridgeVersion();
|
||||
});
|
||||
|
||||
String.prototype.replaceAll = function(search, replace)
|
||||
{
|
||||
//if replace is not sent, return original string otherwise it will
|
||||
//replace search string with 'undefined'.
|
||||
if (replace === undefined) {
|
||||
return this.toString();
|
||||
}
|
||||
|
||||
return this.replace(new RegExp('[' + search + ']', 'g'), replace);
|
||||
};
|
||||
|
||||
|
||||
app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
var self = this;
|
||||
this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, habridgeversion: ""};
|
||||
this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, habridgeversion: ""};
|
||||
|
||||
this.displayWarn = function(errorTitle, error) {
|
||||
var toastContent = errorTitle;
|
||||
@@ -155,6 +170,11 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateShowHal = function () {
|
||||
this.state.showHal = self.state.settings.halconfigured;
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadBridgeSettings = function () {
|
||||
return $http.get(this.state.systemsbase + "/settings").then(
|
||||
function (response) {
|
||||
@@ -163,6 +183,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
self.updateShowHarmony();
|
||||
self.updateShowNest();
|
||||
self.updateShowHue();
|
||||
self.updateShowHal();
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Load Bridge Settings Error: ", error);
|
||||
@@ -292,6 +313,19 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
);
|
||||
};
|
||||
|
||||
this.viewHalDevices = function () {
|
||||
if(!this.state.showHal)
|
||||
return;
|
||||
return $http.get(this.state.base + "/hal/devices").then(
|
||||
function (response) {
|
||||
self.state.haldevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Get Hal Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.updateLogLevels = function(logComponents) {
|
||||
return $http.put(this.state.systemsbase + "/logmgmt/update", logComponents ).then(
|
||||
function (response) {
|
||||
@@ -324,6 +358,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
this.bulkAddDevice = function (devices) {
|
||||
return $http.post(this.state.base, devices).then(
|
||||
function (response) {
|
||||
self.displaySuccess("Bulk device add successful.");
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Bulk Add new Device Error: ", error);
|
||||
@@ -564,7 +599,7 @@ app.controller('SystemController', function ($scope, $location, $http, $window,
|
||||
bridgeService.viewConfigs();
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.optionalbackupname = "";
|
||||
$scope.isInControl = false;
|
||||
$scope.bridge.isInControl = false;
|
||||
$scope.visible = false;
|
||||
$scope.imgUrl = "glyphicon glyphicon-plus";
|
||||
$scope.addVeratoSettings = function (newveraname, newveraip) {
|
||||
@@ -615,12 +650,26 @@ app.controller('SystemController', function ($scope, $location, $http, $window,
|
||||
}
|
||||
}
|
||||
};
|
||||
$scope.addHaltoSettings = function (newhalname, newhalip) {
|
||||
if($scope.bridge.settings.haladdress == null) {
|
||||
$scope.bridge.settings.haladdress = { devices: [] };
|
||||
}
|
||||
var newhal = {name: newhalname, ip: newhalip }
|
||||
$scope.bridge.settings.haladdress.devices.push(newhal);
|
||||
$scope.newhalname = null;
|
||||
$scope.newhalip = null;
|
||||
};
|
||||
$scope.removeHaltoSettings = function (halname, halip) {
|
||||
for(var i = $scope.bridge.settings.haladdress.devices.length - 1; i >= 0; i--) {
|
||||
if($scope.bridge.settings.haladdress.devices[i].name === halname && $scope.bridge.settings.haladdress.devices[i].ip === halip) {
|
||||
$scope.bridge.settings.haladdress.devices.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
$scope.bridgeReinit = function () {
|
||||
$scope.isInControl = false;
|
||||
bridgeService.reinit();
|
||||
};
|
||||
$scope.bridgeStop = function () {
|
||||
$scope.isInControl = false;
|
||||
bridgeService.stop();
|
||||
};
|
||||
$scope.saveSettings = function() {
|
||||
@@ -724,7 +773,12 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.testUrl(device, type);
|
||||
};
|
||||
$scope.deleteDevice = function (device) {
|
||||
bridgeService.deleteDevice(device.id);
|
||||
$scope.bridge.device = device;
|
||||
ngDialog.open({
|
||||
template: 'deleteDialog',
|
||||
controller: 'DeleteDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
$scope.editDevice = function (device) {
|
||||
bridgeService.editDevice(device);
|
||||
@@ -789,11 +843,49 @@ app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('VeraController', function ($scope, $location, $http, bridgeService) {
|
||||
app.controller('DeleteDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
$scope.deleteDevice = function (device) {
|
||||
ngDialog.close('ngdialog1');
|
||||
bridgeService.deleteDevice(device.id);
|
||||
bridgeService.viewDevices();
|
||||
$scope.bridge.device = null;
|
||||
$scope.bridge.type = "";
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('DeleteMapandIdDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.mapandid = $scope.bridge.mapandid;
|
||||
$scope.deleteMapandId = function (mapandid) {
|
||||
ngDialog.close('ngdialog1');
|
||||
bridgeService.deleteDeviceByMapId(mapandid.id, mapandid.mapType);
|
||||
bridgeService.viewDevices();
|
||||
if(mapandid.mapType == "veraDevice")
|
||||
bridgeService.viewVeraDevices();
|
||||
if(mapandid.mapType == "veraScene")
|
||||
bridgeService.viewVeraScenes();
|
||||
if(mapandid.mapType == "harmonyActivity")
|
||||
bridgeService.viewHarmonyActivities();
|
||||
if(mapandid.mapType == "harmonyButton")
|
||||
bridgeService.viewHarmonyDevices();
|
||||
if(mapandid.mapType == "nestThermoSet" || mapandid.mapType == "nestHomeAway")
|
||||
bridgeService.viewNestItems();
|
||||
if(mapandid.mapType == "hueDevice")
|
||||
bridgeService.viewHueDevices();
|
||||
if(mapandid.mapType == "halDevice")
|
||||
bridgeService.viewHalDevices();
|
||||
$scope.bridge.mapandid = null;
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('VeraController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
$scope.device_dim_control = "";
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
var veraList = angular.fromJson($scope.bridge.settings.veraaddress);
|
||||
if(veraList != null)
|
||||
$scope.vera = {base: "http://" + veraList.devices[0].ip, port: "3480", id: ""};
|
||||
@@ -878,6 +970,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
deviceType: $scope.device.deviceType,
|
||||
targetDevice: $scope.device.targetDevice,
|
||||
onUrl: $scope.device.onUrl,
|
||||
dimUrl: $scope.device.dimUrl,
|
||||
offUrl: $scope.device.offUrl,
|
||||
headers: $scope.device.headers,
|
||||
httpVerb: $scope.device.httpVerb,
|
||||
@@ -888,12 +981,19 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeService.bulkAddDevice(devicesList);
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
bridgeService.bulkAddDevice(devicesList).then(
|
||||
function () {
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
},
|
||||
function (error) {
|
||||
bridgeService.displayWarn("Error adding Vera devices in bulk.", error)
|
||||
}
|
||||
);
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
};
|
||||
|
||||
$scope.toggleSelection = function toggleSelection(deviceId) {
|
||||
@@ -902,11 +1002,28 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
// is currently selected
|
||||
if (idx > -1) {
|
||||
$scope.bulk.devices.splice(idx, 1);
|
||||
if($scope.bulk.devices.length == 0 && $scope.selectAll)
|
||||
$scope.selectAll = false;
|
||||
}
|
||||
|
||||
// is newly selected
|
||||
else {
|
||||
$scope.bulk.devices.push(deviceId);
|
||||
$scope.selectAll = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleSelectAll = function toggleSelectAll() {
|
||||
if($scope.selectAll) {
|
||||
$scope.selectAll = false;
|
||||
$scope.bulk = { devices: [] };
|
||||
}
|
||||
else {
|
||||
$scope.selectAll = true;
|
||||
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
|
||||
if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.veradevices[x].id, bridgeService.state.veradevices[x].veraname, "veraDevice"))
|
||||
$scope.bulk.devices.push(bridgeService.state.veradevices[x].id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -919,15 +1036,17 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
$scope.bridge.mapandid = { id, mapType };
|
||||
ngDialog.open({
|
||||
template: 'deleteMapandIdDialog',
|
||||
controller: 'DeleteMapandIdDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.controller('HarmonyController', function ($scope, $location, $http, bridgeService) {
|
||||
app.controller('HarmonyController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
bridgeService.viewHarmonyActivities();
|
||||
@@ -951,21 +1070,22 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
||||
};
|
||||
|
||||
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
|
||||
bridgeService.clearDevice();
|
||||
var currentOn = $scope.device.onUrl;
|
||||
var currentOff = $scope.device.offUrl;
|
||||
var actionOn = angular.fromJson(onbutton);
|
||||
var actionOff = angular.fromJson(offbutton);
|
||||
if( $scope.device.mapType == "harmonyButton") {
|
||||
$scope.device.mapId = $scope.device.mapId + "-" + actionOn.command;
|
||||
$scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]";
|
||||
$scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]";
|
||||
}
|
||||
else if ($scope.device.mapType == null || $scope.device.mapType == "") {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "button";
|
||||
$scope.device.targetDevice = harmonydevice.hub;
|
||||
$scope.device.name = harmonydevice.device.label;
|
||||
$scope.device.mapType = "harmonyButton";
|
||||
$scope.device.mapId = harmonydevice.device.id + "-" + actionOn.command + "-" + actionOff.command;
|
||||
$scope.device.mapId = harmonydevice.device.id + "-" + actionOn.command;
|
||||
$scope.device.onUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]";
|
||||
$scope.device.offUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]";
|
||||
}
|
||||
@@ -996,15 +1116,17 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHarmonyActivities();
|
||||
bridgeService.viewHarmonyDevices();
|
||||
$scope.bridge.mapandid = { id, mapType };
|
||||
ngDialog.open({
|
||||
template: 'deleteMapandIdDialog',
|
||||
controller: 'DeleteMapandIdDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.controller('NestController', function ($scope, $location, $http, bridgeService) {
|
||||
app.controller('NestController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
bridgeService.viewNestItems();
|
||||
@@ -1116,17 +1238,21 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewNestItems();
|
||||
$scope.bridge.mapandid = { id, mapType };
|
||||
ngDialog.open({
|
||||
template: 'deleteMapandIdDialog',
|
||||
controller: 'DeleteMapandIdDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.controller('HueController', function ($scope, $location, $http, bridgeService) {
|
||||
app.controller('HueController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
bridgeService.viewHueDevices();
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
$scope.buttonsVisible = false;
|
||||
@@ -1168,7 +1294,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
var devicesList = [];
|
||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
|
||||
if(bridgeService.state.huedevices[x].id == $scope.bulk.devices[i]) {
|
||||
if(bridgeService.state.huedevices[x].device.uniqueid == $scope.bulk.devices[i]) {
|
||||
$scope.buildDeviceUrls(bridgeService.state.huedevices[x]);
|
||||
devicesList[i] = {
|
||||
name: $scope.device.name,
|
||||
@@ -1177,6 +1303,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
deviceType: $scope.device.deviceType,
|
||||
targetDevice: $scope.device.targetDevice,
|
||||
onUrl: $scope.device.onUrl,
|
||||
dimUrl: $scope.device.dimUrl,
|
||||
offUrl: $scope.device.offUrl,
|
||||
headers: $scope.device.headers,
|
||||
httpVerb: $scope.device.httpVerb,
|
||||
@@ -1187,11 +1314,19 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeService.bulkAddDevice(devicesList);
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHueDevices();
|
||||
bridgeService.bulkAddDevice(devicesList).then(
|
||||
function () {
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHueDevices();
|
||||
},
|
||||
function (error) {
|
||||
bridgeService.displayWarn("Error adding Hue devices in bulk.", error)
|
||||
}
|
||||
);
|
||||
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
};
|
||||
|
||||
$scope.toggleSelection = function toggleSelection(deviceId) {
|
||||
@@ -1200,11 +1335,28 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
// is currently selected
|
||||
if (idx > -1) {
|
||||
$scope.bulk.devices.splice(idx, 1);
|
||||
if($scope.bulk.devices.length == 0 && $scope.selectAll)
|
||||
$scope.selectAll = false;
|
||||
}
|
||||
|
||||
// is newly selected
|
||||
else {
|
||||
$scope.bulk.devices.push(deviceId);
|
||||
$scope.selectAll = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleSelectAll = function toggleSelectAll() {
|
||||
if($scope.selectAll) {
|
||||
$scope.selectAll = false;
|
||||
$scope.bulk = { devices: [] };
|
||||
}
|
||||
else {
|
||||
$scope.selectAll = true;
|
||||
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
|
||||
if($scope.bulk.devices.indexOf(bridgeService.state.huedevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.huedevices[x].device.uniqueid, bridgeService.state.huedevices[x].huename, "hueDevice"))
|
||||
$scope.bulk.devices.push(bridgeService.state.huedevices[x].device.uniqueid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1217,9 +1369,329 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHueDevices();
|
||||
$scope.bridge.mapandid = { id, mapType };
|
||||
ngDialog.open({
|
||||
template: 'deleteMapandIdDialog',
|
||||
controller: 'DeleteMapandIdDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.controller('HalController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
$scope.device_dim_control = "";
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
bridgeService.viewHalDevices();
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
$scope.buttonsVisible = false;
|
||||
|
||||
$scope.clearDevice = function () {
|
||||
bridgeService.clearDevice();
|
||||
};
|
||||
|
||||
$scope.buildDeviceUrls = function (haldevice, dim_control) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device = $scope.bridge.device;
|
||||
var preOnCmd = "";
|
||||
var preDimCmd = "";
|
||||
var preOffCmd = "";
|
||||
var nameCmd = ""
|
||||
var postCmd = "?Token=" + $scope.bridge.settings.haltoken;
|
||||
if(haldevice.haldevicetype == "Group") {
|
||||
$scope.device.deviceType = "group";
|
||||
preOnCmd = "/GroupService!GroupCmd=On";
|
||||
preOffCmd = "/GroupService!GroupCmd=Off";
|
||||
nameCmd = "!GroupName=";
|
||||
}
|
||||
else if(haldevice.haldevicetype == "Macro") {
|
||||
$scope.device.deviceType = "macro";
|
||||
preOnCmd = "/MacroService!MacroCmd=Set!MacroName=";
|
||||
preOffCmd = preOnCmd;
|
||||
}
|
||||
else if(haldevice.haldevicetype == "Scene") {
|
||||
$scope.device.deviceType = "scene";
|
||||
preOnCmd = "/SceneService!SceneCmd=Set!SceneName=";
|
||||
preOffCmd = preOnCmd;
|
||||
}
|
||||
else {
|
||||
$scope.device.deviceType = "switch";
|
||||
preOnCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=On";
|
||||
preDimCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Dim!DevicePercent=";
|
||||
preOffCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Off";
|
||||
nameCmd = "!DeviceName=";
|
||||
}
|
||||
$scope.device.name = haldevice.haldevicename;
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halDevice";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname;
|
||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) && $scope.device.deviceType == "switch")
|
||||
$scope.device.dimUrl = "http://" + haldevice.haladdress
|
||||
+ preDimCmd
|
||||
+ dim_control
|
||||
+ nameCmd
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ postCmd;
|
||||
else
|
||||
$scope.device.dimUrl = "http://" + haldevice.haladdress
|
||||
+ preOnCmd
|
||||
+ nameCmd
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ postCmd;
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ preOnCmd
|
||||
+ nameCmd
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ postCmd;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ preOffCmd
|
||||
+ nameCmd
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ postCmd;
|
||||
};
|
||||
|
||||
$scope.buildButtonUrls = function (haldevice, onbutton, offbutton) {
|
||||
var currentOn = $scope.device.onUrl;
|
||||
var currentOff = $scope.device.offUrl;
|
||||
var actionOn = angular.fromJson(onbutton);
|
||||
var actionOff = angular.fromJson(offbutton);
|
||||
if( $scope.device.mapType == "halButton") {
|
||||
$scope.device.mapId = $scope.device.mapId + "-" + actionOn.DeviceName;
|
||||
$scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken +"\"}]";
|
||||
$scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOff.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
|
||||
}
|
||||
else if ($scope.device.mapType == null || $scope.device.mapType == "") {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "button";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.name = haldevice.haldevicename;
|
||||
$scope.device.mapType = "halButton";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-" + actionOn.DeviceName;
|
||||
$scope.device.onUrl = "[{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
|
||||
$scope.device.offUrl = "[{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOff.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.buildHALHomeUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "home";
|
||||
$scope.device.name = haldevice.haldevicename;
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halHome";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-HomeAway";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken;
|
||||
};
|
||||
|
||||
$scope.buildHALHeatUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = haldevice.haldevicename + " Heat";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halThermoSet";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetHeat";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Heat?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.dimUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Heat!HeatSpValue=${intensity.percent}?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Off?Token="
|
||||
};
|
||||
|
||||
$scope.buildHALCoolUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = haldevice.haldevicename + " Cool";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halThermoSet";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetCool";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Cool?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.dimUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Cool!CoolSpValue=${intensity.percent}?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Off?Token="
|
||||
};
|
||||
|
||||
$scope.buildHALAutoUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = haldevice.haldevicename + " Auto";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halThermoSet";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetAuto";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Auto?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Off?Token="
|
||||
};
|
||||
|
||||
$scope.buildHALOffUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = haldevice.haldevicename + " Thermostat";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halThermoSet";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-TurnOff";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Auto?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!HVACMode=Off?Token="
|
||||
};
|
||||
|
||||
$scope.buildHALFanUrls = function (haldevice) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = haldevice.haldevicename + " Fan";
|
||||
$scope.device.targetDevice = haldevice.halname;
|
||||
$scope.device.mapType = "halThermoSet";
|
||||
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetFan";
|
||||
$scope.device.onUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!FanMode=On?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||
+ "!FanMode=Auto?Token="
|
||||
+ $scope.bridge.settings.haltoken;
|
||||
};
|
||||
|
||||
$scope.addDevice = function () {
|
||||
if($scope.device.name == "" && $scope.device.onUrl == "")
|
||||
return;
|
||||
bridgeService.addDevice($scope.device).then(
|
||||
function () {
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHalDevices();
|
||||
},
|
||||
function (error) {
|
||||
bridgeService.displayWarn("Error adding device: " + $scope.device.name, error)
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
$scope.bulkAddDevices = function(dim_control) {
|
||||
var devicesList = [];
|
||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||
if(bridgeService.state.haldevices[x].haldevicename == $scope.bulk.devices[i]) {
|
||||
if(bridgeService.state.haldevices[x].haldevicetype == "HVAC")
|
||||
$scope.buildHALAutoUrls(bridgeService.state.haldevices[x]);
|
||||
else if(bridgeService.state.haldevices[x].haldevicetype == "HOME")
|
||||
$scope.buildHALHomeUrls(bridgeService.state.haldevices[x]);
|
||||
else
|
||||
$scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control);
|
||||
devicesList[i] = {
|
||||
name: $scope.device.name,
|
||||
mapId: $scope.device.mapId,
|
||||
mapType: $scope.device.mapType,
|
||||
deviceType: $scope.device.deviceType,
|
||||
targetDevice: $scope.device.targetDevice,
|
||||
onUrl: $scope.device.onUrl,
|
||||
dimUrl: $scope.device.dimUrl,
|
||||
offUrl: $scope.device.offUrl,
|
||||
headers: $scope.device.headers,
|
||||
httpVerb: $scope.device.httpVerb,
|
||||
contentType: $scope.device.contentType,
|
||||
contentBody: $scope.device.contentBody,
|
||||
contentBodyOff: $scope.device.contentBodyOff
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeService.bulkAddDevice(devicesList).then(
|
||||
function () {
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewHalDevices();
|
||||
},
|
||||
function (error) {
|
||||
bridgeService.displayWarn("Error adding HAL devices in bulk.", error)
|
||||
}
|
||||
);
|
||||
$scope.bulk = { devices: [] };
|
||||
$scope.selectAll = false;
|
||||
};
|
||||
|
||||
$scope.toggleSelection = function toggleSelection(deviceId) {
|
||||
var idx = $scope.bulk.devices.indexOf(deviceId);
|
||||
|
||||
// is currently selected
|
||||
if (idx > -1) {
|
||||
$scope.bulk.devices.splice(idx, 1);
|
||||
if($scope.bulk.devices.length == 0 && $scope.selectAll)
|
||||
$scope.selectAll = false;
|
||||
}
|
||||
|
||||
// is newly selected
|
||||
else {
|
||||
$scope.bulk.devices.push(deviceId);
|
||||
$scope.selectAll = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleSelectAll = function toggleSelectAll() {
|
||||
if($scope.selectAll) {
|
||||
$scope.selectAll = false;
|
||||
$scope.bulk = { devices: [] };
|
||||
}
|
||||
else {
|
||||
$scope.selectAll = true;
|
||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||
if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
|
||||
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleButtons = function () {
|
||||
$scope.buttonsVisible = !$scope.buttonsVisible;
|
||||
if($scope.buttonsVisible)
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-minus";
|
||||
else
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||
$scope.bridge.mapandid = { id, mapType };
|
||||
ngDialog.open({
|
||||
template: 'deleteMapandIdDialog',
|
||||
controller: 'DeleteMapandIdDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1455,6 +1927,35 @@ app.filter('unavailableHueDeviceId', function(bridgeService) {
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('availableHalDeviceId', 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].haldevicename + "-" + input[i].halname, input[i].halname, "halDevice") &&
|
||||
!bridgeService.findDeviceByMapId(input[i].haldevicename + "-" + input[i].halname + "-HomeAway", input[i].halname, "halHome") ){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('unavailableHalDeviceId', function(bridgeService) {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(input[i].mapType != null && bridgeService.aContainsB(input[i].mapType, "hal")){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('configuredButtons', function() {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
|
||||
@@ -1,40 +1,50 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Current devices ({{bridge.devices.length}}) </h2>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.devices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="id">ID</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="deviceType">Type</th>
|
||||
<th sortable-header col="targetDevice">Target</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="device in bridge.devices">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.deviceType}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>
|
||||
<p>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#">Bridge
|
||||
Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Current devices
|
||||
({{bridge.devices.length}})</h2>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.devices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="id">ID</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="deviceType">Type</th>
|
||||
<th sortable-header col="targetDevice">Target</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="device in bridge.devices">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.deviceType}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>
|
||||
<p>
|
||||
<button class="btn btn-info" type="submit"
|
||||
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||
<button class="btn btn-info" type="submit"
|
||||
@@ -45,50 +55,56 @@
|
||||
ng-click="editDevice(device)">Edit/Copy</button>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDevice(device)">Delete</button>
|
||||
</p>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">
|
||||
Bridge Device DB Backup <a ng-click="toggleBk()"><span
|
||||
class={{imgBkUrl}} aria-hidden="true"></a>
|
||||
</h1>
|
||||
</div>
|
||||
<div ng-if="visibleBk" class="animate-if" class="panel-body">
|
||||
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
|
||||
File Name</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupDeviceDb(optionalbackupname)">Backup
|
||||
Device DB</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.backups">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreBackup(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteBackup(backup)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default backup">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge Device DB Backup <a ng-click="toggleBk()"><span class={{imgBkUrl}} aria-hidden="true"></a></h1>
|
||||
</div>
|
||||
<div ng-if="visibleBk" class="animate-if" class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup File Name</label>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupDeviceDb(optionalbackupname)">Backup Device DB</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.backups">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreBackup(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteBackup(backup)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="valueDialog">
|
||||
<script type="text/ng-template" id="valueDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Select value</h2>
|
||||
<p>
|
||||
@@ -103,4 +119,13 @@
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="deleteDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device to Delete?</h2>
|
||||
<p>{{device.name}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
@@ -1,210 +1,235 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue 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>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL Devices</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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Edit/Copy a device</h2>
|
||||
</div>
|
||||
<p class="text-muted">This screen allows the modification of many fields the bridge uses. Please use care when
|
||||
updating these fields as you may break the settings used by the bridge to call a specific end point device.</p>
|
||||
<p>When copying, update the name and select the "Add Bridge Device" Button.</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">This screen allows the modification of many
|
||||
fields the bridge uses. Please use care when updating these fields as
|
||||
you may break the settings used by the bridge to call a specific end
|
||||
point device.</p>
|
||||
<p>When copying, update the name and select the "Add Bridge
|
||||
Device" Button.</p>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-success" ng-click="addDevice()">
|
||||
Update Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
|
||||
</label>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-success"
|
||||
ng-click="addDevice()">Update Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-target"
|
||||
ng-model="device.targetDevice" placeholder="default">
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="copyDevice()">
|
||||
Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||
</label>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-target"
|
||||
ng-model="device.targetDevice" placeholder="default">
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="copyDevice()">Add
|
||||
Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device
|
||||
Type </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
<option value="switch">Switch</option>
|
||||
<option value="scene">Scene</option>
|
||||
<option value="activity">Activity</option>
|
||||
<option value="button">Button</option>
|
||||
<option value="thermo">Thermo</option>
|
||||
<option value="passthru">Pass Thru</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type"
|
||||
ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
<option value="switch">Switch</option>
|
||||
<option value="scene">Scene</option>
|
||||
<option value="macro">Macro</option>
|
||||
<option value="group">Group</option>
|
||||
<option value="activity">Activity</option>
|
||||
<option value="button">Button</option>
|
||||
<option value="thermo">Thermo</option>
|
||||
<option value="passthru">Pass Thru</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-map-type">Map Type </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-map-type" id="device-map-type" ng-model="device.mapType">
|
||||
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||
<option value="veraDevice">Vera Device</option>
|
||||
<option value="veraScene">Vera Scene</option>
|
||||
<option value="harmonyActivity">Harmony Activity</option>
|
||||
<option value="harmonyButton">Harmony Button</option>
|
||||
<option value="nestHomeAway">Nest Home Status</option>
|
||||
<option value="nestThermoSet">Nest Thermostat</option>
|
||||
<option value="hueDevice">Hue Device</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-map-type" id="device-map-type"
|
||||
ng-model="device.mapType">
|
||||
<option value="">---Please select---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="veraDevice">Vera Device</option>
|
||||
<option value="veraScene">Vera Scene</option>
|
||||
<option value="harmonyActivity">Harmony Activity</option>
|
||||
<option value="harmonyButton">Harmony Button</option>
|
||||
<option value="nestHomeAway">Nest Home Status</option>
|
||||
<option value="nestThermoSet">Nest Thermostat</option>
|
||||
<option value="hueDevice">Hue Device</option>
|
||||
<option value="halDevice">HAL Device</option>
|
||||
<option value="halHome">HAL Home Status</option>
|
||||
<option value="halThermoSet">HAL Thermostat</option>
|
||||
</select>
|
||||
</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>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.mapType" class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map
|
||||
ID </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-map-id"
|
||||
ng-model="device.mapId" placeholder="1111">
|
||||
</div>
|
||||
</div>
|
||||
<div 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">
|
||||
<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
|
||||
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 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 class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</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>
|
||||
</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 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 class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-headers">HTTP Headers </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-headers">HTTP
|
||||
Headers </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers"
|
||||
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</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>
|
||||
</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 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 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>
|
||||
</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 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 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>
|
||||
</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 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 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="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 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>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,230 +1,250 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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.showVera">
|
||||
<div ng-if="bridge.showVera" class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">You can generate on/off URLs by filling in
|
||||
the Vera server URL, port, and device ID; or you can fill them out
|
||||
manually in the lower section.</p>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">You can generate on/off URLs by filling in
|
||||
the Vera server URL, port, and device ID; or you can fill them out
|
||||
manually in the lower section.</p>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
||||
Server URL </label>
|
||||
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
||||
Server URL </label>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="vera-base"
|
||||
ng-model="vera.base"
|
||||
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
||||
Request Port </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="vera-base"
|
||||
ng-model="vera.base"
|
||||
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
||||
Request Port </label>
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-port"
|
||||
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
||||
</div>
|
||||
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-port"
|
||||
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
||||
</div>
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
||||
ID </label>
|
||||
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
||||
ID </label>
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-id"
|
||||
ng-model="vera.id" placeholder="ID">
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<input type="text" class="form-control" id="vera-id"
|
||||
ng-model="vera.id" placeholder="ID">
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Scene
|
||||
URLs</button>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<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>
|
||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
|
||||
Scene URLs</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a new device</h2>
|
||||
</div>
|
||||
<p class="text-muted">This area allows you to create any http or udp call to an endpoint. You can use the default GET or select
|
||||
the http verb type below and configure a payload for either on, dim or off methods. Currently, https is not supported. For Execution of
|
||||
a script or program, plese fill in the path. All manually entered calls can use Json notation of array with
|
||||
[{"item":"the payload"},{"item":"another payload"}] to execute multiple entries. Adding the value replacements (${intensity..byte},${intensity.percent},${intensity.math(X*1)})
|
||||
will also work.</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">This area allows you to create any http or
|
||||
udp call to an endpoint. You can use the default GET or select the
|
||||
http verb type below and configure a payload for either on, dim or
|
||||
off methods. Currently, https is not supported. For Execution of a
|
||||
script or program, plese fill in the path. All manually entered calls
|
||||
can use Json notation of array with [{"item":"the
|
||||
payload"},{"item":"another payload"}] to
|
||||
execute multiple entries. Adding the value replacements
|
||||
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
|
||||
also work.</p>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||
</label>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device
|
||||
Type </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type"
|
||||
ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
</select>
|
||||
</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>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div 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 class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</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>
|
||||
</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 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 class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-headers">HTTP Headers </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-headers">HTTP
|
||||
Headers </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers"
|
||||
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</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>
|
||||
</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 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 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>
|
||||
</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 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 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>
|
||||
</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 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 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="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 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>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
217
src/main/resources/public/views/haldevice.html
Normal file
217
src/main/resources/public/views/haldevice.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showHAL" role="presentation"><a href="#/HAL">HAL</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/haldevices">HAL
|
||||
Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">HAL Device List
|
||||
({{bridge.haldevices.length}})</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any HAL Device, use the action buttons
|
||||
to generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured HAL Devices' list below will show what
|
||||
is already setup for your HAL.</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>
|
||||
<p>Use the check boxes by the names to use the bulk addition
|
||||
feature. Select your items and dim control type if wanted, then click
|
||||
bulk add below. Your items will be added with on and off or dim and
|
||||
off if selected with the name of the device from the HAL.</p>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.haldevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">
|
||||
<span><input type="checkbox" name="selectAll"
|
||||
value="{{selectAll}}"
|
||||
ng-checked="selectAll"
|
||||
ng-click="toggleSelectAll()"> Name</span></th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="halname">HAL</th>
|
||||
<th>On Button</th>
|
||||
<th>Off Button</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="haldevice in bridge.haldevices | availableHalDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]"
|
||||
value="{{haldevice.haldevicename}}"
|
||||
ng-checked="bulk.devices.indexOf(haldevice.haldevicename) > -1"
|
||||
ng-click="toggleSelection(haldevice.haldevicename)">
|
||||
{{haldevice.haldevicename}}</td>
|
||||
<td>{{haldevice.haldevicetype}}</td>
|
||||
<td>{{haldevice.halname}}</td>
|
||||
<td>
|
||||
<select name="button-on" id="button-on" ng-model="button_on">
|
||||
<option ng-repeat="aButtonOn in haldevice.buttons.DeviceElements"
|
||||
value="{{aButtonOn}}">{{aButtonOn.DeviceName}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="button-off" id="button-off" ng-model="button_off">
|
||||
<option ng-repeat="aButtonOff in haldevice.buttons.DeviceElements"
|
||||
value="{{aButtonOff}}">{{aButtonOff.DeviceName}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button ng-if="haldevice.haldevicetype != 'Home' && haldevice.haldevicetype != 'HVAC' && haldevice.haldevicetype != 'IrData'" class="btn btn-success" type="submit"
|
||||
ng-click="buildDeviceUrls(haldevice, device_dim_control)">Generate
|
||||
Bridge Device</button>
|
||||
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
|
||||
ng-click="buildHALHomeUrls(haldevice)">Home/Away</button>
|
||||
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
|
||||
ng-click="buildButtonUrls(haldevice, button_on, button_off)">Build
|
||||
A Button</button>
|
||||
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALHeatUrls(haldevice)">Heat</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALCoolUrls(haldevice)">Cool</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALAutoUrls(haldevice)">Auto</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALOffUrls(haldevice)">Off</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALFanUrls(haldevice)">Fan</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
|
||||
({{bulk.devices.length}})</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured HAL Devices <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.haldevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="halname">HAL</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="device in bridge.devices | unavailableHalDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.deviceType}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add Bridge Device for a HAL Device</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-dim-url">Dim URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,100 +1,113 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation" class="active"><a
|
||||
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li role="presentation"><a href="#/harmonydevices">Harmony
|
||||
Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Harmony Activity List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Harmony Activity, use the action buttons to generate the device addition information below automatically.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Activities' list below will show what is already setup for your Harmony Hubs.</p>
|
||||
|
||||
<scrollable-table watch="bridge.harmonyactivities">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildActivityUrls(harmonyactivity)">Generate Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Activities <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any Harmony Activity, use the action
|
||||
buttons to generate the device addition information below
|
||||
automatically. Then you can modify the name to anything you want that
|
||||
will be the keyword for Alexa. Click the 'Add Bridge Device' to
|
||||
finish that selection setup. The 'Already Configured Activities' list
|
||||
below will show what is already setup for your Harmony Hubs.</p>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.harmonyactivities">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<scrollable-table watch="bridge.harmonyactivities">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||
Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Bridge Device for a Harmony Activity</h2>
|
||||
<h2 class="panel-title">
|
||||
Already Configured Activities <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||
</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<scrollable-table ng-if="buttonsVisible"
|
||||
watch="bridge.harmonyactivities">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonyactivity.activity.label}}</td>
|
||||
<td>{{harmonyactivity.activity.id}}</td>
|
||||
<td>{{harmonyactivity.hub}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Bridge Device for a Harmony
|
||||
Activity</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -104,10 +117,10 @@
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
</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>
|
||||
|
||||
@@ -115,9 +128,18 @@
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,121 +1,137 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/verascenes">Vera Scenes</a></li>
|
||||
<li role="presentation"><a href="#/harmonyactivities">Harmony
|
||||
Activities</a></li>
|
||||
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony
|
||||
Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Harmony Device List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Harmony Device and Buttons, use the build button to generate the configuration for this bridge device. You can add button presses by
|
||||
selecting yoru devic and buttons and then selecting the Build Button. This will allow multiple button presses to be built for a given device.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Harmony Buttons' list below will show what is already setup for your Harmony Hubs.</p>
|
||||
|
||||
<scrollable-table watch="bridge.harmonydevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>On Button</th>
|
||||
<th>Off Button</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonydevice in bridge.harmonydevices">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonydevice.device.label}}</td>
|
||||
<td>{{harmonydevice.device.id}}</td>
|
||||
<td>{{harmonydevice.hub}}</td>
|
||||
<td>
|
||||
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
|
||||
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}">
|
||||
<option ng-repeat="funcon in ctrlon.function" value="{{funcon.action}}">{{funcon.label}}</option>
|
||||
</optgroup >
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
|
||||
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}">
|
||||
<option ng-repeat="funcoff in ctrloff.function" value="{{funcoff.action}}">{{funcoff.label}}</option>
|
||||
</optgroup >
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build A Button</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-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 class="panel-body">
|
||||
<p class="text-muted">For any Harmony Device and Buttons, use the
|
||||
build button to generate the configuration for this bridge device.
|
||||
You can add button presses by selecting yoru devic and buttons and
|
||||
then selecting the Build Button. This will allow multiple button
|
||||
presses to be built for a given device. Then you can modify the name
|
||||
to anything you want that will be the keyword for Alexa. Click the
|
||||
'Add Bridge Device' to finish that selection setup. The 'Already
|
||||
Configured Harmony Buttons' list below will show what is already
|
||||
setup for your Harmony Hubs.</p>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.harmonydevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Device Id</th>
|
||||
<th sortable-header col="targetDevice">Hub</th>
|
||||
<th>Harmony Device-Button On-Button Off</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>{{device.mapId}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
|
||||
<scrollable-table watch="bridge.harmonydevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="hub">Hub</th>
|
||||
<th>On Button</th>
|
||||
<th>Off Button</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonydevice in bridge.harmonydevices">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{harmonydevice.device.label}}</td>
|
||||
<td>{{harmonydevice.device.id}}</td>
|
||||
<td>{{harmonydevice.hub}}</td>
|
||||
<td><select name="device-ctrlon" id="device-ctrlon"
|
||||
ng-model="devicectrlon">
|
||||
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup"
|
||||
label="{{ctrlon.name}}">
|
||||
<option ng-repeat="funcon in ctrlon.function"
|
||||
value="{{funcon.action}}">{{funcon.label}}</option>
|
||||
</optgroup>
|
||||
</select></td>
|
||||
<td><select name="device-ctrloff" id="device-ctrloff"
|
||||
ng-model="devicectrloff">
|
||||
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup"
|
||||
label="{{ctrloff.name}}">
|
||||
<option ng-repeat="funcoff in ctrloff.function"
|
||||
value="{{funcoff.action}}">{{funcoff.label}}</option>
|
||||
</optgroup>
|
||||
</select></td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build
|
||||
A Button</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<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>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.harmonydevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Device Id</th>
|
||||
<th sortable-header col="targetDevice">Hub</th>
|
||||
<th>Harmony Device-Button On-Button Off</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>{{device.mapId}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Bridge Device for Harmony Buttons</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -125,10 +141,10 @@
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
</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>
|
||||
|
||||
@@ -136,9 +152,18 @@
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,108 +1,128 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li role="presentation" class="active"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li role="presentation" class="active"><a href="#/huedevices">Hue
|
||||
Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Hue Device List ({{bridge.huedevices.length}})</h2>
|
||||
<h2 class="panel-title">Hue Device List
|
||||
({{bridge.huedevices.length}})</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Hue Device, use the action buttons to generate the device addition information below automatically.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Hue Devices' list below will show what is already setup for your Hue.</p>
|
||||
<p>Use the check boxes by the names to use the bulk addition feature. Select your items, then click bulk add below.
|
||||
Your items will be added with on and off or dim and off if selected with the name of the device from the Hue.
|
||||
</p>
|
||||
<scrollable-table watch="bridge.huedevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="huename">Hue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="huedevice in bridge.huedevices | availableHueDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]" value="{{huedevice.id}}" ng-checked="bulk.devices.indexOf(huedevice.id) > -1" ng-click="toggleSelection(huedevice.id)"> {{huedevice.device.name}}</td>
|
||||
<td>{{huedevice.device.uniqueid}}</td>
|
||||
<td>{{huedevice.huename}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildDeviceUrls(huedevice)">Generate Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<p>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any Hue Device, use the action buttons
|
||||
to generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured Hue Devices' list below will show what
|
||||
is already setup for your Hue.</p>
|
||||
<p>Use the check boxes by the names to use the bulk addition
|
||||
feature. Select your items, then click bulk add below. Your items
|
||||
will be added with on and off or dim and off if selected with the
|
||||
name of the device from the Hue.</p>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.huedevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name"><span><input type="checkbox" name="selectAll"
|
||||
value="{{selectAll}}"
|
||||
ng-checked="selectAll"
|
||||
ng-click="toggleSelectAll()"> Name</span></th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="huename">Hue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="huedevice in bridge.huedevices | availableHueDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]"
|
||||
value="{{huedevice.device.uniqueid}}"
|
||||
ng-checked="bulk.devices.indexOf(huedevice.device.uniqueid) > -1"
|
||||
ng-click="toggleSelection(huedevice.device.uniqueid)">
|
||||
{{huedevice.device.name}}</td>
|
||||
<td>{{huedevice.device.uniqueid}}</td>
|
||||
<td>{{huedevice.huename}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkHueDevices()">Bulk Add ({{bulk.devices.length}})</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Hue Devices <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></a></h2>
|
||||
ng-click="buildDeviceUrls(huedevice)">Generate Bridge
|
||||
Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkAddDevices()">Bulk Add
|
||||
({{bulk.devices.length}})</button>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.huedevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="huename">hue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="huedevice in bridge.huedevices | unavailableHueDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{huedevice.device.name}}</td>
|
||||
<td>{{huedevice.device.uniqueid}}</td>
|
||||
<td>{{huedevice.huename}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(huedevice.uniqueid, 'hueDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured Hue Devices <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.huedevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="huename">hue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="huedevice in bridge.huedevices | unavailableHueDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{huedevice.device.name}}</td>
|
||||
<td>{{huedevice.device.uniqueid}}</td>
|
||||
<td>{{huedevice.huename}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(huedevice.device.uniqueid, 'hueDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add Bridge Device for a Hue Device</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -113,7 +133,16 @@
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
@@ -1,76 +1,85 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation" class="active"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation" class="active"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Log Messages</h1>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit"
|
||||
ng-click="updateLogs()">Update Log</button>
|
||||
</p>
|
||||
<scrollable-table watch="bridge.logMsgs">
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th sortable-header col="time">Time</th>
|
||||
<th sortable-header col="level">Level</th>
|
||||
<th sortable-header col="message">Message</th>
|
||||
<th sortable-header col="component">Component</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="logMessage in bridge.logMsgs">
|
||||
<td>{{logMessage.time}}</td>
|
||||
<td>{{logMessage.level}}</td>
|
||||
<td>{{logMessage.message}}</td>
|
||||
<td>{{logMessage.component}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Log Messages</h1>
|
||||
</div>
|
||||
<div class="panel panel-default logconfig">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Logging Configuration <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit"
|
||||
ng-click="updateLoggers()">Update Log Levels</button>
|
||||
Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll"
|
||||
ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false> {{bridge.logShowAll}}
|
||||
</p>
|
||||
<scrollable-table watch="bridge.loggerInfo">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th sortable-header col="logLevel">Log Level</th>
|
||||
<th sortable-header col="loggerName">Component</th>
|
||||
<th>New Log Level</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="logInfo in bridge.loggerInfo">
|
||||
<td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td>
|
||||
<td>{{logInfo.loggerName}}</td>
|
||||
<td>
|
||||
<select name="new-log-level" id="new-log-level" ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel">
|
||||
<option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit" ng-click="updateLogs()">Update
|
||||
Log</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<scrollable-table watch="bridge.logMsgs">
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th sortable-header col="time">Time</th>
|
||||
<th sortable-header col="level">Level</th>
|
||||
<th sortable-header col="message">Message</th>
|
||||
<th sortable-header col="component">Component</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="logMessage in bridge.logMsgs">
|
||||
<td>{{logMessage.time}}</td>
|
||||
<td>{{logMessage.level}}</td>
|
||||
<td>{{logMessage.message}}</td>
|
||||
<td>{{logMessage.component}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">
|
||||
Logging Configuration <a ng-click="toggle()"><span
|
||||
class={{imgUrl}} aria-hidden="true"></a>
|
||||
</h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit"
|
||||
ng-click="updateLoggers()">Update Log Levels</button>
|
||||
Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll"
|
||||
ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false>
|
||||
{{bridge.logShowAll}}
|
||||
</p>
|
||||
<scrollable-table watch="bridge.loggerInfo">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th sortable-header col="logLevel">Log Level</th>
|
||||
<th sortable-header col="loggerName">Component</th>
|
||||
<th>New Log Level</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="logInfo in bridge.loggerInfo">
|
||||
<td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td>
|
||||
<td>{{logInfo.loggerName}}</td>
|
||||
<td><select name="new-log-level" id="new-log-level"
|
||||
ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel">
|
||||
<option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option>
|
||||
</select></td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,122 +1,132 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/veradevices">Vera Devices</a></li>
|
||||
<li ng-if="bridge.showVera" role="presentation"><a
|
||||
href="#/verascenes">Vera Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Nest Items List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Nest Item, use the action buttons to generate the device addition information below automatically.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Nest Items' list below will show what is already setup for your Nest.</p>
|
||||
|
||||
<scrollable-table watch="bridge.nestitems">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="type">Type</th>
|
||||
<th sortable-header col="location">Location</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{nestitem.name}}</td>
|
||||
<td>{{nestitem.type}}</td>
|
||||
<td>{{nestitem.location}}</td>
|
||||
<td>
|
||||
<ul class="list-group">
|
||||
<li ng-if="nestitem.type ==='Home' " class="list-group-item">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestHomeUrls(nestitem)">Home/Away</button>
|
||||
</li>
|
||||
<li ng-if="nestitem.type ==='Thermostat' " class="list-group-item">
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestTempUrls(nestitem)">Temp</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestHeatUrls(nestitem)">Heat</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestCoolUrls(nestitem)">Cool</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestRangeUrls(nestitem)">Range</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestOffUrls(nestitem)">Off</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestFanUrls(nestitem)">Fan</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Nest Items <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any Nest Item, use the action buttons to
|
||||
generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured Nest Items' list below will show what
|
||||
is already setup for your Nest.</p>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.nestitems">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Device Id</th>
|
||||
<th>mapId</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.mapId}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, 'nest')">Delete</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<scrollable-table watch="bridge.nestitems">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="type">Type</th>
|
||||
<th sortable-header col="location">Location</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{nestitem.name}}</td>
|
||||
<td>{{nestitem.type}}</td>
|
||||
<td>{{nestitem.location}}</td>
|
||||
<td>
|
||||
<ul class="list-group">
|
||||
<li ng-if="nestitem.type ==='Home' " class="list-group-item">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestHomeUrls(nestitem)">Home/Away</button>
|
||||
</li>
|
||||
<li ng-if="nestitem.type ==='Thermostat' " class="list-group-item">
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestTempUrls(nestitem)">Temp</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestHeatUrls(nestitem)">Heat</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestCoolUrls(nestitem)">Cool</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestRangeUrls(nestitem)">Range</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestOffUrls(nestitem)">Off</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildNestFanUrls(nestitem)">Fan</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured Nest Items <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.nestitems">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Device Id</th>
|
||||
<th>mapId</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.id}}</td>
|
||||
<td>{{device.mapId}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, 'nest')">Delete</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Bridge Device for a Nest Item</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -126,10 +136,10 @@
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
</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>
|
||||
|
||||
@@ -137,9 +147,18 @@
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,49 +1,57 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/system">Bridge
|
||||
Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge Settings</h1>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge Settings</h1>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||
server</label>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||
server</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="bridge-base" class="form-control" type="text"
|
||||
ng-model="bridge.base" placeholder="URL to bridge">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="goBridgeUrl(bridge.base)">Test</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="bridge-base" class="form-control" type="text"
|
||||
ng-model="bridge.base" placeholder="URL to bridge">
|
||||
</div>
|
||||
</form>
|
||||
<form name="form">
|
||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||
ng-click="goBridgeUrl(bridge.base)">Test</button>
|
||||
</div>
|
||||
</form>
|
||||
<form name="form">
|
||||
<p>
|
||||
<button ng-disabled="form.$pristine || bridge.isInControl" class="btn btn-success" type="submit"
|
||||
ng-click="saveSettings()">Save</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-warning" type="submit"
|
||||
ng-click="bridgeReinit()">Bridge Reinitialize</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-danger" type="submit"
|
||||
ng-click="bridgeStop()">Bridge Stop</button>
|
||||
<button class="btn btn-primary" type="submit"
|
||||
onclick="myRefresh()">Refresh</button>
|
||||
<button ng-disabled="bridge.isInControl"
|
||||
class="btn btn-success" type="submit" ng-click="saveSettings()">Save</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-warning"
|
||||
type="submit" ng-click="bridgeReinit()">Bridge
|
||||
Reinitialize</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-danger"
|
||||
type="submit" ng-click="bridgeStop()">Bridge Stop</button>
|
||||
<button class="btn btn-primary" type="submit" onclick="myRefresh()">Refresh</button>
|
||||
<script>
|
||||
function myRefresh() {
|
||||
location.reload();
|
||||
}
|
||||
function myRefresh() {
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
</p>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
@@ -55,32 +63,41 @@
|
||||
</thead>
|
||||
<tr>
|
||||
<td>Configuration Path and File</td>
|
||||
<td><input id="bridge-settings-configfile" class="form-control" type="text"
|
||||
ng-model="bridge.settings.configfile" placeholder="data/ha-bridge.config"></td>
|
||||
<td><input id="bridge-settings-configfile"
|
||||
class="form-control" type="text"
|
||||
ng-model="bridge.settings.configfile"
|
||||
placeholder="data/ha-bridge.config"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Device DB Path and File</td>
|
||||
<td><input id="bridge-settings-upnpdevicedb" class="form-control" type="text"
|
||||
ng-model="bridge.settings.upnpdevicedb" placeholder="data/device.db"></td>
|
||||
<td><input id="bridge-settings-upnpdevicedb"
|
||||
class="form-control" type="text"
|
||||
ng-model="bridge.settings.upnpdevicedb"
|
||||
placeholder="data/device.db"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UPNP IP Address</td>
|
||||
<td><input id="bridge-settings-upnpconfigaddress" class="form-control" type="text"
|
||||
ng-model="bridge.settings.upnpconfigaddress" placeholder="192.168.1.1"></td>
|
||||
<td><input id="bridge-settings-upnpconfigaddress"
|
||||
class="form-control" type="text"
|
||||
ng-model="bridge.settings.upnpconfigaddress"
|
||||
placeholder="192.168.1.1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Web Server Port</td>
|
||||
<td><input id="bridge-settings-serverport" class="form-control" type="number"
|
||||
ng-model="bridge.settings.serverport" min="1" max="65535"></td>
|
||||
<td><input id="bridge-settings-serverport"
|
||||
class="form-control" type="number"
|
||||
ng-model="bridge.settings.serverport" min="1" max="65535"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UPNP Response Port</td>
|
||||
<td><input id="bridge-settings-upnpresponseport" class="form-control" type="number"
|
||||
ng-model="bridge.settings.upnpresponseport" min="1" max="65535"></td>
|
||||
<td><input id="bridge-settings-upnpresponseport"
|
||||
class="form-control" type="number"
|
||||
ng-model="bridge.settings.upnpresponseport" min="1" max="65535"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vera Names and IP Addresses</td>
|
||||
<td><table class="table table-bordered table-striped table-hover">
|
||||
<td><table
|
||||
class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@@ -95,19 +112,21 @@
|
||||
ng-click="removeVeratoSettings(vera.name, vera.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-vera-name" class="form-control" type="text"
|
||||
ng-model="newveraname" placeholder="A Vera"></td>
|
||||
<td><input id="bridge-settings-next-vera-ip" class="form-control" type="text"
|
||||
ng-model="newveraip" placeholder="192.168.1.2"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
<td><input id="bridge-settings-next-vera-name"
|
||||
class="form-control" type="text" ng-model="newveraname"
|
||||
placeholder="A Vera"></td>
|
||||
<td><input id="bridge-settings-next-vera-ip"
|
||||
class="form-control" type="text" ng-model="newveraip"
|
||||
placeholder="192.168.1.2"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addVeratoSettings(newveraname, newveraip)">Add</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</table></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harmony Names and IP Addresses</td>
|
||||
<td><table class="table table-bordered table-striped table-hover">
|
||||
<td><table
|
||||
class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@@ -122,29 +141,34 @@
|
||||
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-harmony-name" class="form-control" type="text"
|
||||
ng-model="newharmonyname" placeholder="A Harmony"></td>
|
||||
<td><input id="bridge-settings-next-harmony-ip" class="form-control" type="text"
|
||||
ng-model="newharmonyip" placeholder="192.168.1.3"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
<td><input id="bridge-settings-next-harmony-name"
|
||||
class="form-control" type="text" ng-model="newharmonyname"
|
||||
placeholder="A Harmony"></td>
|
||||
<td><input id="bridge-settings-next-harmony-ip"
|
||||
class="form-control" type="text" ng-model="newharmonyip"
|
||||
placeholder="192.168.1.3"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addHarmonytoSettings(newharmonyname, newharmonyip)">Add</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</table></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harmony Username</td>
|
||||
<td><input id="bridge-settings-harmonyuser" class="form-control" type="text"
|
||||
ng-model="bridge.settings.harmonyuser" placeholder="someone@gmail.com"></td>
|
||||
<td><input id="bridge-settings-harmonyuser"
|
||||
class="form-control" type="text"
|
||||
ng-model="bridge.settings.harmonyuser"
|
||||
placeholder="someone@gmail.com"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harmony Password</td>
|
||||
<td><input id="bridge-settings-harmonypwd" class="form-control" type="password"
|
||||
ng-model="bridge.settings.harmonypwd" placeholder="thepassword"></td>
|
||||
<td><input id="bridge-settings-harmonypwd"
|
||||
class="form-control" type="password"
|
||||
ng-model="bridge.settings.harmonypwd" placeholder="thepassword"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hue Names and IP Addresses</td>
|
||||
<td><table class="table table-bordered table-striped table-hover">
|
||||
<td><table
|
||||
class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@@ -159,89 +183,138 @@
|
||||
ng-click="removeHuetoSettings(hue.name, hue.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-hue-name" class="form-control" type="text"
|
||||
ng-model="newhuename" placeholder="A Hue"></td>
|
||||
<td><input id="bridge-settings-next-hue-ip" class="form-control" type="text"
|
||||
ng-model="newhueip" placeholder="192.168.1.3"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
<td><input id="bridge-settings-next-hue-name"
|
||||
class="form-control" type="text" ng-model="newhuename"
|
||||
placeholder="A Hue"></td>
|
||||
<td><input id="bridge-settings-next-hue-ip"
|
||||
class="form-control" type="text" ng-model="newhueip"
|
||||
placeholder="192.168.1.3"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addHuetoSettings(newhuename, newhueip)">Add</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</table></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HAL Names and IP Addresses</td>
|
||||
<td><table
|
||||
class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>IP</th>
|
||||
<th>Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="hal in bridge.settings.haladdress.devices">
|
||||
<td>{{hal.name}}</td>
|
||||
<td>{{hal.ip}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="removeHaltoSettings(hal.name, hal.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-hal-name"
|
||||
class="form-control" type="text" ng-model="newhalname"
|
||||
placeholder="A Hal"></td>
|
||||
<td><input id="bridge-settings-next-hal-ip"
|
||||
class="form-control" type="text" ng-model="newhalip"
|
||||
placeholder="192.168.1.3:82"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addHaltoSettings(newhalname, newhalip)">Add</button></td>
|
||||
</tr>
|
||||
</table></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HAL Token</td>
|
||||
<td><input id="bridge-settings-haltoken" class="form-control"
|
||||
type="password" ng-model="bridge.settings.haltoken"
|
||||
placeholder="thetoken"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nest Username</td>
|
||||
<td><input id="bridge-settings-nestuser" class="form-control" type="text"
|
||||
ng-model="bridge.settings.nestuser" placeholder="someone@gmail.com"></td>
|
||||
<td><input id="bridge-settings-nestuser" class="form-control"
|
||||
type="text" ng-model="bridge.settings.nestuser"
|
||||
placeholder="someone@gmail.com"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nest Password</td>
|
||||
<td><input id="bridge-settings-nestpwd" class="form-control" type="password"
|
||||
ng-model="bridge.settings.nestpwd" placeholder="thepassword"></td>
|
||||
<td><input id="bridge-settings-nestpwd" class="form-control"
|
||||
type="password" ng-model="bridge.settings.nestpwd"
|
||||
placeholder="thepassword"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nest Temp Farenheit</td>
|
||||
<td><input type="checkbox" ng-model="bridge.settings.farenheit"
|
||||
ng-true-value=true ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||
<td><input type="checkbox"
|
||||
ng-model="bridge.settings.farenheit" ng-true-value=true
|
||||
ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button Press/Call Item Loop Sleep Interval (ms)</td>
|
||||
<td><input id="bridge-settings-buttonsleep" class="form-control" type="number" name="input"
|
||||
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td>
|
||||
<td><input id="bridge-settings-buttonsleep"
|
||||
class="form-control" type="number" name="input"
|
||||
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Log Messages to Buffer</td>
|
||||
<td><input id="bridge-settings-numberoflogmessages" class="form-control" type="number"
|
||||
ng-model="bridge.settings.numberoflogmessages" min="100" max="65535"></td>
|
||||
<td><input id="bridge-settings-numberoflogmessages"
|
||||
class="form-control" type="number"
|
||||
ng-model="bridge.settings.numberoflogmessages" min="100"
|
||||
max="65535"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UPNP Strict Handling</td>
|
||||
<td><input type="checkbox" ng-model="bridge.settings.upnpstrict"
|
||||
ng-true-value=true ng-false-value=false> {{bridge.settings.upnpstrict}}</td>
|
||||
<td><input type="checkbox"
|
||||
ng-model="bridge.settings.upnpstrict" ng-true-value=true
|
||||
ng-false-value=false> {{bridge.settings.upnpstrict}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Trace UPNP Calls</td>
|
||||
<td><input type="checkbox" ng-model="bridge.settings.traceupnp"
|
||||
ng-true-value=true ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
||||
<td><input type="checkbox"
|
||||
ng-model="bridge.settings.traceupnp" ng-true-value=true
|
||||
ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default backup">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge Settings Backup <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup Settings File Name</label>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">
|
||||
Bridge Settings Backup <a ng-click="toggle()"><span
|
||||
class={{imgUrl}} aria-hidden="true"></a>
|
||||
</h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
|
||||
Settings File Name</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupSettings(optionalbackupname)">Backup Settings</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.configs">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreSettings(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteSettingsBackup(backup)">Delete</button>
|
||||
</td>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupSettings(optionalbackupname)">Backup
|
||||
Settings</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.configs">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreSettings(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteSettingsBackup(backup)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,125 +1,146 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li role="presentation" class="active"><a href="#/veradevices">Vera
|
||||
Devices</a></li>
|
||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Vera Device List ({{bridge.veradevices.length}})</h2>
|
||||
<h2 class="panel-title">Vera Device List
|
||||
({{bridge.veradevices.length}})</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Vera Device, use the action buttons to generate the device addition information below automatically.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Vera Devices' list below will show what is already setup for your Vera.</p>
|
||||
<p>Also, use this select menu for which type of dim
|
||||
control you would like to be generated:
|
||||
<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>
|
||||
<p>Use the check boxes by the names to use the bulk addition feature. Select your items and dim control type if wanted, then click bulk add below.
|
||||
Your items will be added with on and off or dim and off if selected with the name of the device from the Vera.
|
||||
</p>
|
||||
<scrollable-table watch="bridge.veradevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]" value="{{veradevice.id}}" ng-checked="bulk.devices.indexOf(veradevice.id) > -1" ng-click="toggleSelection(veradevice.id)"> {{veradevice.name}}</td>
|
||||
<td>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
<td>{{veradevice.room}}</td>
|
||||
<td>{{veradevice.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<p>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any Vera Device, use the action buttons
|
||||
to generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured Vera Devices' list below will show
|
||||
what is already setup for your Vera.</p>
|
||||
<p>
|
||||
Also, use this select menu for which type of dim control you would
|
||||
like to be generated: <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>
|
||||
<p>Use the check boxes by the names to use the bulk addition
|
||||
feature. Select your items and dim control type if wanted, then click
|
||||
bulk add below. Your items will be added with on and off or dim and
|
||||
off if selected with the name of the device from the Vera.</p>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.veradevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name"><span><input type="checkbox" name="selectAll"
|
||||
value="{{selectAll}}"
|
||||
ng-checked="selectAll"
|
||||
ng-click="toggleSelectAll()"> Name</span></th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]"
|
||||
value="{{veradevice.id}}"
|
||||
ng-checked="bulk.devices.indexOf(veradevice.id) > -1"
|
||||
ng-click="toggleSelection(veradevice.id)">
|
||||
{{veradevice.name}}</td>
|
||||
<td>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
<td>{{veradevice.room}}</td>
|
||||
<td>{{veradevice.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkAddDevices(device_dim_control)">Bulk Add ({{bulk.devices.length}})</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Vera Devices <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></a></h2>
|
||||
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
|
||||
Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
|
||||
({{bulk.devices.length}})</button>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.veradevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{veradevice.name}}</td>
|
||||
<td>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
<td>{{veradevice.room}}</td>
|
||||
<td>{{veradevice.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(veradevice.id, 'veraDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured Vera Devices <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.veradevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{veradevice.name}}</td>
|
||||
<td>{{veradevice.id}}</td>
|
||||
<td>{{veradevice.category}}</td>
|
||||
<td>{{veradevice.room}}</td>
|
||||
<td>{{veradevice.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(veradevice.id, 'veraDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add Bridge Device for a Vera Device</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -132,26 +153,35 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-dim-url">Dim URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></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>
|
||||
<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 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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,106 +1,115 @@
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||
<li role="presentation" class="active"><a href="#/verascenes">Vera
|
||||
Scenes</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||
href="#/harmonydevices">Harmony Devices</a></li>
|
||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||
<li ng-if="bridge.showHue" role="presentation"><a
|
||||
href="#/huedevices">Hue Devices</a></li>
|
||||
<li ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL 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">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Vera Scene List</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">For any Vera Scene, use the action buttons to generate the device addition information below automatically.
|
||||
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||
The 'Already Configured Vera Scenes' list below will show what is already setup for your Vera.</p>
|
||||
|
||||
<scrollable-table watch="bridge.verascenes">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="verascene in bridge.verascenes | availableVeraSceneId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
<td>{{verascene.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildSceneUrls(verascene)">Generate Bridge Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Already Configured Vera Scenes <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any Vera Scene, use the action buttons
|
||||
to generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured Vera Scenes' list below will show what
|
||||
is already setup for your Vera.</p>
|
||||
</div>
|
||||
<ul ng-if="buttonsVisible" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<scrollable-table watch="bridge.verascenes">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
<td>{{verascene.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(verascene.id, 'veraScene')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<scrollable-table watch="bridge.verascenes">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="verascene in bridge.verascenes | availableVeraSceneId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
<td>{{verascene.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildSceneUrls(verascene)">Generate Bridge
|
||||
Device</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured Vera Scenes <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.verascenes">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="id">Id</th>
|
||||
<th sortable-header col="room">Room</th>
|
||||
<th sortable-header col="veraname">Vera</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{verascene.name}}</td>
|
||||
<td>{{verascene.id}}</td>
|
||||
<td>{{verascene.room}}</td>
|
||||
<td>{{verascene.veraname}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(verascene.id, 'veraScene')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a Bridge Device for a Vera scene</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
@@ -113,15 +122,24 @@
|
||||
</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>
|
||||
<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 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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
Reference in New Issue
Block a user