mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 08:13:23 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7acff9f54 | ||
|
|
9c4b428c86 | ||
|
|
80b3e87e44 | ||
|
|
e14482e232 | ||
|
|
08166c0ebf | ||
|
|
373515e1ed | ||
|
|
68f38e1d95 | ||
|
|
90f2bce282 | ||
|
|
3eba9b9245 | ||
|
|
7d39b79e05 | ||
|
|
407b0e0bd5 | ||
|
|
9baff8d403 | ||
|
|
23a6c7059c | ||
|
|
84fb79f9d9 | ||
|
|
3702de8efd | ||
|
|
f0ab9afd66 | ||
|
|
e5c4e09543 | ||
|
|
425ac9fb91 | ||
|
|
32203b65be | ||
|
|
7e9600d2a7 | ||
|
|
dcc470486f | ||
|
|
330adbdd4c | ||
|
|
23d43b0136 | ||
|
|
004276d3ea | ||
|
|
e90e0f69ef | ||
|
|
7163a12384 | ||
|
|
bb65650e53 | ||
|
|
7f7e96465b | ||
|
|
8ff7bc0120 | ||
|
|
4da5f65d89 | ||
|
|
faa67827c6 | ||
|
|
bbce1f4235 | ||
|
|
8575deadf1 | ||
|
|
ad4015927c | ||
|
|
f7df6951b0 | ||
|
|
c20d046b30 | ||
|
|
20dedec8ab | ||
|
|
580c037b1e | ||
|
|
77cb064d60 | ||
|
|
0e4319ea1d | ||
|
|
c61e623e23 | ||
|
|
669483f686 | ||
|
|
5a59747bc9 | ||
|
|
53ec096c95 | ||
|
|
8ccb768391 | ||
|
|
9d84e2a180 | ||
|
|
6a5fae583f | ||
|
|
8d15d0a0fb | ||
|
|
d4b8b70a83 | ||
|
|
a276f97776 | ||
|
|
9438b25538 | ||
|
|
6c15ca2c3b | ||
|
|
39782fa339 | ||
|
|
d7e29e2ee5 | ||
|
|
6b4693eaaf | ||
|
|
7f816b03d5 | ||
|
|
ed3db4427b | ||
|
|
80ca8c3ca3 | ||
|
|
e43473734e | ||
|
|
8a468b8352 | ||
|
|
51ce10cfc7 | ||
|
|
b5f7144c9c | ||
|
|
86a931d383 |
177
README.md
177
README.md
@@ -1,5 +1,7 @@
|
||||
# ha-bridge
|
||||
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
|
||||
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo or Google Home. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
|
||||
|
||||
**ATTENTION: This requires a physical Amazon Echo, Dot or Tap and does not work with prototype devices built using the Alexa Voice Service e.g. Amazon's Alexa AVS Sample App and Sam Machin's AlexaPi. The AVS version does not have any capability for Hue Bridge discovery!**
|
||||
|
||||
In the cases of systems that require authorization and/or have API's that cannot be handled in the current method, a module may need to be built. The Harmony Hub is such a module and so is the Nest module. The Bridge has helpers to build devices for the gateway for the Logitech Harmony Hub, Vera, Vera Lite or Vera Edge, Nest and the ability to proxy all of your real Hue bridges behind this bridge.
|
||||
|
||||
@@ -21,12 +23,19 @@ Then locate the jar and start the server with:
|
||||
ATTENTION: This requires JDK 1.8 to run
|
||||
|
||||
```
|
||||
java -jar ha-bridge-2.0.5.jar
|
||||
java -jar ha-bridge-3.5.0.jar
|
||||
```
|
||||
### Automation on Linux systems
|
||||
To have this conigured and running automatically ther eare a few resources to use. One is using Docker and a docker container has 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
|
||||
|
||||
Create the directory and make sure that ha-bridge-3.5.0.jar is in your /home/pi/habridge directory.
|
||||
```
|
||||
pi@raspberrypi:~ $ mkdir habridge
|
||||
pi@raspberrypi:~ $ cd habridge
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v3.5.0/ha-bridge-3.5.0.jar
|
||||
```
|
||||
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
|
||||
|
||||
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 +44,38 @@ 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.5.jar
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-3.5.0.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
Basic script setup to run the bridge on a pi.
|
||||
|
||||
*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.
|
||||
|
||||
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 -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-3.5.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
chmod 777 /home/pi/habridge/habridge-log.txt
|
||||
```
|
||||
Exit and save the file with ctrl-X and follow the prompts and then execute on the command line:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ chmod u+x starthabridge.sh
|
||||
```
|
||||
Then execute the script:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ ./starthabridge.sh
|
||||
```
|
||||
You should now be running the bridge. Check for errors:
|
||||
```
|
||||
pi@raspberrypi:~/habridge $ tail -f habridge-log.txt
|
||||
```
|
||||
## Available Arguments
|
||||
Arguments are now deprecated. The ha-bridge will use the old -D arguments and populate the configuration screen, Brisge Control Tab, which can now be saved to a file and will not be needed. There is only one optional argument that overrides and that is the location of the configuration file. The default is the relative path "data/habridge.config".
|
||||
### -Dconfig.file=`<filepath>`
|
||||
@@ -48,14 +84,15 @@ 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
|
||||
```
|
||||
Note: if using with a Google Home device, port 80 *must* be used.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -72,22 +109,30 @@ The default location for the configuration file to contain the settings for the
|
||||
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify `<directory>/<filename> explicitly.
|
||||
#### 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 IP Address
|
||||
The server defaults to all interfaces on the machine (0.0.0.0). Replace this value with the server ipv4 address you would like to use as the address that will bind to a specific ip address on an interface if you would like. This is only necessary if you want to isolate how access is handled to the web UI.
|
||||
#### Web Server Port
|
||||
The server defaults to running on port 8080. To override what the default is, specify a different number. ATTENTION: If you want to use any of the apps made for the Hue to control this bridge, you should set this port to 80.
|
||||
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
|
||||
The user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub features.
|
||||
depracated
|
||||
#### Harmony Password
|
||||
The password for the user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub Features.
|
||||
depracated
|
||||
#### Hue Names and IP Addresses
|
||||
Provide IP Addresses of your Hue Bridges that you want to proxy through the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will passthru the call it receives to the target Hue and device you configure.
|
||||
|
||||
Don't forget - You will need to push the link button when you got to the Hue Tab the first time ater the process comes up. (The user name is not persistent when the process comes up.)
|
||||
#### HAL Names and IP Addresses
|
||||
Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure.
|
||||
#### HAL Token
|
||||
The token you generate or give to a HAL and must be the same for all HAL's you have identified. This needs to be given if you are using the HAL features.
|
||||
#### MQTT Client IDs and IP Addresses
|
||||
Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured yourMQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish mqtt messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages.
|
||||
#### 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
|
||||
@@ -137,7 +182,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,11 +196,11 @@ 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. Also within the item format you can specify delay in milliseconds and count per item. These new paramters work on device buttons for the Harmony as well.
|
||||
Format Example in the URL areas:
|
||||
```
|
||||
[{"item":"http://192.168.1.1:8180/do/this/thing"},
|
||||
{"item":"http://192.168.1.1:8180/do/the/next/thing"},
|
||||
{"item":"http://192.168.1.1:8180/do/the/next/thing","delay":1000,"count":2},
|
||||
"item":"http://192.168.1.1:8180/do/another/thing"}]
|
||||
|
||||
|
||||
@@ -165,7 +210,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 +231,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.
|
||||
@@ -228,6 +278,39 @@ DIM Commands |
|
||||
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.
|
||||
|
||||
## Google Assistant
|
||||
Google Home is supported as of v3.2.0 and forward, but only if the bridge is running on port 80.
|
||||
|
||||
Use the Google Home app on a phone to add new "home control" devices by going into `Settings / Home Control / +`
|
||||
as described [here](https://support.google.com/googlehome/answer/7124115?hl=en&ref_topic=7125624#homecontrol).
|
||||
Click on `Philips Hue` under the `Add new` section. If ha-bridge is on the same network as the
|
||||
phone as well as the Home device, then the app should quickly pass through the pairing step and
|
||||
populate with all of the devices. If instead it takes you to a Philips Hue login page, this means
|
||||
that the bridge was not properly discovered.
|
||||
|
||||
Then you can say "OK Google, Turn on the office light" or whatever name you have given your configured devices.
|
||||
|
||||
The Google Assistant can also group lights into rooms as described in the main [help article](https://support.google.com/googlehome/answer/7072090?hl=en&ref_topic=7029100).
|
||||
|
||||
Here is the table of items to use to tell Google what you want to do. Note that either "OK Google"
|
||||
or "Hey Google" can be used as a trigger.
|
||||
|
||||
To do this: | Say "Hey Google", then...
|
||||
------------|--------------------------
|
||||
To turn on/off a light | "Turn on <light name>"
|
||||
Dim a light | "Dim the <light name>"
|
||||
Brighten a light | "Brighten the <light name>"
|
||||
Set a light brightness to a certain percentage | "Set <light name> to 50%"
|
||||
Dim/Brighten lights by a certain percentage | "Dim/Brighten <light name> by 50%"
|
||||
Turn on/off all lights in room | “Turn on/off lights in <room name>"
|
||||
Turn on/off all lights | “Turn on/off all of the lightsâ€<C3A2>
|
||||
|
||||
To see what Home thinks you said, you can ask "Hey Google, What did I say?" or check the history in the app.
|
||||
|
||||
New or removed devices are picked up automatically as soon as they are added/removed from ha-bridge.
|
||||
No re-discovery step is necessary.
|
||||
|
||||
## Configuration REST API Usage
|
||||
This section will describe the REST api available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
||||
```
|
||||
@@ -238,7 +321,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
|
||||
@@ -888,22 +971,50 @@ ST: upnp:rootdevice\r\n
|
||||
ST: ssdp:all\r\n
|
||||
```
|
||||
|
||||
If this criteria is met, the following response is provided to the calling application:
|
||||
If this criteria is met, the following three responses are provided to the calling application:
|
||||
|
||||
```
|
||||
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
|
||||
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
|
||||
HTTP/1.1 200 OK
|
||||
HOST: 239.255.255.250:1900
|
||||
CACHE-CONTROL: max-age=100
|
||||
EXT:
|
||||
LOCATION: http://192.168.1.1:80/description.xml
|
||||
SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0
|
||||
hue-bridgeid: 001E06FFFE123456
|
||||
ST: upnp:rootdevice
|
||||
USN: uuid:2f402f80-da50-11e1-9b23-001e06123456::upnp:rootdevice
|
||||
```
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
HOST: 239.255.255.250:1900
|
||||
CACHE-CONTROL: max-age=100
|
||||
EXT:
|
||||
LOCATION: http://192.168.1.1:80/description.xml
|
||||
SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0
|
||||
hue-bridgeid: 001E06FFFE123456
|
||||
ST: uuid:2f402f80-da50-11e1-9b23-001e06123456
|
||||
USN: uuid:2f402f80-da50-11e1-9b23-001e06123456
|
||||
```
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
HOST: 239.255.255.250:1900
|
||||
CACHE-CONTROL: max-age=100
|
||||
EXT:
|
||||
LOCATION: http://192.168.1.1:80/description.xml
|
||||
SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0
|
||||
hue-bridgeid: 001E06FFFE123456
|
||||
ST: urn:schemas-upnp-org:device:basic:1
|
||||
USN: uuid:2f402f80-da50-11e1-9b23-001e06123456
|
||||
```
|
||||
|
||||
Note that `192.168.1.1` and `12345` are replaced with the actual IP address and last 6 digits of the MAC address, respectively.
|
||||
|
||||
|
||||
### 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 response is the correct device.
|
||||
#### Get Description
|
||||
```
|
||||
GET http://host:8080/description.xml
|
||||
GET http://host:80/description.xml
|
||||
```
|
||||
#### Response
|
||||
```
|
||||
@@ -913,18 +1024,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
|
||||
|
||||
160
kodivolume.md
Normal file
160
kodivolume.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Kodi volume control using dim commands & JSON-RPC
|
||||
|
||||
You can use HA Bridge to adjust the Kodi software volume output. This allows you to use dim commands and set the volume level with percentage values.
|
||||
### What is JSON-RPC?
|
||||
|
||||
The short answer is JSON-RPC an interface to communicate with Kodi. [See the official Kodi Wiki for more info](http://kodi.wiki/view/JSON-RPC_API)
|
||||
### Setup Kodi to allow control through JSON-RPC
|
||||
|
||||
In Kodi navigate to Settings/Services/Control ([screenshot](http://kodi.wiki/view/Settings/Services/Control))
|
||||
|
||||
Turn **ON** the following:
|
||||
- Allow control of Kodi via HTTP
|
||||
- Allow remote control from applications on this system
|
||||
- Allow remote control from applications on other systems
|
||||
|
||||
Change the **username** to something unique and set a strong **password**.
|
||||
|
||||
Make a note of the **PORT**
|
||||
### Adding the device to HA Bridge
|
||||
|
||||
Access the HA Bridge Configuration in your browser and open the **Manual Add** tab.
|
||||
#### Name
|
||||
|
||||
Give the device a unique name that doesn<73>t include **<EFBFBD>volume<EFBFBD>** as it will cause conflicts with the Echo<68>s built in volume controls. A device name of **<EFBFBD>cody sound<6E>** works well.
|
||||
#### Device type
|
||||
|
||||
Select **TCP** in the dropdown
|
||||
### URLs
|
||||
|
||||
This section might seem a little long winded and if you know what you are doing then feel free to jump ahead.
|
||||
#### Building the URL
|
||||
|
||||
We need to log into the Kodi web server without having to fill in the popup each time. You can do this by putting the username and password in the URL. It is not a good idea to do this on other websites as it does put your password in clear view, but for your local network it is fine.
|
||||
|
||||
Use the example below replacing the relevant sections with the details that you defined in the Kodi settings screen in the first step. Replacing the IP with the address of the machine that Kodi is running on.
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc
|
||||
```
|
||||
##### Testing the URL in a browser
|
||||
|
||||
Before you continue, open your custom URL in a browser (making sure Kodi is running). If all is working as it should you will see a big page of JSON that starts with:
|
||||
|
||||
``` json
|
||||
{
|
||||
"description": "JSON-RPC API of XBMC",
|
||||
"id": "http://xbmc.org/jsonrpc/ServiceDescription.json",
|
||||
```
|
||||
|
||||
If you don<6F>t see something that looks like the code above, then go back and double check your settings.
|
||||
#### The JSON request
|
||||
|
||||
The URL is what connects you to Kodi, JSON is what is used to communicate with it. The JSON that is used to set the volume level is:
|
||||
|
||||
``` json
|
||||
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
||||
```
|
||||
##### Joining the URL and JSON
|
||||
|
||||
Join the two together by adding `?request=` to the end of the URL and then add the JSON to the end of the request. You will end up with something like:
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
||||
```
|
||||
##### Testing the request in a browser
|
||||
|
||||
Go ahead and test the combined URL/JSON in a browser changing **100** to whatever level you want to set. Kodi should adjust the volume accordingly, try a few different levels to be sure it is working correctly.
|
||||
|
||||
The browser will reformat the URL each time you press return so don<6F>t build the URL in the browser bar without making a copy first.
|
||||
|
||||
Ideally build the URL in a text document which you can easily edit and then copy/paste each time.
|
||||
#### Prepare the three URLs
|
||||
|
||||
You want to end up with three full URLs in your text file, one for each of the commands.
|
||||
|
||||
**ON**
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
||||
```
|
||||
|
||||
**DIM**
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":45},"id":1}
|
||||
```
|
||||
|
||||
**OFF**
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
|
||||
```
|
||||
#### Encoding the JSON part
|
||||
|
||||
You should now be able to control the volume of Kodi using the structured URL you built above in a browser. If you can<61>t get it to work in a browser then you won<6F>t be able to get it to work in HA Bridge.
|
||||
|
||||
In order for HA Bridge to send the JSON request you need to encode the URL. This means we take this:
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
||||
```
|
||||
|
||||
And turn it into this:
|
||||
|
||||
```
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=%7B%22jsonrpc%22%3A%222.0%22%2C%22method%22%3A%22Application.SetVolume%22%2C%22params%22%3A%7B%22volume%22%3A100%7D%2C%22id%22%3A1%7D
|
||||
```
|
||||
|
||||
Note that we are only encoding the JSON, the URL part we leave as is.
|
||||
|
||||
Using the online tool [www.url-encode-decode.com](http://www.url-encode-decode.com/), copy the JSON part (shown in bold below) and paste it into the left hand field.
|
||||
|
||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=**{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}**
|
||||
|
||||
Click the **Encode url** button.
|
||||
|
||||
Copy the output from the right hand box and paste it on a new line in your text file.
|
||||
|
||||
```
|
||||
%7B%22jsonrpc%22%3A%222.0%22%2C%22method%22%3A%22Application.SetVolume%22%2C%22params%22%3A%7B%22volume%22%3A100%7D%2C%22id%22%3A1%7D
|
||||
```
|
||||
#### Join the URL and JSON
|
||||
|
||||
Finally you want to insert the URL part before the request (shown in bold below)
|
||||
|
||||
**http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=**%7B%22jsonrpc%22%3A%222.0%22%2C%22method%22%3A%22Application.SetVolume%22%2C%22params%22%3A%7B%22volume%22%3A100%7D%2C%22id%22%3A1%7D
|
||||
### HA Bridge
|
||||
|
||||
Paste the final URL in **On URL** field. Just do the one for now, add the device and in the Bridge Control tab click Save.
|
||||
|
||||
Test the button in the Bridge Devices tab and hopefully it should turn the volume up in Kodi.
|
||||
|
||||
Go ahead and repeat the steps for the **Off URL**. All the same steps but change 100% to 0%. If you want to use the previous URL you can, just find the 100% in the encoded URL.
|
||||
|
||||
`<EFBFBD>%22%3A%7B%22volume%22%3A`**100**`%7D%2C%22id%22%3A1%7D`
|
||||
|
||||
and change it to 0
|
||||
|
||||
`<EFBFBD>%22%3A%7B%22volume%22%3A`**0**`%7D%2C%22id%22%3A1%7D`
|
||||
#### Dim JSON
|
||||
|
||||
The Dim URL uses the `${intensity.percent}` to take the given number from your voice command and pass it to Kodi.
|
||||
|
||||
Here is the JSON to <20>Dim<69> the volume
|
||||
|
||||
``` json
|
||||
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":"${intensity.percent}""},"id":1}
|
||||
```
|
||||
|
||||
You don<6F>t need to encode the `${intensity.percent}` part. This means you can simply replace the number value (100/0) with `${intensity.percent}` as shown below.
|
||||
|
||||
`<EFBFBD>%22%3A%7B%22volume%22%3A`**${intensity.percent}**`%7D%2C%22id%22%3A1%7D`
|
||||
### Controlling the Device
|
||||
|
||||
You can use the commands as listed in the [README](https://github.com/bwssytems/ha-bridge#ask-alexa)
|
||||
|
||||
<EFBFBD>Set Cody Sound to 50 percent<6E>
|
||||
<EFBFBD>Cody Sound to 70 percent<6E>
|
||||
|
||||
Remembering that <20>Turn on Cody Sound<6E> will set the volume to 100%, and <20>Turn off Cody Sound<6E> will mute.
|
||||
33
pom.xml
33
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>2.0.5</version>
|
||||
<version>3.5.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
@@ -22,13 +22,17 @@
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>Eclipse Paho Repo</id>
|
||||
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>harmony-java-client</artifactId>
|
||||
<version>1.0.8</version>
|
||||
<version>1.1.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
@@ -43,7 +47,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 +93,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>
|
||||
@@ -116,6 +110,11 @@
|
||||
<artifactId>smack-core</artifactId>
|
||||
<version>4.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -193,6 +192,12 @@
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.eclipse.paho:org.eclipse.paho.client.mqttv3</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<transformers>
|
||||
<transformer
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,6 +31,11 @@ public class BridgeSettings extends BackupHandler {
|
||||
super();
|
||||
bridgeControl = new BridgeControlDescriptor();
|
||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||
}
|
||||
|
||||
}
|
||||
public BridgeControlDescriptor getBridgeControl() {
|
||||
return bridgeControl;
|
||||
@@ -35,12 +44,9 @@ 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;
|
||||
|
||||
String configFileProperty = System.getProperty("config.file");
|
||||
if(configFileProperty == null) {
|
||||
Path filePath = Paths.get(Configuration.CONFIG_FILE);
|
||||
@@ -96,8 +102,6 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
}
|
||||
theBridgeSettings.setHarmonyAddress(theHarmonyList);
|
||||
theBridgeSettings.setHarmonyUser(System.getProperty("harmony.user"));
|
||||
theBridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd"));
|
||||
theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||
theBridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DEFAULT_BUTTON_SLEEP)));
|
||||
@@ -106,34 +110,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 +134,23 @@ 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());
|
||||
theBridgeSettings.setMqttconfigured(theBridgeSettings.isValidMQTT());
|
||||
if(serverPortOverride != null)
|
||||
theBridgeSettings.setServerPort(serverPortOverride);
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
@@ -171,31 +167,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 +189,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 +209,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 +230,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 +244,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -9,8 +12,6 @@ public class BridgeSettingsDescriptor {
|
||||
private String upnpdevicedb;
|
||||
private IpList veraaddress;
|
||||
private IpList harmonyaddress;
|
||||
private String harmonyuser;
|
||||
private String harmonypwd;
|
||||
private Integer buttonsleep;
|
||||
private boolean upnpstrict;
|
||||
private boolean traceupnp;
|
||||
@@ -24,6 +25,15 @@ 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;
|
||||
private String myechourl;
|
||||
private String webaddress;
|
||||
private IpList mqttaddress;
|
||||
private boolean mqttconfigured;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
@@ -33,7 +43,13 @@ public class BridgeSettingsDescriptor {
|
||||
this.veraconfigured = false;
|
||||
this.harmonyconfigured = false;
|
||||
this.hueconfigured = false;
|
||||
this.halconfigured = false;
|
||||
this.mqttconfigured = false;
|
||||
this.farenheit = true;
|
||||
this.whitelist = null;
|
||||
this.settingsChanged = false;
|
||||
this.myechourl = "echo.amazon.com/#cards";
|
||||
this.webaddress = "0.0.0.0";
|
||||
}
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
@@ -77,18 +93,6 @@ public class BridgeSettingsDescriptor {
|
||||
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||
this.harmonyaddress = harmonyaddress;
|
||||
}
|
||||
public String getHarmonyUser() {
|
||||
return harmonyuser;
|
||||
}
|
||||
public void setHarmonyUser(String harmonyuser) {
|
||||
this.harmonyuser = harmonyuser;
|
||||
}
|
||||
public String getHarmonyPwd() {
|
||||
return harmonypwd;
|
||||
}
|
||||
public void setHarmonyPwd(String harmonypwd) {
|
||||
this.harmonypwd = harmonypwd;
|
||||
}
|
||||
public boolean isUpnpStrict() {
|
||||
return upnpstrict;
|
||||
}
|
||||
@@ -167,6 +171,60 @@ 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 String getMyechourl() {
|
||||
return myechourl;
|
||||
}
|
||||
public void setMyechourl(String myechourl) {
|
||||
this.myechourl = myechourl;
|
||||
}
|
||||
public String getWebaddress() {
|
||||
return webaddress;
|
||||
}
|
||||
public void setWebaddress(String webaddress) {
|
||||
this.webaddress = webaddress;
|
||||
}
|
||||
public IpList getMqttaddress() {
|
||||
return mqttaddress;
|
||||
}
|
||||
public void setMqttaddress(IpList mqttaddress) {
|
||||
this.mqttaddress = mqttaddress;
|
||||
}
|
||||
public boolean isMqttconfigured() {
|
||||
return mqttconfigured;
|
||||
}
|
||||
public void setMqttconfigured(boolean mqttconfigured) {
|
||||
this.mqttconfigured = mqttconfigured;
|
||||
}
|
||||
public Boolean isValidVera() {
|
||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
@@ -181,10 +239,6 @@ public class BridgeSettingsDescriptor {
|
||||
List<NamedIP> devicesList = this.getHarmonyAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
if(this.getHarmonyPwd() == null || this.getHarmonyPwd().equals(""))
|
||||
return false;
|
||||
if(this.getHarmonyUser() == null || this.getHarmonyUser().equals(""))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public Boolean isValidNest() {
|
||||
@@ -202,4 +256,22 @@ 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;
|
||||
}
|
||||
public Boolean isValidMQTT() {
|
||||
if(this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getMqttaddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -10,8 +10,11 @@ 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.mqtt.MQTTHome;
|
||||
import com.bwssystems.util.UDPDatagramSender;
|
||||
|
||||
public class HABridge {
|
||||
|
||||
@@ -36,7 +39,10 @@ public class HABridge {
|
||||
HarmonyHome harmonyHome;
|
||||
NestHome nestHome;
|
||||
HueHome hueHome;
|
||||
HalHome halHome;
|
||||
MQTTHome mqttHome;
|
||||
HueMulator theHueMulator;
|
||||
UDPDatagramSender udpSender;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
SystemControl theSystem;
|
||||
@@ -50,9 +56,9 @@ public class HABridge {
|
||||
bridgeSettings = new BridgeSettings();
|
||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
bridgeSettings.buildSettings();
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") initializing....");
|
||||
log.info("HA Bridge initializing....");
|
||||
// sparkjava config directive to set ip address for the web server to listen on
|
||||
// ipAddress("0.0.0.0"); // not used
|
||||
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
||||
// sparkjava config directive to set port for the web server to listen on
|
||||
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
@@ -66,30 +72,45 @@ 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 mqtt handlers if available
|
||||
mqttHome = new MQTTHome(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, mqttHome);
|
||||
// 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, mqttHome, 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;
|
||||
mqttHome.shutdownMQTTClients();
|
||||
mqttHome = null;
|
||||
udpSender.closeResponseSocket();
|
||||
}
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||
System.exit(0);
|
||||
|
||||
@@ -4,6 +4,9 @@ public class NamedIP {
|
||||
private String name;
|
||||
private String ip;
|
||||
private String port;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -22,4 +25,16 @@ public class NamedIP {
|
||||
public void setPort(String port) {
|
||||
this.port = port;
|
||||
}
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.bwssystems.HABridge.api;
|
||||
|
||||
public class CallItem {
|
||||
private String item;
|
||||
private Integer count;
|
||||
private Integer delay;
|
||||
|
||||
public String getItem() {
|
||||
return item;
|
||||
@@ -10,4 +12,20 @@ public class CallItem {
|
||||
public void setItem(String anitem) {
|
||||
item = anitem;
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Integer getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setDelay(Integer delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class DeviceTypes {
|
||||
private Boolean bridge;
|
||||
private String[] lights;
|
||||
public Boolean getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
public void setBridge(Boolean bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
public String[] getLights() {
|
||||
return lights;
|
||||
}
|
||||
public void setLights(String[] lights) {
|
||||
this.lights = lights;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ public class HueApiResponse {
|
||||
private Map<String, JsonObject> rules;
|
||||
private HueConfig config;
|
||||
|
||||
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
||||
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
|
||||
super();
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid));
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist));
|
||||
this.setRules(new HashMap<>());
|
||||
this.setSensors(new HashMap<>());
|
||||
this.setSchedules(new HashMap<>());
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@@ -29,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;
|
||||
}
|
||||
}
|
||||
|
||||
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueError {
|
||||
|
||||
private HueErrorDetails error;
|
||||
|
||||
public HueError(HueErrorDetails error) {
|
||||
super();
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public HueErrorDetails getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(HueErrorDetails error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueErrorDetails {
|
||||
private String type;
|
||||
private String address;
|
||||
private String description;
|
||||
private String method_name;
|
||||
private String resource_name;
|
||||
private String value;
|
||||
public HueErrorDetails(String type, String address, String description, String method_name, String resource_name,
|
||||
String value) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.description = description;
|
||||
this.method_name = method_name;
|
||||
this.resource_name = resource_name;
|
||||
this.value = value;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public String getMethod_name() {
|
||||
return method_name;
|
||||
}
|
||||
public void setMethod_name(String method_name) {
|
||||
this.method_name = method_name;
|
||||
}
|
||||
public String getResource_name() {
|
||||
return resource_name;
|
||||
}
|
||||
public void setResource_name(String resource_name) {
|
||||
this.resource_name = resource_name;
|
||||
}
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HueErrorResponse {
|
||||
private ArrayList<HueError> theErrors;
|
||||
|
||||
public HueErrorResponse() {
|
||||
super();
|
||||
theErrors = new ArrayList<HueError>();
|
||||
}
|
||||
|
||||
public void addError(HueError anError) {
|
||||
theErrors.add(anError);
|
||||
}
|
||||
|
||||
public HueError[] getTheErrors() {
|
||||
HueError theList[] = new HueError[theErrors.size()];
|
||||
theList = theErrors.toArray(theList);
|
||||
return theList;
|
||||
}
|
||||
|
||||
public void setTheErrors(ArrayList<HueError> theErrors) {
|
||||
this.theErrors = theErrors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
// import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
*/
|
||||
public class StateChangeBody {
|
||||
private boolean on;
|
||||
private int bri;
|
||||
private int hue;
|
||||
private int sat;
|
||||
private String effect;
|
||||
private int ct;
|
||||
private String alert;
|
||||
private List<Double> xy;
|
||||
private int transitiontime;
|
||||
private int bri_inc;
|
||||
private int hue_inc;
|
||||
private int sat_inc;
|
||||
private List<Double> xy_inc;
|
||||
private int ct_inc;
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(boolean on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public int getBri() {
|
||||
return bri;
|
||||
}
|
||||
|
||||
public void setBri(int bri) {
|
||||
this.bri = bri;
|
||||
}
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public int getSat() {
|
||||
return sat;
|
||||
}
|
||||
|
||||
public void setSat(int sat) {
|
||||
this.sat = sat;
|
||||
}
|
||||
|
||||
public String getEffect() {
|
||||
return effect;
|
||||
}
|
||||
|
||||
public void setEffect(String effect) {
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public int getCt() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
public void setCt(int ct) {
|
||||
this.ct = ct;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return alert;
|
||||
}
|
||||
|
||||
public void setAlert(String alert) {
|
||||
this.alert = alert;
|
||||
}
|
||||
|
||||
public List<Double> getXy() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXy(List<Double> xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
public int getTransitiontime() {
|
||||
return transitiontime;
|
||||
}
|
||||
|
||||
public void setTransitiontime(int transitiontime) {
|
||||
this.transitiontime = transitiontime;
|
||||
}
|
||||
|
||||
public int getBri_inc() {
|
||||
return bri_inc;
|
||||
}
|
||||
|
||||
public void setBri_inc(int bri_inc) {
|
||||
this.bri_inc = bri_inc;
|
||||
}
|
||||
|
||||
public int getHue_inc() {
|
||||
return hue_inc;
|
||||
}
|
||||
|
||||
public void setHue_inc(int hue_inc) {
|
||||
this.hue_inc = hue_inc;
|
||||
}
|
||||
|
||||
public int getSat_inc() {
|
||||
return sat_inc;
|
||||
}
|
||||
|
||||
public void setSat_inc(int sat_inc) {
|
||||
this.sat_inc = sat_inc;
|
||||
}
|
||||
|
||||
public List<Double> getXy_inc() {
|
||||
return xy_inc;
|
||||
}
|
||||
|
||||
public void setXy_inc(List<Double> xy_inc) {
|
||||
this.xy_inc = xy_inc;
|
||||
}
|
||||
|
||||
public int getCt_inc() {
|
||||
return ct_inc;
|
||||
}
|
||||
|
||||
public void setCt_inc(int ct_inc) {
|
||||
this.ct_inc = ct_inc;
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,36 @@ package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class Swupdate
|
||||
{
|
||||
private Integer updatestate;
|
||||
private Boolean checkforupdate;
|
||||
private DeviceTypes devicetypes;
|
||||
private String text;
|
||||
private Boolean notify;
|
||||
private Integer updatestate;
|
||||
private String url;
|
||||
|
||||
public static Swupdate createSwupdate() {
|
||||
Swupdate aSwupdate = new Swupdate();
|
||||
aSwupdate.setUpdatestate(0);
|
||||
aSwupdate.setCheckforupdate(false);
|
||||
aSwupdate.setDevicetypes(new DeviceTypes());
|
||||
aSwupdate.setNotify(false);
|
||||
aSwupdate.setText("");
|
||||
aSwupdate.setUpdatestate(0);
|
||||
aSwupdate.setUrl("");
|
||||
return aSwupdate;
|
||||
}
|
||||
|
||||
public Boolean getCheckforupdate() {
|
||||
return checkforupdate;
|
||||
}
|
||||
public void setCheckforupdate(Boolean checkforupdate) {
|
||||
this.checkforupdate = checkforupdate;
|
||||
}
|
||||
public DeviceTypes getDevicetypes() {
|
||||
return devicetypes;
|
||||
}
|
||||
public void setDevicetypes(DeviceTypes devicetypes) {
|
||||
this.devicetypes = devicetypes;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -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,12 @@ public class DeviceDescriptor{
|
||||
@SerializedName("contentBodyOff")
|
||||
@Expose
|
||||
private String contentBodyOff;
|
||||
@SerializedName("contentBodyDim")
|
||||
@Expose
|
||||
private String contentBodyDim;
|
||||
@SerializedName("requesterAddress")
|
||||
@Expose
|
||||
private String requesterAddress;
|
||||
|
||||
private DeviceState deviceState;
|
||||
|
||||
@@ -125,6 +134,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 +182,22 @@ public class DeviceDescriptor{
|
||||
this.contentBodyOff = contentBodyOff;
|
||||
}
|
||||
|
||||
public String getContentBodyDim() {
|
||||
return contentBodyDim;
|
||||
}
|
||||
|
||||
public void setContentBodyDim(String contentBodyDim) {
|
||||
this.contentBodyDim = contentBodyDim;
|
||||
}
|
||||
|
||||
public String getRequesterAddress() {
|
||||
return requesterAddress;
|
||||
}
|
||||
|
||||
public void setRequesterAddress(String requesterAddress) {
|
||||
this.requesterAddress = requesterAddress;
|
||||
}
|
||||
|
||||
public DeviceState getDeviceState() {
|
||||
if(deviceState == null)
|
||||
deviceState = DeviceState.createDeviceState();
|
||||
|
||||
@@ -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 nextId;
|
||||
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-");
|
||||
nextId = 0;
|
||||
_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()) > nextId) {
|
||||
nextId = Integer.decode(list[i].getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,12 +73,48 @@ public class DeviceRepository extends BackupHandler {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<DeviceDescriptor> findByDeviceType(String aType) {
|
||||
/*
|
||||
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
return list;
|
||||
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
|
||||
Iterator<DeviceDescriptor> anIterator = list.iterator();
|
||||
DeviceDescriptor theDevice;
|
||||
String theRequesterAddress;
|
||||
while(anIterator.hasNext()) {
|
||||
theDevice = anIterator.next();
|
||||
theRequesterAddress = theDevice.getRequesterAddress();
|
||||
if(theRequesterAddress == null || theRequesterAddress.length() == 0 || theRequesterAddress.contains(anAddress))
|
||||
theReturnList.add(theDevice);
|
||||
}
|
||||
return theReturnList;
|
||||
}
|
||||
*/
|
||||
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
|
||||
Iterator<DeviceDescriptor> anIterator = list.iterator();
|
||||
DeviceDescriptor theDevice;
|
||||
String theRequesterAddress;
|
||||
|
||||
HashMap<String,String > addressMap;
|
||||
while (anIterator.hasNext()) {
|
||||
theDevice = anIterator.next();
|
||||
theRequesterAddress = theDevice.getRequesterAddress();
|
||||
addressMap = new HashMap<String, String>();
|
||||
if(theRequesterAddress != null) {
|
||||
if (theRequesterAddress.contains(",")) {
|
||||
String[] theArray = theRequesterAddress.split(",");
|
||||
for (String v : theArray) {
|
||||
addressMap.put(v.trim(), v.trim());
|
||||
}
|
||||
} else
|
||||
addressMap.put(theRequesterAddress, theRequesterAddress);
|
||||
}
|
||||
if (theRequesterAddress == null || theRequesterAddress.length() == 0 || addressMap.containsKey(anAddress))
|
||||
theReturnList.add(theDevice);
|
||||
}
|
||||
return theReturnList;
|
||||
}
|
||||
|
||||
public DeviceDescriptor findOne(String id) {
|
||||
return devices.get(id);
|
||||
}
|
||||
@@ -84,8 +128,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 {
|
||||
nextId++;
|
||||
descriptors[i].setId(String.valueOf(nextId));
|
||||
}
|
||||
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 +147,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>();;
|
||||
nextId = 0;
|
||||
log.debug("Renumber devices.");
|
||||
while(deviceIterator.hasNext()) {
|
||||
nextId++;
|
||||
DeviceDescriptor theDevice = deviceIterator.next();
|
||||
theDevice.setId(String.valueOf(nextId));
|
||||
BigInteger bigInt = BigInteger.valueOf(nextId);
|
||||
byte[] theBytes = bigInt.toByteArray();
|
||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||
|
||||
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
||||
newdevices.put(theDevice.getId(), theDevice);
|
||||
}
|
||||
devices = newdevices;
|
||||
String jsonValue = gson.toJson(findAll());
|
||||
repositoryWriter(jsonValue, repositoryPath);
|
||||
}
|
||||
|
||||
public String delete(DeviceDescriptor aDescriptor) {
|
||||
if (aDescriptor != null) {
|
||||
devices.remove(aDescriptor.getId());
|
||||
|
||||
@@ -21,10 +21,12 @@ 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;
|
||||
import com.bwssystems.luupRequests.Scene;
|
||||
import com.bwssystems.mqtt.MQTTHome;
|
||||
import com.bwssystems.util.JsonTransformer;
|
||||
import com.bwssystems.vera.VeraHome;
|
||||
import com.google.gson.Gson;
|
||||
@@ -40,9 +42,11 @@ public class DeviceResource {
|
||||
private HarmonyHome myHarmonyHome;
|
||||
private NestHome nestHome;
|
||||
private HueHome hueHome;
|
||||
private HalHome halHome;
|
||||
private MQTTHome mqttHome;
|
||||
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, MQTTHome aMqttHome) {
|
||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
|
||||
if(theSettings.isValidVera())
|
||||
@@ -64,7 +68,18 @@ public class DeviceResource {
|
||||
this.hueHome = aHueHome;
|
||||
else
|
||||
this.hueHome = null;
|
||||
setupEndpoints();
|
||||
|
||||
if(theSettings.isValidHal())
|
||||
this.halHome = aHalHome;
|
||||
else
|
||||
this.halHome = null;
|
||||
|
||||
if(theSettings.isValidMQTT())
|
||||
this.mqttHome = aMqttHome;
|
||||
else
|
||||
this.mqttHome = null;
|
||||
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
public DeviceRepository getDeviceRepository() {
|
||||
@@ -262,6 +277,41 @@ public class DeviceResource {
|
||||
return hueHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/hal/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get hal items");
|
||||
if(halHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return new ErrorMessage("A Hal is not available.");
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return halHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/mqtt/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get MQTT brokers");
|
||||
if(mqttHome == null) {
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return new ErrorMessage("A MQTT config is not available.");
|
||||
}
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return mqttHome.getBrokers();
|
||||
}, 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
@@ -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,10 @@ 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;
|
||||
log.warn("UpnpListener encountered an error sending upnp response packet. IP: " + packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
|
||||
log.debug("UpnpListener send upnp exception: ", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -139,7 +144,6 @@ public class UpnpListener {
|
||||
}
|
||||
}
|
||||
upnpMulticastSocket.close();
|
||||
responseSocket.close();
|
||||
if (bridgeControl.isReinit())
|
||||
log.info("UPNP Discovery Listener - ended, restart found");
|
||||
if (bridgeControl.isStop())
|
||||
@@ -168,7 +172,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 +183,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 +195,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 "";
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class DeviceElements {
|
||||
@SerializedName(value="DeviceElements", alternate={"SceneElements", "GroupElements", "HVACElements", "MacroElements", "IrElements", "IrButtons"})
|
||||
private List<DeviceName> DeviceElements;
|
||||
|
||||
public List<DeviceName> getDeviceElements() {
|
||||
return DeviceElements;
|
||||
}
|
||||
|
||||
public void setDeviceElements(List<DeviceName> deviceElements) {
|
||||
DeviceElements = deviceElements;
|
||||
}
|
||||
}
|
||||
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class DeviceName {
|
||||
@SerializedName(value="DeviceName", alternate={"SceneName", "GroupName", "HVACName", "MacroName", "IrName", "IrButton"})
|
||||
private String DeviceName;
|
||||
|
||||
public String getDeviceName() {
|
||||
return DeviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
DeviceName = deviceName;
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
public class HalDevice {
|
||||
private String haldevicetype;
|
||||
private String haldevicename;
|
||||
private String haladdress;
|
||||
private String halname;
|
||||
private DeviceElements buttons;
|
||||
public String getHaldevicetype() {
|
||||
return haldevicetype;
|
||||
}
|
||||
public void setHaldevicetype(String haldevicetype) {
|
||||
this.haldevicetype = haldevicetype;
|
||||
}
|
||||
public String getHaldevicename() {
|
||||
return haldevicename;
|
||||
}
|
||||
public void setHaldevicename(String haldevicename) {
|
||||
this.haldevicename = haldevicename;
|
||||
}
|
||||
public String getHaladdress() {
|
||||
return haladdress;
|
||||
}
|
||||
public void setHaladdress(String haladdress) {
|
||||
this.haladdress = haladdress;
|
||||
}
|
||||
public String getHalname() {
|
||||
return halname;
|
||||
}
|
||||
public void setHalname(String halname) {
|
||||
this.halname = halname;
|
||||
}
|
||||
public DeviceElements getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
public void setButtons(DeviceElements buttons) {
|
||||
this.buttons = buttons;
|
||||
}
|
||||
}
|
||||
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class HalHome {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||
private Map<String, HalInfo> hals;
|
||||
|
||||
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
super();
|
||||
hals = new HashMap<String, HalInfo>();
|
||||
if(!bridgeSettings.isValidHal())
|
||||
return;
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aHal = theList.next();
|
||||
try {
|
||||
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get harmony client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<HalDevice> getDevices() {
|
||||
log.debug("consolidating devices for hues");
|
||||
List<HalDevice> theResponse = null;
|
||||
Iterator<String> keys = hals.keySet().iterator();
|
||||
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = hals.get(key).getLights();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else {
|
||||
log.warn("Cannot get lights for Hal with name: " + key + ", skipping this HAL.");
|
||||
continue;
|
||||
}
|
||||
theResponse = hals.get(key).getAppliances();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get appliances for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getTheatre();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get theatre for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getCustom();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get custom for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getHVAC();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get HVAC for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getHome(key);
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Homes for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getGroups();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Groups for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getMacros();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Macros for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getScenes();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Scenes for Hal with name: " + key);
|
||||
theResponse = hals.get(key).getButtons();
|
||||
if(theResponse != null)
|
||||
addHalDevices(deviceList, theResponse, key);
|
||||
else
|
||||
log.warn("Cannot get Buttons for Hal with name: " + key);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
||||
Iterator<HalDevice> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
HalDevice theDevice = devices.next();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype());
|
||||
aNewHalDevice.setHaldevicename(theDevice.getHaldevicename());
|
||||
aNewHalDevice.setButtons(theDevice.getButtons());
|
||||
aNewHalDevice.setHaladdress(hals.get(theKey).getHalAddress().getIp());
|
||||
aNewHalDevice.setHalname(theKey);
|
||||
theDeviceList.add(aNewHalDevice);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
@@ -0,0 +1,206 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.util.TextStringFormatter;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HalInfo {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalInfo.class);
|
||||
private static final String DEVICE_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType=";
|
||||
private static final String HVAC_REQUEST = "/HVACData!HVACCmd=GetNames";
|
||||
private static final String GROUP_REQUEST = "/GroupData!GroupCmd=GetNames";
|
||||
private static final String MACRO_REQUEST = "/MacroData!MacroCmd=GetNames";
|
||||
private static final String SCENE_REQUEST = "/SceneData!SceneCmd=GetNames";
|
||||
private static final String IRDATA_REQUEST = "/IrData!IRCmd=GetNames";
|
||||
private static final String IRBUTTON_REQUEST = "/IrData!IRCmd=GetButtons!IrDevice=";
|
||||
private static final String TOKEN_REQUEST = "?Token=";
|
||||
private static final String LIGHT_REQUEST = "Light";
|
||||
private static final String APPL_REQUEST = "Appl";
|
||||
// private static final String VIDEO_REQUEST = "Video";
|
||||
private static final String THEATRE_REQUEST = "Theatre";
|
||||
private static final String CUSTOM_REQUEST = "Custom";
|
||||
private static final String HVAC_TYPE = "HVAC";
|
||||
private static final String HOME_TYPE = "Home";
|
||||
private static final String GROUP_TYPE = "Group";
|
||||
private static final String MACRO_TYPE = "Macro";
|
||||
private static final String SCENE_TYPE = "Scene";
|
||||
private static final String IRDATA_TYPE = "IrData";
|
||||
private HttpClient httpClient;
|
||||
private NamedIP halAddress;
|
||||
private String theToken;
|
||||
|
||||
public HalInfo(NamedIP addressName, String aGivenToken) {
|
||||
super();
|
||||
httpClient = HttpClients.createDefault();
|
||||
halAddress = addressName;
|
||||
theToken = aGivenToken;
|
||||
}
|
||||
|
||||
public List<HalDevice> getLights() {
|
||||
return getHalDevices(DEVICE_REQUEST + LIGHT_REQUEST + TOKEN_REQUEST, LIGHT_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getAppliances() {
|
||||
return getHalDevices(DEVICE_REQUEST + APPL_REQUEST + TOKEN_REQUEST, APPL_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getTheatre() {
|
||||
return getHalDevices(DEVICE_REQUEST + THEATRE_REQUEST + TOKEN_REQUEST, THEATRE_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getCustom() {
|
||||
return getHalDevices(DEVICE_REQUEST + CUSTOM_REQUEST + TOKEN_REQUEST, CUSTOM_REQUEST);
|
||||
}
|
||||
|
||||
public List<HalDevice> getHVAC() {
|
||||
return getHalDevices(HVAC_REQUEST + TOKEN_REQUEST, HVAC_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getGroups() {
|
||||
return getHalDevices(GROUP_REQUEST + TOKEN_REQUEST, GROUP_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getMacros() {
|
||||
return getHalDevices(MACRO_REQUEST + TOKEN_REQUEST, MACRO_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getScenes() {
|
||||
return getHalDevices(SCENE_REQUEST + TOKEN_REQUEST, SCENE_TYPE);
|
||||
}
|
||||
|
||||
public List<HalDevice> getButtons() {
|
||||
List<HalDevice> irDataDevices = getHalDevices(IRDATA_REQUEST + TOKEN_REQUEST, IRDATA_TYPE);
|
||||
|
||||
return getDeviceButtons(irDataDevices);
|
||||
}
|
||||
|
||||
public List<HalDevice> getHome(String theDeviceName) {
|
||||
List<HalDevice> deviceList = null;
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(HOME_TYPE);
|
||||
aNewHalDevice.setHaldevicename(theDeviceName);
|
||||
deviceList.add(aNewHalDevice);
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private List<HalDevice> getHalDevices(String apiType, String deviceType) {
|
||||
DeviceElements theHalApiResponse = null;
|
||||
List<HalDevice> deviceList = null;
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
||||
theData = doHttpGETRequest(theUrl);
|
||||
if(theData != null) {
|
||||
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||
if(theHalApiResponse.getDeviceElements() == null) {
|
||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||
if(theStatus.getStatus() == null) {
|
||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
||||
}
|
||||
else {
|
||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: " + theStatus.getDescription());
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
|
||||
Iterator<DeviceName> theDeviceNames = theHalApiResponse.getDeviceElements().iterator();
|
||||
while(theDeviceNames.hasNext()) {
|
||||
DeviceName theDevice = theDeviceNames.next();
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(deviceType);
|
||||
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||
deviceList.add(aNewHalDevice);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Get Hal device types " + deviceType + " for " + halAddress.getName() + " - returned null, no data.");
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private List<HalDevice> getDeviceButtons(List<HalDevice> theIrDevices) {
|
||||
DeviceElements theHalApiResponse = null;
|
||||
List<HalDevice> deviceList = null;
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
if(theIrDevices == null)
|
||||
return null;
|
||||
Iterator<HalDevice> theHalDevices = theIrDevices.iterator();
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
while (theHalDevices.hasNext()) {
|
||||
HalDevice theHalDevice = theHalDevices.next();
|
||||
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||
theData = doHttpGETRequest(theUrl);
|
||||
if (theData != null) {
|
||||
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||
if (theHalApiResponse.getDeviceElements() == null) {
|
||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||
if (theStatus.getStatus() == null) {
|
||||
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||
+ halAddress.getName() + " as response is not parsable.");
|
||||
} else {
|
||||
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||
+ halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: "
|
||||
+ theStatus.getDescription());
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
theHalDevice.setButtons(theHalApiResponse);
|
||||
deviceList.add(theHalDevice);
|
||||
|
||||
} else {
|
||||
log.warn("Get Hal buttons for IR Device " + theHalDevice.getHaldevicename() + " for "
|
||||
+ halAddress.getName() + " - returned null, no data.");
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
// This function executes the url against the hal
|
||||
protected String doHttpGETRequest(String url) {
|
||||
String theContent = null;
|
||||
log.debug("calling GET on URL: " + url);
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||
if(response.getStatusLine().getStatusCode() == 200){
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||
}
|
||||
return theContent;
|
||||
}
|
||||
|
||||
public NamedIP getHalAddress() {
|
||||
return halAddress;
|
||||
}
|
||||
|
||||
public void setHalAddress(NamedIP halAddress) {
|
||||
this.halAddress = halAddress;
|
||||
}
|
||||
|
||||
}
|
||||
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.hal;
|
||||
|
||||
public class StatusDescription {
|
||||
private String Status;
|
||||
private String Description;
|
||||
public String getStatus() {
|
||||
return Status;
|
||||
}
|
||||
public void setStatus(String status) {
|
||||
Status = status;
|
||||
}
|
||||
public String getDescription() {
|
||||
return Description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.bwssystems.harmony;
|
||||
public class ButtonPress {
|
||||
private String device;
|
||||
private String button;
|
||||
private Integer delay;
|
||||
private Integer count;
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
@@ -15,6 +17,18 @@ public class ButtonPress {
|
||||
public void setButton(String button) {
|
||||
this.button = button;
|
||||
}
|
||||
public Integer getDelay() {
|
||||
return delay;
|
||||
}
|
||||
public void setDelay(Integer delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
public Boolean isValid() {
|
||||
if (device != null && !device.isEmpty()){
|
||||
if (button != null && !button.isEmpty())
|
||||
|
||||
@@ -75,7 +75,7 @@ public class HarmonyServer {
|
||||
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||
}
|
||||
});
|
||||
harmonyClient.connect(myNameAndIP.getIp(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||
harmonyClient.connect(myNameAndIP.getIp());
|
||||
}
|
||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||
}
|
||||
|
||||
30
src/main/java/com/bwssystems/mqtt/MQTTBroker.java
Normal file
30
src/main/java/com/bwssystems/mqtt/MQTTBroker.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.bwssystems.mqtt;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class MQTTBroker {
|
||||
private String clientId;
|
||||
private String ip;
|
||||
|
||||
public MQTTBroker(NamedIP brokerConfig) {
|
||||
super();
|
||||
this.setIp(brokerConfig.getIp());
|
||||
this.setClientId(brokerConfig.getName());
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
71
src/main/java/com/bwssystems/mqtt/MQTTHandler.java
Normal file
71
src/main/java/com/bwssystems/mqtt/MQTTHandler.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package com.bwssystems.mqtt;
|
||||
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class MQTTHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(MQTTHandler.class);
|
||||
private NamedIP myConfig;
|
||||
private MqttClient myClient;
|
||||
private int qos = 1;
|
||||
|
||||
public MQTTHandler(NamedIP aConfig) {
|
||||
super();
|
||||
log.info("Setting up handler for name: " + aConfig.getName());
|
||||
MemoryPersistence persistence = new MemoryPersistence();
|
||||
myConfig = aConfig;
|
||||
try {
|
||||
myClient = new MqttClient("tcp://" + myConfig.getIp(), myConfig.getName(), persistence);
|
||||
} catch (MqttException e) {
|
||||
log.error("Could not create MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage());
|
||||
}
|
||||
MqttConnectOptions connOpts = new MqttConnectOptions();
|
||||
connOpts.setCleanSession(true);
|
||||
if(aConfig.getUsername() != null && aConfig.getUsername().trim().length() > 0) {
|
||||
if(aConfig.getPassword() != null && aConfig.getPassword().trim().length() > 0) {
|
||||
connOpts.setUserName(aConfig.getUsername().trim());
|
||||
connOpts.setPassword(aConfig.getPassword().trim().toCharArray());
|
||||
}
|
||||
}
|
||||
try {
|
||||
myClient.connect(connOpts);
|
||||
} catch (MqttSecurityException e) {
|
||||
log.error("Could not connect MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage());
|
||||
} catch (MqttException e) {
|
||||
log.error("Could not connect MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void publishMessage(String topic, String content) {
|
||||
MqttMessage message = new MqttMessage(content.getBytes());
|
||||
message.setQos(qos);
|
||||
try {
|
||||
myClient.publish(topic, message);
|
||||
} catch (MqttPersistenceException e) {
|
||||
log.error("Could not publish to MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage());
|
||||
} catch (MqttException e) {
|
||||
log.error("Could not publish to MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public NamedIP getMyConfig() {
|
||||
return myConfig;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
try {
|
||||
myClient.disconnect();
|
||||
} catch (MqttException e) {
|
||||
log.warn("Could not disconnect MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/main/java/com/bwssystems/mqtt/MQTTHome.java
Normal file
77
src/main/java/com/bwssystems/mqtt/MQTTHome.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package com.bwssystems.mqtt;
|
||||
|
||||
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 MQTTHome {
|
||||
private static final Logger log = LoggerFactory.getLogger(MQTTHome.class);
|
||||
private Map<String, MQTTHandler> handlers;
|
||||
private Boolean validMqtt;
|
||||
|
||||
public MQTTHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
super();
|
||||
validMqtt = bridgeSettings.isValidMQTT();
|
||||
if(!validMqtt)
|
||||
return;
|
||||
|
||||
handlers = new HashMap<String, MQTTHandler>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getMqttaddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aClientConfig = theList.next();
|
||||
MQTTHandler aHandler = new MQTTHandler(aClientConfig);
|
||||
if(aHandler != null)
|
||||
handlers.put(aClientConfig.getName(), aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownMQTTClients() {
|
||||
if(!validMqtt)
|
||||
return;
|
||||
log.debug("Shutting down MQTT handlers.");
|
||||
if(handlers != null && !handlers.isEmpty()) {
|
||||
Iterator<String> keys = handlers.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
handlers.get(key).shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MQTTHandler getMQTTHandler(String aName) {
|
||||
if(!validMqtt)
|
||||
return null;
|
||||
MQTTHandler aHandler;
|
||||
if(aName == null || aName.equals("")) {
|
||||
aHandler = null;
|
||||
log.debug("Cannot get MQTT handler for name as it is empty.");
|
||||
}
|
||||
else {
|
||||
aHandler = handlers.get(aName);
|
||||
log.debug("Retrieved a MQTT hanlder for name: " + aName);
|
||||
}
|
||||
return aHandler;
|
||||
}
|
||||
|
||||
public List<MQTTBroker> getBrokers() {
|
||||
if(!validMqtt)
|
||||
return null;
|
||||
Iterator<String> keys = handlers.keySet().iterator();
|
||||
ArrayList<MQTTBroker> deviceList = new ArrayList<MQTTBroker>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
MQTTHandler aHandler = handlers.get(key);
|
||||
MQTTBroker aDevice = new MQTTBroker(aHandler.getMyConfig());
|
||||
deviceList.add(aDevice);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
39
src/main/java/com/bwssystems/mqtt/MQTTMessage.java
Normal file
39
src/main/java/com/bwssystems/mqtt/MQTTMessage.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.bwssystems.mqtt;
|
||||
|
||||
public class MQTTMessage {
|
||||
private String clientId;
|
||||
private String topic;
|
||||
private String message;
|
||||
private Integer delay;
|
||||
private Integer count;
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
public String getTopic() {
|
||||
return topic;
|
||||
}
|
||||
public void setTopic(String topic) {
|
||||
this.topic = topic;
|
||||
}
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
public Integer getDelay() {
|
||||
return delay;
|
||||
}
|
||||
public void setDelay(Integer delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@@ -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>.
|
||||
*
|
||||
|
||||
72
src/main/java/com/bwssystems/util/UDPDatagramSender.java
Normal file
72
src/main/java/com/bwssystems/util/UDPDatagramSender.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
|
||||
<li><a href="http://{{bridge.settings.myechourl}}" target="_blank">My Echo</a></li>
|
||||
<li><a href="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Help</a></li>
|
||||
<li class="dropdown">
|
||||
<a id="dLabel" href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">About <span class="caret"></span></a>
|
||||
|
||||
@@ -34,6 +34,12 @@ app.config(function ($routeProvider) {
|
||||
}).when('/huedevices', {
|
||||
templateUrl: 'views/huedevice.html',
|
||||
controller: 'HueController'
|
||||
}).when('/haldevices', {
|
||||
templateUrl: 'views/haldevice.html',
|
||||
controller: 'HalController'
|
||||
}).when('/mqttmessages', {
|
||||
templateUrl: 'views/mqttpublish.html',
|
||||
controller: 'MQTTController'
|
||||
}).otherwise({
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
@@ -45,9 +51,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: [], mapandid: [], 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, showMqtt: false, habridgeversion: ""};
|
||||
|
||||
this.displayWarn = function(errorTitle, error) {
|
||||
var toastContent = errorTitle;
|
||||
@@ -100,12 +118,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,7 +146,9 @@ 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.device.requesterAddress = null;
|
||||
self.state.olddevicename = "";
|
||||
};
|
||||
|
||||
@@ -155,6 +187,16 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateShowHal = function () {
|
||||
this.state.showHal = self.state.settings.halconfigured;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateShowMqtt = function () {
|
||||
this.state.showMqtt = self.state.settings.mqttconfigured;
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadBridgeSettings = function () {
|
||||
return $http.get(this.state.systemsbase + "/settings").then(
|
||||
function (response) {
|
||||
@@ -163,6 +205,8 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
self.updateShowHarmony();
|
||||
self.updateShowNest();
|
||||
self.updateShowHue();
|
||||
self.updateShowHal();
|
||||
self.updateShowMqtt();
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Load Bridge Settings Error: ", error);
|
||||
@@ -292,6 +336,32 @@ 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.viewMQTTDevices = function () {
|
||||
if(!this.state.showMqtt)
|
||||
return;
|
||||
return $http.get(this.state.base + "/mqtt/devices").then(
|
||||
function (response) {
|
||||
self.state.mqttbrokers = response.data;
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Get MQTT Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.updateLogLevels = function(logComponents) {
|
||||
return $http.put(this.state.systemsbase + "/logmgmt/update", logComponents ).then(
|
||||
function (response) {
|
||||
@@ -565,7 +635,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) {
|
||||
@@ -616,12 +686,44 @@ 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.addMQTTtoSettings = function (newmqttname, newmqttip, newmqttusername, newmqttpassword) {
|
||||
if($scope.bridge.settings.mqttaddress == null) {
|
||||
$scope.bridge.settings.mqttaddress = { devices: [] };
|
||||
}
|
||||
var newmqtt = {name: newmqttname, ip: newmqttip, username: newmqttusername, password: newmqttpassword }
|
||||
$scope.bridge.settings.mqttaddress.devices.push(newmqtt);
|
||||
$scope.newmqttname = null;
|
||||
$scope.newmqttip = null;
|
||||
$scope.newmqttusername = null;
|
||||
$scope.newmqttpassword = null;
|
||||
};
|
||||
$scope.removeMQTTtoSettings = function (mqttname, mqttip) {
|
||||
for(var i = $scope.bridge.settings.mqttaddress.devices.length - 1; i >= 0; i--) {
|
||||
if($scope.bridge.settings.mqttaddress.devices[i].name === mqttname && $scope.bridge.settings.mqttaddress.devices[i].ip === mqttip) {
|
||||
$scope.bridge.settings.mqttaddress.devices.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
$scope.bridgeReinit = function () {
|
||||
$scope.isInControl = false;
|
||||
bridgeService.reinit();
|
||||
};
|
||||
$scope.bridgeStop = function () {
|
||||
$scope.isInControl = false;
|
||||
bridgeService.stop();
|
||||
};
|
||||
$scope.saveSettings = function() {
|
||||
@@ -708,11 +810,7 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
(type == "off" && (bridgeService.aContainsB(device.offUrl, "${intensity.byte}") ||
|
||||
bridgeService.aContainsB(device.offUrl, "${intensity.percent}") ||
|
||||
bridgeService.aContainsB(device.offUrl, "${intensity.math("))) ||
|
||||
(type == "dim" && (bridgeService.aContainsB(device.dimUrl, "${intensity.byte}") ||
|
||||
bridgeService.aContainsB(device.dimUrl, "${intensity.percent}") ||
|
||||
bridgeService.aContainsB(device.dimUrl, "${intensity.math(") ||
|
||||
bridgeService.aContainsB(device.deviceType, "passthru") ||
|
||||
bridgeService.aContainsB(device.mapType, "hueDevice"))))) {
|
||||
(type == "dim"))) {
|
||||
$scope.bridge.device = device;
|
||||
$scope.bridge.type = type;
|
||||
ngDialog.open({
|
||||
@@ -736,6 +834,9 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.editDevice(device);
|
||||
$location.path('/editdevice');
|
||||
};
|
||||
$scope.renumberDevices = function() {
|
||||
bridgeService.renumberDevices();
|
||||
};
|
||||
$scope.backupDeviceDb = function (optionalbackupname) {
|
||||
bridgeService.backupDeviceDb(optionalbackupname);
|
||||
};
|
||||
@@ -814,12 +915,20 @@ app.controller('DeleteMapandIdDialogCtrl', function ($scope, bridgeService, ngDi
|
||||
ngDialog.close('ngdialog1');
|
||||
bridgeService.deleteDeviceByMapId(mapandid.id, mapandid.mapType);
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
bridgeService.viewHarmonyActivities();
|
||||
bridgeService.viewHarmonyDevices();
|
||||
bridgeService.viewNestItems();
|
||||
bridgeService.viewHueDevices();
|
||||
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;
|
||||
};
|
||||
});
|
||||
@@ -829,6 +938,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
$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: ""};
|
||||
@@ -913,22 +1023,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) {
|
||||
@@ -937,11 +1056,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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -988,21 +1124,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 + "\"}]";
|
||||
}
|
||||
@@ -1169,6 +1306,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
$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;
|
||||
@@ -1219,21 +1357,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) {
|
||||
@@ -1242,14 +1390,414 @@ 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$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'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
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'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
app.controller('MQTTController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = $scope.bridge.device;
|
||||
bridgeService.viewMQTTDevices();
|
||||
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||
$scope.buttonsVisible = false;
|
||||
|
||||
$scope.clearDevice = function () {
|
||||
bridgeService.clearDevice();
|
||||
};
|
||||
|
||||
$scope.buildMQTTPublish = function (mqttbroker, mqtttopic, mqttmessage) {
|
||||
var currentOn = $scope.device.onUrl;
|
||||
var currentOff = $scope.device.offUrl;
|
||||
if( $scope.device.mapType == "mqttMessage") {
|
||||
$scope.device.mapId = $scope.device.mapId + "-" + mqtttopic;
|
||||
$scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\"}]";
|
||||
$scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\"}]";
|
||||
}
|
||||
else if ($scope.device.mapType == null || $scope.device.mapType == "") {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "mqtt";
|
||||
$scope.device.targetDevice = mqttbroker.clientId;
|
||||
$scope.device.name = mqttbroker.clientId + mqtttopic;
|
||||
$scope.device.mapType = "mqttMessage";
|
||||
$scope.device.mapId = mqttbroker.clientId + "-" + mqtttopic;
|
||||
$scope.device.onUrl = "[{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\"}]";
|
||||
$scope.device.offUrl = "[{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\"}]";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addDevice = function () {
|
||||
if($scope.device.name == "" && $scope.device.onUrl == "")
|
||||
return;
|
||||
bridgeService.addDevice($scope.device).then(
|
||||
function () {
|
||||
$scope.clearDevice();
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewMQTTDevices();
|
||||
},
|
||||
function (error) {
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
$scope.toggleButtons = function () {
|
||||
$scope.buttonsVisible = !$scope.buttonsVisible;
|
||||
if($scope.buttonsVisible)
|
||||
@@ -1500,6 +2048,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 = [];
|
||||
@@ -1514,6 +2091,20 @@ app.filter('configuredButtons', function() {
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('configuredMqttMsgs', function() {
|
||||
return function(input) {
|
||||
var out = [];
|
||||
if(input == null)
|
||||
return out;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if(input[i].mapType == "mqttMessage"){
|
||||
out.push(input[i]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('VersionController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
@@ -1,40 +1,58 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</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 sortable-header col="requesterAddress">Requester Address</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>{{device.requesterAddress}}</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 +63,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,7 +127,7 @@
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/ng-template" id="deleteDialog">
|
||||
<script type="text/ng-template" id="deleteDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device to Delete?</h2>
|
||||
<p>{{device.name}}</p>
|
||||
@@ -113,4 +137,3 @@
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
@@ -1,210 +1,265 @@
|
||||
<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 ng-if="bridge.showHal" role="presentation"><a
|
||||
href="#/haldevices">HAL Devices</a></li>
|
||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
<li role="presentation" class="active"><a href="#/editdevice">Edit
|
||||
Device</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<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 class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-requester-addr">Requester Address (comma separated list) </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="evice-requester-addr"
|
||||
ng-model="device.requesterAddress" placeholder="Only use if you want to restrict this device to a specific caller(s)">
|
||||
</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-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">
|
||||
<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-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-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-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-dim-url">Dim
|
||||
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: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-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-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-off-url">Off
|
||||
URL </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-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></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-headers">HTTP
|
||||
Headers </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">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers"
|
||||
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
<div 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 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">
|
||||
<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-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-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-type">Content Type </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">
|
||||
<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>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body On</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-content-body"
|
||||
ng-model="device.contentBody"
|
||||
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
|
||||
</div>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body-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>
|
||||
@@ -1,230 +1,274 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation" class="active"><a href="#/editor">Manual
|
||||
Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer" ng-if="bridge.showVera">
|
||||
<div ng-if="bridge.showVera" class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p class="text-muted">You can generate on/off URLs by filling in
|
||||
the Vera server URL, port, and device ID; or you can fill them out
|
||||
manually in the lower section.</p>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">You can generate on/off URLs by filling in
|
||||
the Vera server URL, port, and device ID; or you can fill them out
|
||||
manually in the lower section.</p>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
||||
Server URL </label>
|
||||
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
||||
Server URL </label>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="vera-base"
|
||||
ng-model="vera.base"
|
||||
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
||||
Request Port </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="vera-base"
|
||||
ng-model="vera.base"
|
||||
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
||||
Request Port </label>
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-port"
|
||||
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
||||
</div>
|
||||
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-port"
|
||||
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
||||
</div>
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
||||
ID </label>
|
||||
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
||||
ID </label>
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-id"
|
||||
ng-model="vera.id" placeholder="ID">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label"
|
||||
for="device-dim-control">Device Dim Control</label>
|
||||
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<input type="text" class="form-control" id="vera-id"
|
||||
ng-model="vera.id" placeholder="ID">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-2 col-sm-2 control-label" for="device-dim-control">Device Dim Control</label>
|
||||
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
||||
<option value="">none</option>
|
||||
<option value="${intensity..byte}">Pass-thru Value</option>
|
||||
<option value="${intensity.percent}">Percentage</option>
|
||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" ng-click="buildUrlsUsingDevice(device_dim_control)"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device
|
||||
URLs</button>
|
||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Scene
|
||||
URLs</button>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="col-xs-10 col-sm-2">
|
||||
<select name="device-dim-control" id="device-dim-control"
|
||||
ng-model="device_dim_control">
|
||||
<option value="">none</option>
|
||||
<option value="${intensity..byte}">Pass-thru Value</option>
|
||||
<option value="${intensity.percent}">Percentage</option>
|
||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit"
|
||||
ng-click="buildUrlsUsingDevice(device_dim_control)"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
|
||||
Device URLs</button>
|
||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
|
||||
Scene URLs</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add a new device</h2>
|
||||
</div>
|
||||
<p class="text-muted">This area allows you to create any http or udp call to an endpoint. You can use the default GET or select
|
||||
the http verb type below and configure a payload for either on, dim or off methods. Currently, https is not supported. For Execution of
|
||||
a script or program, plese fill in the path. All manually entered calls can use Json notation of array with
|
||||
[{"item":"the payload"},{"item":"another payload"}] to execute multiple entries. Adding the value replacements (${intensity..byte},${intensity.percent},${intensity.math(X*1)})
|
||||
will also work.</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">This area allows you to create any http or
|
||||
udp call to an endpoint. You can use the default GET or select the
|
||||
http verb type below and configure a payload for either on, dim or
|
||||
off methods. Currently, https is not supported. For Execution of a
|
||||
script or program, plese fill in the path. All manually entered calls
|
||||
can use Json notation of array with [{"item":"the
|
||||
payload"},{"item":"another payload"}] to
|
||||
execute multiple entries. Adding the value replacements
|
||||
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
|
||||
also work.</p>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||
Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||
</label>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device
|
||||
Type </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-type" id="device-type"
|
||||
ng-model="device.deviceType">
|
||||
<option value="">---Types if needed---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="custom">Custom</option>
|
||||
<option value="UDP">UDP</option>
|
||||
<option value="TCP">TCP</option>
|
||||
<option value="exec">Execute Script/Program</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-requester-addr">Requester Address (comma separated list) </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="evice-requester-addr"
|
||||
ng-model="device.requesterAddress" placeholder="Only use if you want to restrict this device to a specific caller(s)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-off-url">Off URL </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-off-url">Off
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-headers">HTTP Headers </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-headers">HTTP
|
||||
Headers </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-headers"
|
||||
ng-model="device.headers"
|
||||
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-http-verb">Http Verb </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb">
|
||||
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||
<option value="GET">GET</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="POST">POST</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-http-verb" id="device-http-verb"
|
||||
ng-model="device.httpVerb">
|
||||
<option value="">---Please select---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="GET">GET</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="POST">POST</option>
|
||||
</select>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-type">Content Type </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-content-type" id="device-content-type" ng-model="device.contentType">
|
||||
<option value="">---Please select---</option> <!-- not selected / blank option -->
|
||||
<option value="application/atom+xml">application/atom+xml</option>
|
||||
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||
<option value="application/json">application/json</option>
|
||||
<option value="application/octet-stream">application/octet-stream</option>
|
||||
<option value="application/svg+xml">application/svg+xml</option>
|
||||
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||
<option value="application/xml">application/xml</option>
|
||||
<option value="*">*</option>
|
||||
<option value="multipart/form-data">multipart/form-data</option>
|
||||
<option value="text/html">text/html</option>
|
||||
<option value="text/plain">text/plain</option>
|
||||
<option value="text/xml">text/xml</option>
|
||||
<option value="*/*">*/*</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<select name="device-content-type" id="device-content-type"
|
||||
ng-model="device.contentType">
|
||||
<option value="">---Please select---</option>
|
||||
<!-- not selected / blank option -->
|
||||
<option value="application/atom+xml">application/atom+xml</option>
|
||||
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||
<option value="application/json">application/json</option>
|
||||
<option value="application/octet-stream">application/octet-stream</option>
|
||||
<option value="application/svg+xml">application/svg+xml</option>
|
||||
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||
<option value="application/xml">application/xml</option>
|
||||
<option value="*">*</option>
|
||||
<option value="multipart/form-data">multipart/form-data</option>
|
||||
<option value="text/html">text/html</option>
|
||||
<option value="text/plain">text/plain</option>
|
||||
<option value="text/xml">text/xml</option>
|
||||
<option value="*/*">*/*</option>
|
||||
</select>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body On</label>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body">Content Body On</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-content-body"
|
||||
ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
|
||||
</div>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-content-body"
|
||||
ng-model="device.contentBody"
|
||||
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body-off">Content Body Off</label>
|
||||
<div class="clearfix visible-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.httpVerb" class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-content-body-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>
|
||||
218
src/main/resources/public/views/haldevice.html
Normal file
218
src/main/resources/public/views/haldevice.html
Normal file
@@ -0,0 +1,218 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">HAL Device List
|
||||
({{bridge.haldevices.length}})</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any HAL Device, use the action buttons
|
||||
to generate the device addition information below automatically. Then
|
||||
you can modify the name to anything you want that will be the keyword
|
||||
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||
setup. The 'Already Configured HAL Devices' list below will show what
|
||||
is already setup for your HAL.</p>
|
||||
<p>
|
||||
Also, use this select menu for which type of dim control you would
|
||||
like to be generated: <select name="device-dim-control"
|
||||
id="device-dim-control" ng-model="device_dim_control">
|
||||
<option value="">none</option>
|
||||
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||
<option value="${intensity.percent}">Percentage</option>
|
||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>Use the check boxes by the names to use the bulk addition
|
||||
feature. Select your items and dim control type if wanted, then click
|
||||
bulk add below. Your items will be added with on and off or dim and
|
||||
off if selected with the name of the device from the HAL.</p>
|
||||
</div>
|
||||
<scrollable-table watch="bridge.haldevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">
|
||||
<span><input type="checkbox" name="selectAll"
|
||||
value="{{selectAll}}"
|
||||
ng-checked="selectAll"
|
||||
ng-click="toggleSelectAll()"> Name</span></th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="halname">HAL</th>
|
||||
<th>On Button</th>
|
||||
<th>Off Button</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="haldevice in bridge.haldevices | availableHalDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td><input type="checkbox" name="bulk.devices[]"
|
||||
value="{{haldevice.haldevicename}}"
|
||||
ng-checked="bulk.devices.indexOf(haldevice.haldevicename) > -1"
|
||||
ng-click="toggleSelection(haldevice.haldevicename)">
|
||||
{{haldevice.haldevicename}}</td>
|
||||
<td>{{haldevice.haldevicetype}}</td>
|
||||
<td>{{haldevice.halname}}</td>
|
||||
<td>
|
||||
<select name="button-on" id="button-on" ng-model="button_on">
|
||||
<option ng-repeat="aButtonOn in haldevice.buttons.DeviceElements"
|
||||
value="{{aButtonOn}}">{{aButtonOn.DeviceName}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="button-off" id="button-off" ng-model="button_off">
|
||||
<option ng-repeat="aButtonOff in haldevice.buttons.DeviceElements"
|
||||
value="{{aButtonOff}}">{{aButtonOff.DeviceName}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button ng-if="haldevice.haldevicetype != 'Home' && haldevice.haldevicetype != 'HVAC' && haldevice.haldevicetype != 'IrData'" class="btn btn-success" type="submit"
|
||||
ng-click="buildDeviceUrls(haldevice, device_dim_control)">Generate
|
||||
Bridge Device</button>
|
||||
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
|
||||
ng-click="buildHALHomeUrls(haldevice)">Home/Away</button>
|
||||
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
|
||||
ng-click="buildButtonUrls(haldevice, button_on, button_off)">Build
|
||||
A Button</button>
|
||||
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALHeatUrls(haldevice)">Heat</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALCoolUrls(haldevice)">Cool</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALAutoUrls(haldevice)">Auto</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALOffUrls(haldevice)">Off</button>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildHALFanUrls(haldevice)">Fan</button>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
|
||||
({{bulk.devices.length}})</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured HAL Devices <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.haldevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">Name</th>
|
||||
<th sortable-header col="category">Category</th>
|
||||
<th sortable-header col="halname">HAL</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="device in bridge.devices | unavailableHalDeviceId">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</td>
|
||||
<td>{{device.deviceType}}</td>
|
||||
<td>{{device.targetDevice}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Add Bridge Device for a HAL Device</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||
</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-name"
|
||||
ng-model="device.name" placeholder="Device Name">
|
||||
</div>
|
||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||
ng-click="addDevice()">Add Bridge Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-on-url"
|
||||
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||
</div>
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-dim-url">Dim URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-off-url">Off URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,100 +1,114 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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">
|
||||
<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 +118,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,13 +129,12 @@
|
||||
<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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
@@ -130,4 +143,4 @@
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
@@ -1,121 +1,138 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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">
|
||||
<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 +142,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,13 +153,12 @@
|
||||
<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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
@@ -151,4 +167,4 @@
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
@@ -1,108 +1,129 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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.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="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="bulkAddDevices()">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.device.uniqueid, 'hueDevice')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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,11 +134,10 @@
|
||||
<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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
|
||||
@@ -1,76 +1,86 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</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>
|
||||
151
src/main/resources/public/views/mqttpublish.html
Normal file
151
src/main/resources/public/views/mqttpublish.html
Normal file
@@ -0,0 +1,151 @@
|
||||
<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="#/mqttmessages">MQTT Messages</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">MQTT Messages</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">For any MQTT Broker, use the
|
||||
build button to generate the configuration for the publish generation.
|
||||
You can add topic and content in the text areas provided
|
||||
then selecting the publish generation. 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 MQTT Publish messages' list below will show what is already
|
||||
setup for your MQTT Brokers.</p>
|
||||
</div>
|
||||
|
||||
<scrollable-table watch="bridge.mqttbrokers">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="name">ClientID</th>
|
||||
<th sortable-header col="ip">IP</th>
|
||||
<th>Topic</th>
|
||||
<th>Content</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="mqttbroker in bridge.mqttbrokers">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{mqttbroker.clientId}}</td>
|
||||
<td>{{mqttbroker.ip}}</td>
|
||||
<td>
|
||||
<textarea rows="2" class="form-control" id="mqtt-topic"
|
||||
ng-model="mqtttopic" placeholder="The MQTT Topic"></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="2" class="form-control" id="mqtt-content"
|
||||
ng-model="mqttcontent" placeholder="The MQTT Message Content"></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="buildMQTTPublish(mqttbroker, mqtttopic, mqttcontent)">Build
|
||||
publish Message</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</scrollable-table>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">
|
||||
Already Configured MQTT Messages <a ng-click="toggleButtons()"><span
|
||||
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||
</h2>
|
||||
</div>
|
||||
<scrollable-table ng-if="buttonsVisible" watch="bridge.mqttbrokers">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Row</th>
|
||||
<th sortable-header col="nameclientid">Name</th>
|
||||
<th sortable-header col="ip">ClientID</th>
|
||||
<th>MQTT Message ID</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
ng-repeat="device in bridge.devices | configuredMqttMsgs | orderBy:predicate:reverse">
|
||||
<td>{{$index+1}}</td>
|
||||
<td>{{device.name}}</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 MQTT Messages</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>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
for="device-off-url">Off URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-off-url"
|
||||
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
<p>Are you Sure?</p>
|
||||
</div>
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
@@ -1,122 +1,133 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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">
|
||||
<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 +137,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,13 +148,12 @@
|
||||
<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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
@@ -152,4 +162,4 @@
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
@@ -1,49 +1,58 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</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 +64,48 @@
|
||||
</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 IP Address</td>
|
||||
<td><input id="bridge-settings-webaddress"
|
||||
class="form-control" type="text"
|
||||
ng-model="bridge.settings.webaddress"
|
||||
placeholder="0.0.0.0"></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 +120,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 +149,21 @@
|
||||
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>
|
||||
</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>
|
||||
</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>
|
||||
</table></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 +178,185 @@
|
||||
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>MQTT Client IDs and IP Addresses</td>
|
||||
<td><table
|
||||
class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client ID</th>
|
||||
<th>IP</th>
|
||||
<th>User (opt)</th>
|
||||
<th>Password (opt)</th>
|
||||
<th>Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="mqtt in bridge.settings.mqttaddress.devices">
|
||||
<td>{{mqtt.name}}</td>
|
||||
<td>{{mqtt.ip}}</td>
|
||||
<td>{{mqtt.username}}</td>
|
||||
<td ng-if="mqtt.password">*******</td>
|
||||
<td ng-if="!mqtt.password"> </td>
|
||||
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="removeMQTTtoSettings(mqtt.name, mqtt.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-mqtt-name"
|
||||
class="form-control" type="text" ng-model="newmqttname"
|
||||
placeholder="A MQTT Client ID"></td>
|
||||
<td><input id="bridge-settings-next-mqtt-ip"
|
||||
class="form-control" type="text" ng-model="newmqttip"
|
||||
placeholder="MQTT Broker IP and port"></td>
|
||||
<td><input id="bridge-settings-next-mqtt-username"
|
||||
class="form-control" type="text" ng-model="newmqttusername"
|
||||
placeholder="MQTT Broker username (optional)"></td>
|
||||
<td><input id="bridge-settings-next-mqtt-password"
|
||||
class="form-control" type="password" ng-model="newmqttpassword"
|
||||
placeholder="MQTT Broker password (opt)"></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addMQTTtoSettings(newmqttname, newmqttip, newmqttusername, newmqttpassword)">Add</button></td>
|
||||
</tr>
|
||||
</table></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>
|
||||
<tr>
|
||||
<td>My Echo URL</td>
|
||||
<td><input id="bridge-settings-myechourl" class="form-control"
|
||||
type="text" ng-model="bridge.settings.myechourl"
|
||||
placeholder="echo.amazon.com/#cards"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default backup">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">Bridge Settings Backup <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup Settings File Name</label>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">
|
||||
Bridge Settings Backup <a ng-click="toggle()"><span
|
||||
class={{imgUrl}} aria-hidden="true"></a>
|
||||
</h1>
|
||||
</div>
|
||||
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
|
||||
Settings File Name</label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupSettings(optionalbackupname)">Backup Settings</button>
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input id="backup-name" class="form-control" type="text"
|
||||
ng-model="optionalbackupname" placeholder="Optional">
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.configs">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreSettings(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteSettingsBackup(backup)">Delete</button>
|
||||
</td>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
ng-click="backupSettings(optionalbackupname)">Backup
|
||||
Settings</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tr ng-repeat="backup in bridge.configs">
|
||||
<td>{{backup}}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" type="submit"
|
||||
ng-click="restoreSettings(backup)">Restore</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
ng-click="deleteSettingsBackup(backup)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,125 +1,147 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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">
|
||||
<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,30 +154,29 @@
|
||||
</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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
@@ -164,4 +185,4 @@
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
@@ -1,106 +1,116 @@
|
||||
<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 ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
|
||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="panel panel-default bridgeServer">
|
||||
<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">
|
||||
<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,19 +123,18 @@
|
||||
</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">
|
||||
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||
<div class="ngdialog-message">
|
||||
<h2>Device Map and Id?</h2>
|
||||
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||
@@ -134,4 +143,4 @@
|
||||
<div class="ngdialog-buttons mt">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
Reference in New Issue
Block a user