Compare commits

...

52 Commits

Author SHA1 Message Date
BWS Systems
32203b65be Merge pull request #189 from bwssytems/postv3.1fixes
Fixes #129 
Fixes #161 
Fixes #166 
Fixes #168 
Fixes #172 
Fixes #173 
Fixes #174 
Fixes #181
2016-10-18 08:42:01 -05:00
Admin
7e9600d2a7 Update release version number. 2016-10-18 08:35:27 -05:00
BWS Systems
dcc470486f Merge pull request #185 from martinbutt/master
Docs fix
2016-10-14 08:17:26 -05:00
Martin Butt
330adbdd4c Docs fix 2016-10-13 15:21:27 -07:00
Admin
23d43b0136 I got some more info from another source about the discovery responses
of a real hue. It sends three responses not just one. Also I have
updated the S/N UUID and the Hue Bridge ID creation as they are
different.
2016-10-10 13:23:29 -05:00
Admin
004276d3ea Changed handling of upnp rsponses from the upnp listener and the
huemulator udp calls to use the same response port.
2016-10-07 16:29:55 -05:00
Admin
e90e0f69ef Updated headers content type to be just "application/json" instead of
"application/json; charset utf-8".
2016-10-04 13:34:47 -05:00
Admin
7163a12384 Updating upnp responses to be more inline with what the hue hub does. To
do so, added the mac address as the id in the bridge id an, serial
number and uuid
2016-10-03 15:07:09 -05:00
Admin
bb65650e53 Added ip check if upnp config address is not available on the current
host. Added checks for content type and body for put and post requests.
2016-09-29 16:21:15 -05:00
Admin
7f7e96465b Switched default web port to be 80. This should resolve some issues with
first time configs and external apps. Changed upnp listener response to
previous style. Set default for link button presses status to true.
2016-09-29 09:25:47 -05:00
Admin
8ff7bc0120 Updated upnp response for M-SEARCH again. Updated devices to have
numbering more in line with how the hue bridge is done. Added special
generation of hue device unique id as the philips api spec shows.  Added
a renumber function to convert id's.
2016-09-28 16:18:53 -05:00
Admin
4da5f65d89 Updatting upnp responses 2016-09-26 17:03:30 -05:00
Admin
faa67827c6 Updated configuration items for hue responses. ADded call thru for hue
devices configured for state info. added dim content body.
2016-09-23 15:46:39 -05:00
Admin
bbce1f4235 Merge remote-tracking branch 'origin/master' into postv3.1fixes 2016-09-22 09:27:02 -05:00
BWS Systems
8575deadf1 Update readne.md for a missed version change
Changed line for download of ha-bridge jar
2016-09-22 09:02:28 -05:00
Admin
ad4015927c Add check for host is down exception on upnp send in listener and not
shutdown only a warning.
2016-09-21 16:33:57 -05:00
BWS Systems
f7df6951b0 Update README.md
Updated version to be the latest in the command examples
2016-09-20 08:29:01 -05:00
Admin
c20d046b30 Updated upnp response to be closer to the hue bridge v2 spec. Updated
handling for is on when bri is 0. Updated exec to check for empty call.
2016-09-15 15:41:59 -05:00
BWS Systems
20dedec8ab Merge pull request #158 from bwssytems/v3-updates
V3.1.0 updates
2016-09-01 11:11:40 -05:00
Admin
580c037b1e updated for unused imports 2016-09-01 11:07:34 -05:00
Admin
77cb064d60 Finished testing fixes and enhancements. 2016-09-01 11:03:11 -05:00
Admin
0e4319ea1d testing for changes: 3.0.0 not storing extended values (2.0.7 does),
update state not always working, Pi3 systemd not starting,
habridge.config created readable by everyone
2016-08-31 16:31:51 -05:00
BWS Systems
c61e623e23 Merge pull request #150 from tylerstraub/patch-1
Update README.md with caveats for using rc.local for starting on raspbian.
2016-08-02 15:45:54 -05:00
Tyler Straub
669483f686 Update README.md
Proposal to add some additional text under the Linux Automation section related to Issue #148. 

see: https://github.com/bwssytems/ha-bridge/issues/148
2016-08-02 12:20:02 -07:00
BWS Systems
5a59747bc9 Merge pull request #141 from bwssytems/hal-integration
Hal integration and other enhancement and fixes
2016-07-19 11:48:49 -05:00
Admin
53ec096c95 Updated version based on enhancement and bug implementations
Fixes #120
Fixes #122
Fixes #123
Fixes #135
Fixes #137
Fixes #138
Fixes #139
2016-07-19 11:42:07 -05:00
Admin
8ccb768391 Updated group 0 handling to be per hue api requirements. 2016-07-15 16:27:53 -05:00
Admin
9d84e2a180 fixed dim addition in bulk add
modified savef button to be active always in bridge settings
2016-07-12 16:26:53 -05:00
Admin
6a5fae583f Updating bridge control to activate save button on list updates. 2016-07-11 16:32:54 -05:00
Admin
8d15d0a0fb Tested api changes 2016-06-09 16:44:11 -05:00
Admin
d4b8b70a83 Added Hue Error Handling objects. Adding whitelsit control. 2016-06-08 16:41:46 -05:00
Admin
a276f97776 Testing api 1.10.0 2016-06-07 16:39:59 -05:00
Admin
9438b25538 Testing upnp response structures. 2016-06-06 16:42:46 -05:00
Admin
6c15ca2c3b Updated the Hue API v 1.11 and tested.
Testing the upnp changes, ongoing.
2016-06-03 16:25:00 -05:00
Admin
39782fa339 Updateing for API V 1.11 and Bridge V2 HUE handling. 2016-06-02 16:51:02 -05:00
Admin
d7e29e2ee5 Finished implementation of HAL calls to the API. Testing next. 2016-05-26 16:06:48 -05:00
Admin
6b4693eaaf Added Home control, Thermostat and other enhancements. 2016-05-25 16:09:29 -05:00
Admin
7f816b03d5 Fixed sizing of scrollable table to be dynamic. Added Appliances,
Theater and Custom devices to HAL interface. Added Select ALL feature
for bulk add screens.
2016-05-24 16:42:05 -05:00
Admin
ed3db4427b Updated view consistency. Fixed HAL bulk add 2016-05-23 16:45:47 -05:00
bwssystems
80ca8c3ca3 updated html pages to reference hal tab 2016-05-21 16:59:03 -05:00
bwssystems
e43473734e Finished draft HAL integration for lights type only 2016-05-21 16:49:12 -05:00
Admin
8a468b8352 First cut at HAL itegration 2016-05-20 16:13:48 -05:00
bwssystems
51ce10cfc7 Fixed build device button in Harmony Device helper tab.
Fixes #116
2016-05-15 12:25:28 -05:00
Admin
b5f7144c9c Update readme with a script construction. 2016-05-11 14:36:58 -05:00
Admin
86a931d383 added exec:// type for loops. updated button maptypeid naming.
Fixes #114
Fixes #115
2016-05-11 12:23:43 -05:00
Admin
3e890721c5 Fixed handling of dim and brigthen requests as they were not setting the
state appropriately for other systems. Fixed handling of data return
from an http call if the entity was empty.

Fixes #102
Fixes #107
2016-05-10 12:29:37 -05:00
Admin
62d1c64a3d Updated entitiy handling in HueMulator http call. 2016-05-06 08:30:37 -05:00
Admin
c025b186cd Updated a comment for the seb server port 2016-05-05 14:13:06 -05:00
Admin
e999c3a969 Update spelling in readme 2016-05-05 10:45:03 -05:00
Admin
351403e611 Fixed success parsing on http to return success. 2016-05-04 14:38:37 -05:00
Admin
c773477a43 Added delete dialog for confirmation. Fixed bug with text in
intensity.byte for vera device tab. Fixed issue with parsing replies for
http requests. Fixed Hue device bulk add. recommit


Fixes #100
Fixes #102
Fixes #104
Fixes #105
2016-05-04 11:45:51 -05:00
BWS Systems
5d1f0ce3b6 update versions in unit file 2016-05-02 15:41:01 -05:00
46 changed files with 4575 additions and 1728 deletions

106
README.md
View File

@@ -21,12 +21,15 @@ 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-3.2.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 (this includes the Raspberry Pi), 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
*NOTE ON RC.LOCAL*: Due to the way network subsystem is brought up on the pi, it uses the new systemctl to start services. The old style runlevel setup, which rc.local is part of does not get the benefit of knowing if the network has been fully realized. Starting ha-bridge from rc.local on next gen systems will cause unexpected results and issues with discovering registered devices.
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
```
[Unit]
Description=HA Bridge
@@ -35,11 +38,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-3.2.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-3.2.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/v3.2.0/ha-bridge-3.2.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-3.2.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>`
@@ -48,14 +83,14 @@ The default location for the configuration file to contain the settings for the
java -jar -Dconfig.file=/home/me/data/myhabridge.config ha-bridge-W.X.Y.jar
```
### -Dserver.port=`<port number>`
The default port number for the bridge is 8080. To override what the default or what is in the configuration file for this parameter, specify -Dserver.port=`<port number>` explicitly. This is especially helpful if you are running the ha-bridge for the first time and have another application on port 8080. The command line example:
The default port number for the bridge is 80. To override what the default or what is in the configuration file for this parameter, specify -Dserver.port=`<port number>` explicitly. This is especially helpful if you are running the ha-bridge for the first time and have another application on port 80. The command line example:
```
java -jar -Dserver.port=80 ha-bridge-W.X.Y.jar
```
## HA Bridge Usage and Configuration
This section will cover the basics of configuration and where this configuration can be done. This requires that you have started your bridge process and then have pointed your
favorite web interface by going to the http://<my ip address>:<port> or http://localhost:<port> with port you have assigned. The default quick link is http://localhost:8080 for yoru reference.
favorite web interface by going to the http://<my ip address>:<port> or http://localhost:<port> with port you have assigned. The default quick link is http://localhost for yoru reference.
### The Bridge Devices Tab
This screen allows you to see your devices you have configured for the ha-bridge to present to a controller, such as an Amazon Echo/Dot. It gives you a count of devices as there have been reports that the Echo only supports a limited number, but has been growing as of late, YMMV. You can test each device from this page as this calls the ha-bridge just as a controller would, i.e. the Echo. This is useful to make sure your configuration for each device is correct and for trouble shooting. You can also manages your devices as well by editing and making a new device copy as well as deleting it.
@@ -73,11 +108,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 80. 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 keep this port set 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
@@ -88,6 +123,10 @@ The password for the user name of the MyHarmony.com account for the Harmony Hub.
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
@@ -107,9 +146,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.
@@ -137,7 +176,7 @@ http://192.168.1.1:8180/set/this/value/${intensity.percent}
PUT
http://192.168.1.1:8280/set/this
ContentBody: {"someValue":"${intensity..byte}"}
ContentBody: {"someValue":"${intensity.byte}"}
udp://192.168.1.1:5000/0x45${intensity.percent}55
@@ -151,7 +190,7 @@ 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"},
@@ -165,7 +204,8 @@ 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 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.
@@ -185,6 +225,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.
@@ -217,13 +261,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
@@ -236,7 +282,7 @@ These calls can be accomplished with a REST tool using the following URLs and HT
### Add a device
Add a new device to the HA Bridge configuration. There is a basic examples and then three alternate examples for the add. Please note that dimming is supported as well as custom value based on the dimming number given from the echo. This is under the Dimming and Value example.
```
POST http://host:8080/api/devices
POST http://host/api/devices
```
#### Body Arguments
Name | Type | Description | Required
@@ -264,7 +310,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.
```
{
@@ -872,7 +918,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:
@@ -892,16 +938,16 @@ If this criteria is met, the following response is provided to the calling appli
HTTP/1.1 200 OK\r\n
CACHE-CONTROL: max-age=86400\r\n
EXT:\r\n
LOCATION: http://192.168.1.1:8080/description.xml\r\n
SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n
LOCATION: http://192.168.1.1:80/description.xml\r\n
SERVER: FreeRTOS/7.4.2 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
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201::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
GET http://host:80/description.xml
```
#### Response
```
@@ -911,18 +957,18 @@ GET http://host:8080/description.xml
<major>1</major>\n
<minor>0</minor>\n
</specVersion>\n
<URLBase>http://192.168.1.1:8080/</URLBase>\n
<URLBase>http://192.168.1.1:80/</URLBase>\n
<device>\n
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n
<friendlyName>HA-Bridge (192.168.1.1)</friendlyName>\n
<friendlyName>Philips hue (192.168.1.1)</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
<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:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n
<UDN>uuid:2f402f80-da50-11e1-9b23-001788102201</UDN>\n
<serviceList>\n
<service>\n
<serviceType>(null)</serviceType>\n

16
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>2.0.3</version>
<version>3.2.0</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
@@ -43,7 +43,7 @@
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>nest-controller</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@@ -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>

View File

@@ -9,7 +9,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import org.apache.http.conn.util.InetAddressUtils;
import org.slf4j.Logger;
@@ -20,6 +23,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,8 +39,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;
String theHarmonyAddress = null;
@@ -106,34 +108,18 @@ public class BridgeSettings extends BackupHandler {
}
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().equals("")) {
try {
log.info("Getting an IP address for this host....");
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
while (ifs.hasMoreElements() && addressString == null) {
NetworkInterface xface = ifs.nextElement();
Enumeration<InetAddress> addrs = xface.getInetAddresses();
String name = xface.getName();
int IPsPerNic = 0;
while (addrs.hasMoreElements() && IPsPerNic == 0) {
address = addrs.nextElement();
if (InetAddressUtils.isIPv4Address(address.getHostAddress())) {
log.debug(name + " ... has IPV4 addr " + address);
if(!name.equalsIgnoreCase(Configuration.LOOP_BACK_INTERFACE)|| !address.getHostAddress().equalsIgnoreCase(Configuration.LOOP_BACK_ADDRESS)) {
IPsPerNic++;
addressString = address.getHostAddress();
log.info("Adding " + addressString + " from interface " + name + " as our default upnp config address.");
}
}
}
}
} catch (SocketException e) {
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
return;
}
theBridgeSettings.setUpnpConfigAddress(addressString);
addressString = checkIpAddress(null, true);
if(addressString != null) {
theBridgeSettings.setUpnpConfigAddress(addressString);
log.info("Adding " + addressString + " as our default upnp config address.");
}
else
log.error("Cannot get ip address of this host.");
}
else {
addressString = checkIpAddress(theBridgeSettings.getUpnpConfigAddress(), false);
if(addressString == null)
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host.");
}
if(theBridgeSettings.getUpnpResponsePort() == null)
@@ -146,15 +132,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 +164,18 @@ 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());
if(jsonContent == null)
return;
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 +186,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;
@@ -227,6 +206,19 @@ public class BridgeSettings extends BackupHandler {
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
// set attributes to be for user only
// using PosixFilePermission to set file permissions
Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
// add owners permission
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
try {
Files.setPosixFilePermissions(filePath, perms);
} catch(UnsupportedOperationException e) {
log.info("Cannot set permissions for config file on this system as it is not supported. Continuing");
}
if(target != null)
Files.delete(target);
} catch (IOException e) {
@@ -235,15 +227,12 @@ 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...");
return null;
}
try {
content = new String(Files.readAllBytes(filePath));
} catch (IOException e) {
@@ -252,4 +241,39 @@ public class BridgeSettings extends BackupHandler {
return content;
}
private String checkIpAddress(String ipAddress, boolean checkForLocalhost) {
Enumeration<NetworkInterface> ifs = null;
try {
ifs = NetworkInterface.getNetworkInterfaces();
} catch(SocketException e) {
log.error("checkIpAddress cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
return null;
}
String addressString = null;
InetAddress address = null;
while (ifs.hasMoreElements() && addressString == null) {
NetworkInterface xface = ifs.nextElement();
Enumeration<InetAddress> addrs = xface.getInetAddresses();
String name = xface.getName();
int IPsPerNic = 0;
while (addrs.hasMoreElements() && IPsPerNic == 0) {
address = addrs.nextElement();
if (InetAddressUtils.isIPv4Address(address.getHostAddress())) {
log.debug(name + " ... has IPV4 addr " + address);
if(checkForLocalhost && (!name.equalsIgnoreCase(Configuration.LOOP_BACK_INTERFACE) || !address.getHostAddress().equalsIgnoreCase(Configuration.LOOP_BACK_ADDRESS))) {
IPsPerNic++;
addressString = address.getHostAddress();
log.debug("checkIpAddress found " + addressString + " from interface " + name);
}
else if(ipAddress != null && ipAddress.equalsIgnoreCase(address.getHostAddress())){
addressString = ipAddress;
IPsPerNic++;
}
}
}
}
return addressString;
}
}

View File

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

View File

@@ -6,7 +6,7 @@ public class Configuration {
public final static String DEFAULT_ADDRESS = "1.1.1.1";
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
public final static String LOOP_BACK_INTERFACE = "lo";
public final static String DEFAULT_WEB_PORT = "8080";
public final static String DEFAULT_WEB_PORT = "80";
public final static String DEFAULT_BUTTON_SLEEP = "100";
public static final int UPNP_DISCOVERY_PORT = 1900;
public static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";

View File

@@ -10,8 +10,10 @@ 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;
import com.bwssystems.util.UDPDatagramSender;
public class HABridge {
@@ -36,7 +38,9 @@ public class HABridge {
HarmonyHome harmonyHome;
NestHome nestHome;
HueHome hueHome;
HalHome halHome;
HueMulator theHueMulator;
UDPDatagramSender udpSender;
UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener;
SystemControl theSystem;
@@ -66,30 +70,41 @@ 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);
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome);
theHueMulator.setupServer();
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome);
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
theSettingResponder.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();
// start the upnp ssdp discovery listener
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl());
if(theUpnpListener.startListening())
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
else
bridgeSettings.getBridgeControl().setStop(true);
// setup the UDP Datagram socket to be used by the HueMulator and the upnpListener
udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort());
if(udpSender == null) {
bridgeSettings.getBridgeControl().setStop(true);
}
else {
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome, udpSender);
theHueMulator.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();
// start the upnp ssdp discovery listener
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender);
if(theUpnpListener.startListening())
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();
nestHome = null;
harmonyHome.shutdownHarmonyHubs();
harmonyHome = null;
udpSender.closeResponseSocket();
}
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
System.exit(0);

View File

@@ -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,16 +71,25 @@ 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());
response.setName(device.getName());
response.setUniqueid(device.getId());
response.setUniqueid(device.getUniqueid());
response.setManufacturername("Philips");
response.setType("Dimmable light");
response.setModelid("LWB004");
response.setSwversion("66012040");
response.setLuminaireuniqueid(null);
return response;
}

View File

@@ -17,6 +17,7 @@ public class DeviceState {
private String colormode;
private boolean reachable;
private List<Double> xy;
// private int transitiontime;
public boolean isOn() {
return on;
@@ -97,7 +98,15 @@ public class DeviceState {
public void setXy(List<Double> xy) {
this.xy = xy;
}
public static DeviceState createDeviceState() {
// public int getTransitiontime() {
// return transitiontime;
// }
// public void setTransitiontime(int transitiontime) {
// this.transitiontime = transitiontime;
// }
public static DeviceState createDeviceState() {
DeviceState newDeviceState = new DeviceState();
newDeviceState.fillIn();
// newDeviceState.setColormode("none");

View File

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

View File

@@ -0,0 +1,44 @@
package com.bwssystems.HABridge.api.hue;
import java.util.List;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
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(List<DeviceDescriptor> deviceList) {
String[] theList = new String[deviceList.size()];
int i = 0;
for (DeviceDescriptor device : deviceList) {
theList[i] = device.getId();
i++;
}
GroupResponse theResponse = new GroupResponse();
theResponse.setAction(DeviceState.createDeviceState());
theResponse.setName("Lightset 0");
theResponse.setLights(theList);
return theResponse;
}
}

View File

@@ -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<>());

View File

@@ -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,19 +28,23 @@ 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.15.0");
aConfig.setPortalservices(false);
aConfig.setGateway(ipaddress);
aConfig.setSwversion("01005215");
aConfig.setLinkbutton(false);
aConfig.setSwversion("01035934");
aConfig.setLinkbutton(true);
aConfig.setIpaddress(ipaddress);
aConfig.setProxyport(0);
aConfig.setSwupdate(Swupdate.createSwupdate());
@@ -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.createConfig(name, ipaddress).getHueBridgeIdFromMac());
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;
}
}

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

View File

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

View File

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

View File

@@ -0,0 +1,151 @@
package com.bwssystems.HABridge.api.hue;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
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.15.0");
aConfig.setSwversion("01035934");
aConfig.setName(name);
aConfig.setBridgeid(aConfig.getHueBridgeIdFromMac());
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();
}
public String getSNUUIDFromMac()
{
StringTokenizer st = new StringTokenizer(this.getMac(), ":");
String bridgeUUID = "";
while(st.hasMoreTokens()) {
bridgeUUID = bridgeUUID + st.nextToken();
}
bridgeUUID = bridgeUUID.toLowerCase();
return bridgeUUID.toLowerCase();
}
protected String getHueBridgeIdFromMac()
{
String cleanMac = this.getSNUUIDFromMac();
String bridgeId = cleanMac.substring(0, 6) + "FFFE" + cleanMac.substring(6);
return bridgeId.toUpperCase();
}
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;
}
}

View File

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

View File

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

View File

@@ -11,6 +11,9 @@ public class DeviceDescriptor{
@SerializedName("id")
@Expose
private String id;
@SerializedName("uniqueid")
@Expose
private String uniqueid;
@SerializedName("name")
@Expose
private String name;
@@ -50,6 +53,9 @@ public class DeviceDescriptor{
@SerializedName("contentBodyOff")
@Expose
private String contentBodyOff;
@SerializedName("contentBodyDim")
@Expose
private String contentBodyDim;
private DeviceState deviceState;
@@ -125,6 +131,14 @@ public class DeviceDescriptor{
this.id = id;
}
public String getUniqueid() {
return uniqueid;
}
public void setUniqueid(String uniqueid) {
this.uniqueid = uniqueid;
}
public String getHeaders() {
return headers;
}
@@ -165,6 +179,14 @@ public class DeviceDescriptor{
this.contentBodyOff = contentBodyOff;
}
public String getContentBodyDim() {
return contentBodyDim;
}
public void setContentBodyDim(String contentBodyDim) {
this.contentBodyDim = contentBodyDim;
}
public DeviceState getDeviceState() {
if(deviceState == null)
deviceState = DeviceState.createDeviceState();

View File

@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.dao;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -9,8 +10,11 @@ import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,7 +33,7 @@ public class DeviceRepository extends BackupHandler {
private Map<String, DeviceDescriptor> devices;
private Path repositoryPath;
private Gson gson;
final private Random random = new Random();
private Integer maxId;
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
public DeviceRepository(String deviceDb) {
@@ -41,6 +45,7 @@ public class DeviceRepository extends BackupHandler {
repositoryPath = null;
repositoryPath = Paths.get(deviceDb);
setupParams(repositoryPath, ".bk", "device.db-");
maxId = 1;
_loadRepository(repositoryPath);
}
@@ -57,6 +62,9 @@ public class DeviceRepository extends BackupHandler {
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
for(int i = 0; i < list.length; i++) {
put(list[i].getId(), list[i]);
if(Integer.decode(list[i].getId()) > maxId) {
maxId = Integer.decode(list[i].getId());
}
}
}
}
@@ -84,8 +92,17 @@ public class DeviceRepository extends BackupHandler {
for(int i = 0; i < descriptors.length; i++) {
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
devices.remove(descriptors[i].getId());
else
descriptors[i].setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
else {
descriptors[i].setId(String.valueOf(maxId));
maxId++;
}
if(descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
BigInteger bigInt = BigInteger.valueOf(Integer.decode(descriptors[i].getId()));
byte[] theBytes = bigInt.toByteArray();
String hexValue = DatatypeConverter.printHexBinary(theBytes);
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
}
put(descriptors[i].getId(), descriptors[i]);
theNames = theNames + " " + descriptors[i].getName() + ", ";
}
@@ -94,6 +111,28 @@ public class DeviceRepository extends BackupHandler {
log.debug("Save device(s): " + theNames);
}
public void renumber() {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
Iterator<DeviceDescriptor> deviceIterator = list.iterator();
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();;
maxId = 1;
log.debug("Renumber devices.");
while(deviceIterator.hasNext()) {
DeviceDescriptor theDevice = deviceIterator.next();
theDevice.setId(String.valueOf(maxId));
BigInteger bigInt = BigInteger.valueOf(maxId);
byte[] theBytes = bigInt.toByteArray();
String hexValue = DatatypeConverter.printHexBinary(theBytes);
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
newdevices.put(theDevice.getId(), theDevice);
maxId++;
}
devices = newdevices;
String jsonValue = gson.toJson(findAll());
repositoryWriter(jsonValue, repositoryPath);
}
public String delete(DeviceDescriptor aDescriptor) {
if (aDescriptor != null) {
devices.remove(aDescriptor.getId());

View File

@@ -8,6 +8,7 @@ import static spark.Spark.delete;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -21,6 +22,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 +42,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 +67,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 +271,31 @@ 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());
// http://ip_address:port/api/devices/exec/renumber CORS request
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "POST");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
post (API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
log.debug("Renumber devices.");
deviceRepository.renumber();
return null;
}, new JsonTransformer());
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
log.debug("Get backup filenames");
response.status(HttpStatus.SC_OK);

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,8 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeControlDescriptor;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.Configuration;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.util.UDPDatagramSender;
import java.io.IOException;
import java.net.*;
@@ -16,16 +18,43 @@ import org.apache.http.conn.util.*;
public class UpnpListener {
private Logger log = LoggerFactory.getLogger(UpnpListener.class);
private int upnpResponsePort;
private UDPDatagramSender theUDPDatagramSender;
private int httpServerPort;
private String responseAddress;
private boolean strict;
private boolean traceupnp;
private BridgeControlDescriptor bridgeControl;
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: upnp:rootdevice\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s::upnp:rootdevice\r\n\r\n";
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: uuid:2f402f80-da50-11e1-9b23-%s\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) {
super();
upnpResponsePort = theSettings.getUpnpResponsePort();
theUDPDatagramSender = aUdpDatagramSender;
httpServerPort = Integer.valueOf(theSettings.getServerPort());
responseAddress = theSettings.getUpnpConfigAddress();
strict = theSettings.isUpnpStrict();
@@ -36,33 +65,9 @@ public class UpnpListener {
@SuppressWarnings("resource")
public boolean startListening(){
log.info("UPNP Discovery Listener starting....");
DatagramSocket responseSocket = null;
MulticastSocket upnpMulticastSocket = null;
Enumeration<NetworkInterface> ifs = null;
boolean portLoopControl = true;
int retryCount = 0;
while(portLoopControl) {
try {
responseSocket = new DatagramSocket(upnpResponsePort);
if(retryCount > 0)
log.info("Upnp Response Port issue, found open port: " + upnpResponsePort);
portLoopControl = false;
} catch(SocketException e) {
if(retryCount == 0)
log.warn("Upnp Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + upnpResponsePort);
if(retryCount >= 20) {
portLoopControl = false;
log.error("Upnp Response Port issue, could not find open port - last port tried: " + upnpResponsePort + " with message: " + e.getMessage());
return false;
}
}
if(portLoopControl) {
retryCount++;
upnpResponsePort++;
}
}
try {
upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
} catch(IOException e){
@@ -119,10 +124,14 @@ public class UpnpListener {
upnpMulticastSocket.receive(packet);
if (isSSDPDiscovery(packet)) {
try {
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
sendUpnpResponse(packet.getAddress(), packet.getPort());
} catch (IOException e) {
log.error("UpnpListener encountered an error sending upnp response packet. Shutting down", e);
error = true;
if(e.getMessage().equalsIgnoreCase("Host is down"))
log.warn("UpnpListener encountered an error sending upnp response packet as requesting host is now not available. IP: " + packet.getAddress().getHostAddress());
else {
log.error("UpnpListener encountered an error sending upnp response packet. Shutting down", e);
error = true;
}
}
}
} catch (IOException e) {
@@ -139,7 +148,6 @@ public class UpnpListener {
}
}
upnpMulticastSocket.close();
responseSocket.close();
if (bridgeControl.isReinit())
log.info("UPNP Discovery Listener - ended, restart found");
if (bridgeControl.isStop())
@@ -168,7 +176,8 @@ public class UpnpListener {
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
}
log.debug("isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
else
log.debug("isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
return true;
}
else if (!strict)
@@ -178,7 +187,8 @@ public class UpnpListener {
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
}
log.debug("isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
else
log.debug("isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
return true;
}
}
@@ -189,21 +199,35 @@ 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 {
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null;
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
if(traceupnp)
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
String bridgeId = null;
String bridgeSNUUID = null;
HuePublicConfig aHueConfig = HuePublicConfig.createConfig("temp", responseAddress);
bridgeId = aHueConfig.getBridgeid();
bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
socket.send(response);
log.debug("sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
}
}

View File

@@ -4,6 +4,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import static spark.Spark.get;
@@ -15,26 +16,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>%s</serialNumber>\n"
+ "<UDN>uuid:2f402f80-da50-11e1-9b23-%s</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,12 +73,13 @@ 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());
String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress()).getSNUUIDFromMac();
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac);
if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber);
else
@@ -72,5 +99,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 "";
} );
}
}

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

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

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

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

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

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

View File

@@ -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>.
*

View File

@@ -0,0 +1,72 @@
package com.bwssystems.util;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UDPDatagramSender {
private Logger log = LoggerFactory.getLogger(UDPDatagramSender.class);
private DatagramSocket responseSocket = null;
private int udpResponsePort;
public UDPDatagramSender() {
super();
udpResponsePort = 0;
}
public static UDPDatagramSender createUDPDatagramSender(int udpResponsePort) {
UDPDatagramSender aDatagramSender = new UDPDatagramSender();
if(aDatagramSender.initializeSocket(udpResponsePort))
return aDatagramSender;
else
return null;
}
private boolean initializeSocket(int port) {
log.info("Initializing UDP response Seocket...");
udpResponsePort = port;
boolean portLoopControl = true;
int retryCount = 0;
while(portLoopControl) {
try {
responseSocket = new DatagramSocket(udpResponsePort);
portLoopControl = false;
} catch(SocketException e) {
if(retryCount == 0)
log.warn("UDP Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + udpResponsePort);
if(retryCount >= 20) {
portLoopControl = false;
log.error("UDP Response Port issue, could not find open port - last port tried: " + udpResponsePort + " with message: " + e.getMessage());
return false;
}
}
if(portLoopControl) {
retryCount++;
udpResponsePort++;
}
}
log.info("UDP response Seocket initialized to: " + udpResponsePort);
return true;
}
public int getUdpResponsePort() {
return udpResponsePort;
}
public void closeResponseSocket() {
responseSocket.close();
}
public void sendUDPResponse(String udpResponse, InetAddress requester, int sourcePort) throws IOException {
log.debug("Sending response string: <<<" + udpResponse + ">>>");
if(responseSocket == null)
throw new IOException("Socket not initialized");
DatagramPacket response = new DatagramPacket(udpResponse.getBytes(), udpResponse.length(), requester, sourcePort);
responseSocket.send(response);
}
}

View File

@@ -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;

View File

@@ -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;
@@ -100,12 +115,24 @@ app.service('bridgeService', function ($http, $window, ngToast) {
);
};
this.renumberDevices = function () {
return $http.post(this.state.base + "/exec/renumber").then(
function (response) {
self.viewDevices();
},
function (error) {
self.displayError("Cannot renumber devices from habridge: ", error);
}
);
};
this.clearDevice = function () {
if(self.state.device == null)
self.state.device = [];
self.state.device.id = "";
self.state.device.mapType = null;
self.state.device.mapId = null;
self.state.device.uniqueid = null;
self.state.device.name = "";
self.state.device.onUrl = "";
self.state.device.dimUrl = "";
@@ -116,6 +143,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
self.state.device.httpVerb = null;
self.state.device.contentType = null;
self.state.device.contentBody = null;
self.state.device.contentBodyDim = null;
self.state.device.contentBodyOff = null;
self.state.olddevicename = "";
};
@@ -155,6 +183,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 +196,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 +326,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 +371,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 +612,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 +663,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,12 +786,20 @@ 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);
$location.path('/editdevice');
};
$scope.renumberDevices = function() {
bridgeService.renumberDevices();
};
$scope.backupDeviceDb = function (optionalbackupname) {
bridgeService.backupDeviceDb(optionalbackupname);
};
@@ -789,11 +859,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,22 +986,31 @@ 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,
contentType: $scope.device.contentType,
contentBody: $scope.device.contentBody,
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
}
}
}
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 +1019,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 +1053,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 +1087,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 +1133,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 +1255,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 +1311,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,21 +1320,31 @@ 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,
contentType: $scope.device.contentType,
contentBody: $scope.device.contentBody,
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
}
}
}
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 +1353,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 +1387,330 @@ 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,
contentBodyDim: $scope.device.contentBodyDim,
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 +1946,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 = [];

View File

@@ -1,40 +1,55 @@
<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>
<form name="form">
<p>
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
</p>
</form>
<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 +60,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 +124,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>

View File

@@ -1,210 +1,256 @@
<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 class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-unique-id">Unique Id (used for Hue responses) </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-unique-id"
ng-model="device.uniqueid" placeholder="AA:BB:CC:DD:EE:FF-XX" readonly>
</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">
<textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
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-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-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-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-dim-url">Dim
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-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-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-off-url">Off
URL </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: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></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-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-headers">HTTP
Headers </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">
<textarea rows="3" class="form-control" id="device-headers"
ng-model="device.headers"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></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-type">Content Type
</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-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-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-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-type">Content Type </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">
<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-off">Content Body Off</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-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"
ng-model="device.contentBody"
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div>
</form>
</li>
</ul>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div ng-if="device.httpVerb" class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-content-body-dim">Content Body Dim</label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-dim"
ng-model="device.contentBodyDim"
placeholder="Content Body Dim for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div ng-if="device.httpVerb" class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control"
id="device-content-body-off" ng-model="device.contentBodyOff"
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
</form>
</div>

View File

@@ -1,230 +1,263 @@
<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
[{&quot;item&quot;:&quot;the payload&quot;},{&quot;item&quot;:&quot;another payload&quot;}] 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 [{&quot;item&quot;:&quot;the
payload&quot;},{&quot;item&quot;:&quot;another payload&quot;}] 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: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></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: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></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-dim">Content Body Dim</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-dim"
ng-model="device.contentBodyDim"
placeholder="Content Body Dim for specific GET/PUT/POST type"></textarea>
</div>
</form>
</li>
</ul>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
<div ng-if="device.httpVerb" class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control"
id="device-content-body-off" ng-model="device.contentBodyOff"
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div>
<div class="clearfix visible-xs"></div>
</div>
</div>
</form>
</div>

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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>