Compare commits

...

46 Commits

Author SHA1 Message Date
BWS Systems
3bcec27861 Merge pull request #557 from bwssytems/NewConnectors3.1
New connectors3.1

Fixes #454 Somfy Tahoma plugin enhancement
Fixes #430 hex value needed for dimming enhancement question
Fixes #423 Naming & Notes Enhancement Suggestions enhancement
Fixes #512 Dim handling in V4 question
Fixes #467 Available syntaxes besides ${intensity.percent} ? enhancement
Fixes #416 Use ${intensity.percent} with Harmony Hub enhancement question
Fixes #548 Removing Delay or Repeat in Edit-Device results in bad Config bug
Fixes #537 Minor documentation error bug
Fixes #237 Upgrade resulted in duplicates - Need to keep ha-bridge created user for device enhancement question
Fixes #324 Added a optional webhook for harmony-activity changes enhancement
Fixes #492 Use relative path in URLs enhancement
2017-03-17 16:55:23 -05:00
Admin
bb0ffeb570 Added device data value passing, off state change for brigthness, hex
intensity values, updatd ui to cgo back to device touched after
edit/add.
2017-03-17 16:53:21 -05:00
Admin
0c4292bfd7 Update scrollable table and try implement scroll to row. 2017-03-16 17:05:40 -05:00
Admin
0083c5854f Merge branch 'master' into NewConnectors3.1
Conflicts:
	src/main/java/com/bwssystems/HABridge/BridgeSettings.java
2017-03-16 15:18:39 -05:00
Admin
c13b9bd8f4 upate for editing with fields that need not be saved when empty. 2017-03-16 14:57:21 -05:00
BWS Systems
ca5a6c6667 Merge pull request #454 from msbg/master
Somfy Tahoma plugin
2017-03-16 13:59:43 -05:00
Monica Goward
c9c6d6e66d Cleanup json->pojo mapping 2017-03-16 13:13:53 +00:00
Monica Goward
c8b1827150 Fixes post merge to comply with updated js code json 2017-03-16 12:59:43 +00:00
Monica Goward
d7d83e866e Post latest merge from master 2017-03-16 11:55:02 +00:00
Admin
fb24e9d1a3 Updated whitelist handling to save users when created. Also, added
default test user for habridge UI. Made change state to be validated
against whitelist.
2017-03-13 16:37:42 -05:00
Admin
d15a1c58d0 update readme for harmony webhook addition 2017-03-10 16:22:48 -06:00
BWS Systems
08c87eb3aa Merge pull request #324 from CrEaK/master
Added a optional webhook for harmony-activity changes
2017-03-10 08:59:14 -06:00
BWS Systems
7da4bf13e0 Merge pull request #492 from hobbe/patch-1
Use relative path in URLs
2017-03-10 08:58:43 -06:00
BWS Systems
cd701ca02e Merge pull request #531 from digiltd/patch-2
delete kodivolume.md as there is now a page in the wiki
2017-03-09 09:50:59 -06:00
Sam Turner
1b676632fe delete kodivolume.md as there is now a page in the wiki 2017-03-09 14:58:25 +00:00
BWS Systems
62e366c028 Add pics 2017-03-08 16:03:51 -06:00
BWS Systems
838b86a266 Merge pull request #529 from bwssytems/NewConnectors2
Fixed null http handler issue for close.
Fixed uniqueid on copy.
Update TCP handling to save connection. Added debug to http handler.
Fixed hex handling of intensity. Added handling for \n, \t, \r and so forth in tcp,udp and mqtt.
Fixed HA group support. Added JSON check for new devices. Added Device level filtering. Added decimal percentage.

Home assistant service call for groups from HA bridge device bug question
Fixes #444 opened on Feb 5 by papa-legba

Add filtering for getting of devices in the hue api by IP enhancement
Fixes #526 opened 6 hours ago by bwssytems

Dim Values 0.0 to 1.0 enhancement question
Fixes #401 opened on Jan 25 by beandi

Avoid JSON-Parse error in on/dim/offURL by parsing before saving enhancement question
Fixes #326 opened on Dec 23, 2016 by luke-ff

Nest account linked- JsonSyntaxException: enhancement question
Fixes #266 opened on Nov 22, 2016 by smithski

Xiaomi Yeelight support - TCP requests to use \n \r enhancement question
Fixes #415 opened on Jan 28 by mihaifireball

newline enhancement question
Fixes #448 opened 29 days ago by mbreunich

Using Escape Character enhancement question
Fixes #495 opened 12 days ago by craiglt

how to use "${intensity.math(X/4)}" bug question
Fixes #124 opened on Jun 4, 2016 by painkillerde

Can't get bridge to talk to Netcat to send commands via mochad bug question
Fixes #458 opened 26 days ago by instructor1361

hass HA bridge idle problem enhancement question
Fixes #501 opened 11 days ago by erroldee

HA-Bridge 4.2.0 - NullPointer on DomoticzHome bug
Fixes #507 opened 9 days ago by kaaspad

Unique ID - Not Unique bug question
Fixes #513 opened 5 days ago by merlin051
2017-03-08 15:24:52 -06:00
Admin
ed8fc95782 Fixed HA group support. Added JSON check for new devices. Added Device
level filtering. Added decimal percentage.
2017-03-08 14:59:04 -06:00
Admin
f6cb41b880 Fixed hex handling of intensity. Added handling for \n, \t, \r and so
forth in tcp,udp and mqtt.
2017-03-07 16:36:25 -06:00
Admin
a578aa9fd8 Update TCP handling to save connection. Added debug to http handler. 2017-03-06 16:30:23 -06:00
Admin
7b97bd75ae fixed uniqueid on copy 2017-03-03 16:25:45 -06:00
Admin
4de14217b4 Fixed null http handler issue for close 2017-03-02 16:36:56 -06:00
Olivier B
02918dc49d Merge pull request #2 from hobbe/master
Merge master into patch-1
2017-03-01 14:21:06 +01:00
Olivier B
3a8c64aac6 Merge branch 'patch-1' into master 2017-03-01 14:13:53 +01:00
Olivier B
10df2f1c3e Merge pull request #1 from bwssytems/master
Merge bwssystem/ha-bridge into master
2017-03-01 14:10:18 +01:00
Olivier B
c45cb24b20 Use relative path in URLs
This change allows to use HA-Bridge web app from a sub-folder of the web server, eg. http://example.com/habridge.
2017-02-23 21:22:47 +01:00
Monica Goward
88f34f3221 Update to use HABridge HTTPHandler 2017-02-22 21:44:17 +00:00
Monica Goward
15223630eb Merge remote-tracking branch 'remotes/bwssystems/master' 2017-02-22 20:50:04 +00:00
Monica Goward
f8474f5f41 Initial fixes and cleanup prior to pull request 1 2017-02-09 14:26:16 +00:00
Niklas
3fea7f4f1a Change to Generic HTTPClient 2017-02-08 08:29:37 +01:00
Niklas
44fbaa68f8 Merge remote-tracking branch 'upstream/master' 2017-02-08 08:28:53 +01:00
Monica Goward
470f6b3c15 Merge branch 'master' of https://github.com/bwssytems/ha-bridge 2017-02-06 21:24:44 +00:00
Monica Goward
2fbf26a5fa Merge branch 'master' of https://github.com/bwssytems/ha-bridge 2017-02-05 20:02:14 +00:00
Monica Goward
ee066f1449 Cleanup 2017-02-04 19:12:20 +00:00
Monica Goward
e5871e61b5 Added some initial docs 2017-02-04 19:04:34 +00:00
Monica Goward
6b8a714959 Re-instating line endings that were erroneously removed 2017-02-04 18:40:28 +00:00
Monica Goward
cf3ec7cfe4 Merge branch 'master' of https://github.com/bwssytems/ha-bridge 2017-02-04 18:30:07 +00:00
Monica Goward
805aac9fde Add Somfy devices 2017-02-04 18:29:50 +00:00
Monica Goward
1221df4c96 add Somfy settings 2017-02-04 18:28:59 +00:00
Monica Goward
1c897e3b36 Add Somfy devices 2017-02-04 18:28:25 +00:00
Monica Goward
65b0d6e470 HTML headers updates only 2017-02-03 12:08:46 +00:00
Monica Goward
99e2243e2d HTML headers updates only 2017-02-03 12:07:44 +00:00
Monica Goward
7a354619d0 Generated pojos from JSON Somfy return data 2017-02-03 12:01:47 +00:00
Monica Goward
2dc245bb96 HTML headers updates only 2017-02-03 11:51:05 +00:00
Niklas
e36145f216 NPE-Check for harmony webhook 2016-12-27 13:33:27 +01:00
Niklas
8cd571c183 Added a optional webhook for harmony-activity changes 2016-12-23 19:57:34 +01:00
56 changed files with 3133 additions and 1849 deletions

124
README.md
View File

@@ -1,6 +1,32 @@
# ha-bridge
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.
Here are some diagrams to put this software in perspective.
The Echo Path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
| Amazon Echo |----->| U P | ha-bridge core |--->| P | Device to control| |
+-------------+ | E I +------------------| | I +------------------+ |
+------------------------+ +------------------------+
```
The Google Home Path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
| Google Home |----->| U P | ha-bridge core |--->| P | Device to control| |
+-------------+ | E I +------------------| | I +------------------+ |
+------------------------+ +------------------------+
```
THe Harmony Hub Path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
| Harmony Hub |----->| U P | ha-bridge core |--->| P | Device to control| |
+-------------+ | E I +------------------| | I +------------------+ |
+------------------------+ +------------------------+
```
**SECURITY RISK: If you are unsure on how this software operates and what it exposes to your network, please make sure you understand that it can allow root access to your system. It is best practice to not open this to the Internet through your router as there are no security protocols in place to protect the system. The License agreement states specifically that you use this at your own risk.**
**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!**
@@ -11,7 +37,7 @@ Emulates Philips Hue api to other home automation gateways such as an Amazon Ech
**FAQ: Please look here for the current FAQs! https://github.com/bwssytems/ha-bridge/wiki/HA-Bridge-FAQs**
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.
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, Somfy Tahoma and the ability to proxy all of your real Hue bridges behind this bridge.
Alternatively the Bridge supports custom calls as well using http/https/udp and tcp such as the LimitlessLED/MiLight bulbs using the UDP protocol. Binary data is supported with UDP/TCP.
@@ -33,23 +59,23 @@ ATTENTION: This requires JDK 1.8 to run
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
```
java -jar ha-bridge-4.2.0.jar
java -jar ha-bridge-4.3.0.jar
```
### Automation on Linux systems
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-4.2.0.jar is in your /home/pi/habridge directory.
Create the directory and make sure that ha-bridge-4.3.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/v4.2.0/ha-bridge-4.2.0.jar
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.0/ha-bridge-4.3.0.jar
```
Create the directory and make sure that ha-bridge-4.2.0.jar is in your /home/pi/habridge directory.
Create the directory and make sure that ha-bridge-4.3.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/v4.2.0/ha-bridge-4.2.0.jar
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.0/ha-bridge-4.3.0.jar
```
#### System Control Setup on a pi (preferred)
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
@@ -69,7 +95,7 @@ After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.0.jar
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.0.jar
[Install]
WantedBy=multi-user.target
@@ -104,7 +130,7 @@ 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-4.2.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
chmod 777 /home/pi/habridge/habridge-log.txt
```
@@ -149,54 +175,6 @@ Added the following lines to my Apache config file “000-default”
</VirtualHost>
```
service apache2 restart
### lighthttpd Example
```
server.modules += ( "mod_proxy" )
proxy.server = (
"/api" =>
(
( "host" => "127.0.0.1",
"port" => "8080"
)
)
)
```
### nginx Example
```
location /api/ {
proxy_pass http://127.0.0.1:8080/api;
}
```
## Run ha-bridge alongside web server already on port 80
These examples will help you proxy your current webserver requests to the ha-bridge running on a different port, such as 8080.
### Apache Example
Reverse proxy with Apache on Ubuntu linux:
a2enmod proxy
a2enmod proxy_http
a2enmod headers
Added the following lines to my Apache config file “000-default”
```
<VirtualHost *:80>
ProxyPass /api http://localhost:8080/api nocanon
ProxyPassReverse /api http://localhost:8080/api
ProxyRequests Off
AllowEncodedSlashes NoDecode
# Local reverse proxy authorization override
# Most unix distribution deny proxy by default (ie /etc/apache2/mods-enabled/proxy.conf in Ubuntu)
<Proxy http://localhost:8080/api*>
Order deny,allow
Allow from all
</Proxy>
….. (the rest of the VirtualHost config section) …..
</VirtualHost>
```
service apache2 restart
### lighthttpd Example
```
@@ -261,13 +239,9 @@ The server defaults to running on port 80. To override what the default is, spec
#### 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 device/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
deprecated
#### Harmony Password
deprecated
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. Also, an option of webhook can be called when the activity changes on the harmony hub that will send an HTTP GET call to the the address of your choosing. This can contain the replacement variables of ${activity.id} and/or ${activity.label}. Example : http://192.168.0.1/activity/${activity.id}/${activity.label} OR http://hook?a=${activity.label}
#### 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.
@@ -284,6 +258,10 @@ The user name of the home.nest.com account for the Nest user. This needs to be g
The password for 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.
#### Nest Temp Fahrenheit
This setting allows the value being sent into the bridge to be interpreted as Fahrenheit or Celsius. The default is to have Fahrenheit.
#### Somfy Tahoma Username
The user name used to login to www.tahomalink.com. This needs to be provided if you're using the Somfy Tahoma features (for connecting to IO Homecontrol used by Velux among others). There is no need to give any IP address or host information as this contacts your cloud account. *Note:* you have to 'turn on' a window to open it, and 'turn off' to close.
#### Somfy Tahoma Password
The password associated with the Somfy Tahoma username above
#### Button Press/Call Item Loop Sleep Interval (ms)
This setting is the time used in between button presses when there is multiple buttons in a button device. It also controls the time between multiple items in a custom device call. This is defaulted to 100ms and the number represents milliseconds (1000 milliseconds = 1 second).
#### Log Messages to Buffer
@@ -314,7 +292,7 @@ There is a new format for the on/dim/off URL areas. The new editor handles the i
Here are the fields that can be put into the call item:
Json Type | field name | What | Use
----------|------------|------|-----
String or JsonElement | item| This is the payload that will be called for devices | Required
String or JsonElement | item | This is the payload that will be called for devices | Required
Integer | count | This is how many times this items will be executed | Optional
Integer | delay | This is how long we will wait until the next call after | Optional
String | type | This is the type of device we are executing | Required
@@ -334,7 +312,7 @@ The Add/Edit tab will show you the fields to fill in for the above in a form, wh
The format of the item can be the default HTTP request which executes the URLs formatted as `http://<your stuff here>` as a GET. Other options to this are to select the HTTP Verb and add the data type and add a body that is passed with the request. Secure https is supported as well, just use `https://<your secure call here>`. When using POST and PUT, you have the ability to specify the body that will be sent with the request as well as the application type for the http call.
The valid device types are: "custom", "veraDevice", "veraScene", "harmonyActivity", "harmonyButton", "nestHomeAway", "nestThermoSet", "hueDevice", "halDevice",
"halButton", "halHome", "halThermoSet", "mqttMessage", "cmdDevice", "hassDevice", "tcpDevice", "udpDevice", "httpDevice", "domoticzDevice"
"halButton", "halHome", "halThermoSet", "mqttMessage", "cmdDevice", "hassDevice", "tcpDevice", "udpDevice", "httpDevice", "domoticzDevice", "somfyDevice"
Filter Ip example:
```
@@ -354,7 +332,7 @@ Headers can be added as well using a Json construct [{"name":"header type name",
Another option that is detected by the bridge is to use UDP or TCP direct calls such as `udp://<ip_address>:<port>/<your stuff here>` to send a UDP request. TCP calls are handled the same way as `tcp://<ip_address>:<port>/<your stuff here>`. If your data for the UDP or TCP request is formatted as "0x00F009B9" lexical hex format, the bridge will convert the data into a binary stream to send.
You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}". See Value Passing Controls Below.
You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} or ${intensity.percent.hex} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} or ${intensity.byte.hex} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}" or "${intensity.math(X/4).hex}". See Value Passing Controls Below.
Examples:
```
@@ -399,18 +377,18 @@ To configure this type of manual add, you will need to select the Device type of
In the URL areas, the format of the execution is just providing what command line you would like to run, or using the multiple call item construct described above.
```
[{"item":"C:\\Users\\John\\Documents\\Applications\\putty.exe 192.168.1.1","type":"cmdDevice"},
{"item":"notepad.exe","type":"cmdDevice"}]
OR
[{"item":"exec://notepad.exe","type":"cmdDevice"}]
[{"item":"exec://C:\\Users\\John\\Documents\\Applications\\putty.exe 192.168.1.1","type":"cmdDevice"},{"item":"exec://notepad.exe","type":"cmdDevice"}]
[{"item":"/home/pi/scripts/dothisscript.sh","type":"cmdDevice"}]
```
#### Value Passing Controls
There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.byte}" and "${intensity.math(using X in your calc)}".
There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.percent.hex}", "${intensity.decimal_percent}", "${intensity.byte}", "${intensity.byte.hex}", "${intensity.math(using X in your calc)}" and "${intensity.math(using X in your calc).hex}".
You can control items that require special calculated values using ${intensity.math(<your expression using "X" as the value to operate on>)} i.e. "${intensity.math(X/4)}".
For the items that want to have a date time put into the message, utilize ${time.format(yyyy-MM-ddTHH:mm:ssXXX)} where "yyyy-MM-ddTHH:mm:ssXXX" can be any format from the Java SimpleDateFormat documented here: https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
Also, device data can be inserted into your payloads by the use of "${device.name}", "${device.id}", "${device.uniqueid}", "${device.targetDevice}", "${device.mapId}", "${device.mapType}" and "${device.deviceType}". These work just like the dimming value replacements.
e.g.
```
[{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=10&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.math(X/4)}","type":"httpDevice"}]
@@ -518,7 +496,7 @@ contentBodyOff | string | This is the content body that you would like to send w
}
```
#### Dimming Control Example
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value.
Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} for 0-255 for straight pass through of the value.
e.g.
```
{

View File

@@ -1,144 +0,0 @@
# 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 doesnt include **“volume”** as it will cause conflicts with the Echos built in volume controls. A device name of **“cody sound”** 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 dont 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 dont 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}
```
### Test the three URLS
You should now be able to control the volume of Kodi using the structured URL you built above in a browser.
If you cant get it to work in a browser then you wont be able to get it to work in HA Bridge.
### Manually adding the device
Add a new manual device and give it a name e.g. “Cody Sound”
Set `Device type` to `Custom`
Use the same URL for all three (ON, OFF, DIM)
```
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=
```
* `HTTP Verb` to `POST`
* `Content type` to `application/json`
**Content body On**
```json
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
```
**Content body Dim**
```json
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":${intensity.percent}},"id":1}
```
**Content body Off**
```json
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
```
### HA Bridge
Save and test the button in the Bridge Devices tab and hopefully it should turn the volume up in Kodi.
### Controlling the Device
You can use the commands as listed in the [README](https://github.com/bwssytems/ha-bridge#ask-alexa)
“Set Cody Sound to 50 percent”
“Cody Sound to 70 percent”
Remembering that “Turn on Cody Sound” will set the volume to 100%, and “Turn off Cody Sound” will mute.

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>4.2.0</version>
<version>4.3.0</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
@@ -48,7 +48,7 @@
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>nest-controller</artifactId>
<version>1.0.13</version>
<version>1.0.14</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@@ -126,6 +126,11 @@
<artifactId>lifx-sdk-java</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
</dependencies>
<build>

View File

@@ -46,6 +46,7 @@ public class BridgeSettings extends BackupHandler {
public void buildSettings() {
String addressString = null;
String theVeraAddress = null;
String theSomfyAddress = null;
String theHarmonyAddress = null;
String configFileProperty = System.getProperty("config.file");
if(configFileProperty == null) {
@@ -103,6 +104,23 @@ public class BridgeSettings extends BackupHandler {
}
}
theBridgeSettings.setHarmonyAddress(theHarmonyList);
theSomfyAddress = System.getProperty("somfy.address");
IpList theSomfyList = null;
if(theSomfyAddress != null) {
try {
theSomfyList = new Gson().fromJson(theSomfyAddress, IpList.class);
} catch (Exception e) {
try {
theSomfyList = new Gson().fromJson("{devices:[{name:default,ip:" + theSomfyAddress + "}]}", IpList.class);
} catch (Exception et) {
log.error("Cannot parse somfy.address, not set with message: " + e.getMessage(), e);
theSomfyList = null;
}
}
}
theBridgeSettings.setSomfyAddress(theSomfyList);
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)));
@@ -148,12 +166,15 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setMqttconfigured(theBridgeSettings.isValidMQTT());
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
// Lifx is either configured or not, so it does not need an update.
if(serverPortOverride != null)
theBridgeSettings.setServerPort(serverPortOverride);
if(serverIpOverride != null)
theBridgeSettings.setWebaddress(serverIpOverride);
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
setupInternalTestUser();
}
public void loadConfig() {
@@ -188,6 +209,16 @@ public class BridgeSettings extends BackupHandler {
}
public void updateConfigFile() {
log.debug("Save HA Bridge settings.");
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(theBridgeSettings);
configWriter(jsonValue, configPath);
_loadConfig(configPath);
}
private void configWriter(String content, Path filePath) {
if(Files.exists(filePath) && !Files.isWritable(filePath)){
log.error("Error file is not writable: " + filePath);
@@ -279,4 +310,9 @@ public class BridgeSettings extends BackupHandler {
}
return addressString;
}
private void setupInternalTestUser() {
theBridgeSettings.setupInternalTestUser();
if(theBridgeSettings.isSettingsChanged())
this.updateConfigFile();
}
}

View File

@@ -1,12 +1,21 @@
package com.bwssystems.HABridge;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
public class BridgeSettingsDescriptor {
private static final String DEFAULT_INTERNAL_USER = "thehabridgeuser";
private static final String DEFAULT_USER_DESCRIPTION = "default_test_user";
private String upnpconfigaddress;
private Integer serverport;
private Integer upnpresponseport;
@@ -40,6 +49,9 @@ public class BridgeSettingsDescriptor {
private String hubversion;
private IpList domoticzaddress;
private boolean domoticzconfigured;
private IpList somfyaddress;
private boolean somfyconfigured;
private boolean lifxconfigured;
public BridgeSettingsDescriptor() {
@@ -48,6 +60,7 @@ public class BridgeSettingsDescriptor {
this.traceupnp = false;
this.nestconfigured = false;
this.veraconfigured = false;
this.somfyconfigured = false;
this.harmonyconfigured = false;
this.hueconfigured = false;
this.halconfigured = false;
@@ -93,9 +106,15 @@ public class BridgeSettingsDescriptor {
public IpList getVeraAddress() {
return veraaddress;
}
public IpList getSomfyAddress() {
return somfyaddress;
}
public void setVeraAddress(IpList veraAddress) {
this.veraaddress = veraAddress;
}
public void setSomfyAddress(IpList somfyAddress) {
this.somfyaddress = somfyAddress;
}
public IpList getHarmonyAddress() {
return harmonyaddress;
}
@@ -129,9 +148,15 @@ public class BridgeSettingsDescriptor {
public boolean isVeraconfigured() {
return veraconfigured;
}
public boolean isSomfyconfigured() {
return somfyconfigured;
}
public void setVeraconfigured(boolean veraconfigured) {
this.veraconfigured = veraconfigured;
}
public void setSomfyconfigured(boolean somfyconfigured) {
this.somfyconfigured = somfyconfigured;
}
public boolean isHarmonyconfigured() {
return harmonyconfigured;
}
@@ -335,7 +360,88 @@ public class BridgeSettingsDescriptor {
return false;
return true;
}
public Boolean isValidSomfy() {
if(this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getSomfyAddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidLifx() {
return this.isLifxconfigured();
}
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
String validUser = null;
boolean found = false;
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
&& !aUser.equalsIgnoreCase("")) {
if (whitelist != null) {
Set<String> theUserIds = whitelist.keySet();
Iterator<String> userIterator = theUserIds.iterator();
while (userIterator.hasNext()) {
validUser = userIterator.next();
if (validUser.equals(aUser))
found = true;
}
}
}
if(!found && !strict) {
newWhitelistUser(aUser, userDescription);
found = true;
}
if (!found) {
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
}
return null;
}
public void newWhitelistUser(String aUser, String userDescription) {
if (whitelist == null) {
whitelist = new HashMap<>();
}
if(userDescription == null)
userDescription = "auto insert user";
whitelist.put(aUser, WhitelistEntry.createEntry(userDescription));
setSettingsChanged(true);
}
public String createWhitelistUser(String userDescription) {
String aUser = getNewUserID();
newWhitelistUser(aUser, userDescription);
return aUser;
}
private String getNewUserID() {
UUID uid = UUID.randomUUID();
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
String newUser = "";
while (st.hasMoreTokens()) {
newUser = newUser + st.nextToken();
}
return newUser;
}
public String getInternalTestUser() {
return DEFAULT_INTERNAL_USER;
}
public void setupInternalTestUser() {
boolean found = false;
for (String key : whitelist.keySet()) {
if(key.equals(DEFAULT_INTERNAL_USER))
found = true;
}
if(!found) {
newWhitelistUser(DEFAULT_INTERNAL_USER, DEFAULT_USER_DESCRIPTION);
}
}
}

View File

@@ -1,84 +1,87 @@
package com.bwssystems.HABridge;
import java.util.ArrayList;
public class DeviceMapTypes {
public final static String[] CUSTOM_DEVICE = { "custom", "Custom"};
public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"};
public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"};
public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"};
public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"};
public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"};
public final static String[] NEST_THERMO_SET = { "nestThermoSet", "Nest Thermostat"};
public final static String[] HUE_DEVICE = { "hueDevice", "Hue Device"};
public final static String[] HAL_DEVICE = { "halDevice", "HAL Device"};
public final static String[] HAL_BUTTON = { "halButton", "HAL Button"};
public final static String[] HAL_HOME = { "halHome", "HAL Home Status"};
public final static String[] HAL_THERMO_SET = { "halThermoSet", "HAL Thermostat"};
public final static String[] MQTT_MESSAGE = { "mqttMessage", "MQTT Message"};
public final static String[] EXEC_DEVICE_COMPAT = { "exec", "Execute Script/Program"};
public final static String[] CMD_DEVICE = { "cmdDevice", "Execute Command/Script/Program"};
public final static String[] HASS_DEVICE = { "hassDevice", "HomeAssistant Device"};
public final static String[] TCP_DEVICE = { "tcpDevice", "TCP Device"};
public final static String[] TCP_DEVICE_COMPAT = { "TCP", "TCP Device"};
public final static String[] UDP_DEVICE = { "udpDevice", "UDP Device"};
public final static String[] UDP_DEVICE_COMPAT = { "UDP", "UDP Device"};
public final static String[] HTTP_DEVICE = { "httpDevice", "HTTP Device"};
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz Device"};
public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
public final static int typeIndex = 0;
public final static int displayIndex = 1;
ArrayList<String[]> deviceMapTypes;
public DeviceMapTypes() {
super();
deviceMapTypes = new ArrayList<String[]>();
deviceMapTypes.add(CMD_DEVICE);
deviceMapTypes.add(DOMOTICZ_DEVICE);
deviceMapTypes.add(HAL_DEVICE);
deviceMapTypes.add(HAL_HOME);
deviceMapTypes.add(HAL_THERMO_SET);
deviceMapTypes.add(HAL_BUTTON);
deviceMapTypes.add(HARMONY_ACTIVITY);
deviceMapTypes.add(HARMONY_BUTTON);
deviceMapTypes.add(HASS_DEVICE);
deviceMapTypes.add(HTTP_DEVICE);
deviceMapTypes.add(HUE_DEVICE);
deviceMapTypes.add(LIFX_DEVICE);
deviceMapTypes.add(MQTT_MESSAGE);
deviceMapTypes.add(NEST_HOMEAWAY);
deviceMapTypes.add(NEST_THERMO_SET);
deviceMapTypes.add(TCP_DEVICE);
deviceMapTypes.add(UDP_DEVICE);
deviceMapTypes.add(VERA_DEVICE);
deviceMapTypes.add(VERA_SCENE);
}
public static int getTypeIndex() {
return typeIndex;
}
public static int getDisplayIndex() {
return displayIndex;
}
public ArrayList<String[]> getDeviceMapTypes() {
return deviceMapTypes;
}
public Boolean validateType(String type) {
if(type == null || type.trim().isEmpty())
return false;
for(String[] mapType : deviceMapTypes) {
if(type.trim().contentEquals(mapType[typeIndex]))
return true;
}
if(type.trim().contentEquals(EXEC_DEVICE_COMPAT[typeIndex]))
return true;
if(type.trim().contentEquals(TCP_DEVICE_COMPAT[typeIndex]))
return true;
if(type.trim().contentEquals(UDP_DEVICE_COMPAT[typeIndex]))
return true;
return false;
}
package com.bwssystems.HABridge;
import java.util.ArrayList;
public class DeviceMapTypes {
public final static String[] CUSTOM_DEVICE = { "custom", "Custom"};
public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"};
public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"};
public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"};
public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"};
public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"};
public final static String[] NEST_THERMO_SET = { "nestThermoSet", "Nest Thermostat"};
public final static String[] HUE_DEVICE = { "hueDevice", "Hue Device"};
public final static String[] HAL_DEVICE = { "halDevice", "HAL Device"};
public final static String[] HAL_BUTTON = { "halButton", "HAL Button"};
public final static String[] HAL_HOME = { "halHome", "HAL Home Status"};
public final static String[] HAL_THERMO_SET = { "halThermoSet", "HAL Thermostat"};
public final static String[] MQTT_MESSAGE = { "mqttMessage", "MQTT Message"};
public final static String[] EXEC_DEVICE_COMPAT = { "exec", "Execute Script/Program"};
public final static String[] CMD_DEVICE = { "cmdDevice", "Execute Command/Script/Program"};
public final static String[] HASS_DEVICE = { "hassDevice", "HomeAssistant Device"};
public final static String[] TCP_DEVICE = { "tcpDevice", "TCP Device"};
public final static String[] TCP_DEVICE_COMPAT = { "TCP", "TCP Device"};
public final static String[] UDP_DEVICE = { "udpDevice", "UDP Device"};
public final static String[] UDP_DEVICE_COMPAT = { "UDP", "UDP Device"};
public final static String[] HTTP_DEVICE = { "httpDevice", "HTTP Device"};
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz Device"};
public final static String[] SOMFY_DEVICE = { "somfyDevice", "Somfy Device"};
public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
public final static int typeIndex = 0;
public final static int displayIndex = 1;
ArrayList<String[]> deviceMapTypes;
public DeviceMapTypes() {
super();
deviceMapTypes = new ArrayList<String[]>();
deviceMapTypes.add(CMD_DEVICE);
deviceMapTypes.add(DOMOTICZ_DEVICE);
deviceMapTypes.add(HAL_DEVICE);
deviceMapTypes.add(HAL_HOME);
deviceMapTypes.add(HAL_THERMO_SET);
deviceMapTypes.add(HAL_BUTTON);
deviceMapTypes.add(HARMONY_ACTIVITY);
deviceMapTypes.add(HARMONY_BUTTON);
deviceMapTypes.add(HASS_DEVICE);
deviceMapTypes.add(HTTP_DEVICE);
deviceMapTypes.add(HUE_DEVICE);
deviceMapTypes.add(LIFX_DEVICE);
deviceMapTypes.add(MQTT_MESSAGE);
deviceMapTypes.add(NEST_HOMEAWAY);
deviceMapTypes.add(NEST_THERMO_SET);
deviceMapTypes.add(SOMFY_DEVICE);
deviceMapTypes.add(TCP_DEVICE);
deviceMapTypes.add(UDP_DEVICE);
deviceMapTypes.add(VERA_DEVICE);
deviceMapTypes.add(VERA_SCENE);
deviceMapTypes.add(SOMFY_DEVICE);
}
public static int getTypeIndex() {
return typeIndex;
}
public static int getDisplayIndex() {
return displayIndex;
}
public ArrayList<String[]> getDeviceMapTypes() {
return deviceMapTypes;
}
public Boolean validateType(String type) {
if(type == null || type.trim().isEmpty())
return false;
for(String[] mapType : deviceMapTypes) {
if(type.trim().contentEquals(mapType[typeIndex]))
return true;
}
if(type.trim().contentEquals(EXEC_DEVICE_COMPAT[typeIndex]))
return true;
if(type.trim().contentEquals(TCP_DEVICE_COMPAT[typeIndex]))
return true;
if(type.trim().contentEquals(UDP_DEVICE_COMPAT[typeIndex]))
return true;
return false;
}
}

View File

@@ -72,7 +72,7 @@ public class HABridge {
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
theSettingResponder.setupServer();
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), homeManager);
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), homeManager);
theHueMulator.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();

View File

@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.plugins.lifx.LifxHome;
import com.bwssystems.HABridge.plugins.mqtt.MQTTHome;
import com.bwssystems.HABridge.plugins.somfy.SomfyHome;
import com.bwssystems.HABridge.plugins.tcp.TCPHome;
import com.bwssystems.HABridge.plugins.udp.UDPHome;
import com.bwssystems.HABridge.plugins.vera.VeraHome;
@@ -88,6 +89,10 @@ public class HomeManager {
aHome = new DomoticzHome(bridgeSettings);
homeList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the Somfy configuration if available
aHome = new SomfyHome(bridgeSettings);
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the Lifx configuration if available
aHome = new LifxHome(bridgeSettings);
resourceList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);

View File

@@ -2,7 +2,8 @@ package com.bwssystems.HABridge;
public class NamedIP {
private String name;
private String ip;
private String ip;
private String webhook;
private String port;
private String username;
private String password;
@@ -20,7 +21,13 @@ public class NamedIP {
public void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
public String getWebhook() {
return webhook;
}
public void setWebhook(final String webhook) {
this.webhook = webhook;
}
public String getPort() {
return port;
}
public void setPort(String port) {

View File

@@ -62,6 +62,13 @@ public class SystemControl {
return "{\"version\":\"" + version.getVersion() + "\"}";
});
// http://ip_address:port/system/habridge/testuser gets the valid test user for calling the api
get (SYSTEM_CONTEXT + "/habridge/testuser", "application/json", (request, response) -> {
log.debug("Get HA Bridge testuser: " + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser());
response.status(HttpStatus.SC_OK);
return "{\"user\":\"" + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser() + "\"}";
});
// http://ip_address:port/system/logmsgs gets the log messages for the bridge
get (SYSTEM_CONTEXT + "/logmsgs", "application/json", (request, response) -> {
log.debug("Get logmsgs.");

View File

@@ -62,6 +62,18 @@ public class DeviceDescriptor{
@SerializedName("noState")
@Expose
private boolean noState;
@SerializedName("offState")
@Expose
private boolean offState;
@SerializedName("requesterAddress")
@Expose
private String requesterAddress;
@SerializedName("description")
@Expose
private String description;
@SerializedName("comments")
@Expose
private String comments;
private DeviceState deviceState;
@@ -219,6 +231,38 @@ public class DeviceDescriptor{
this.noState = noState;
}
public boolean isOffState() {
return offState;
}
public void setOffState(boolean offState) {
this.offState = offState;
}
public String getRequesterAddress() {
return requesterAddress;
}
public void setRequesterAddress(String requesterAddress) {
this.requesterAddress = requesterAddress;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public boolean containsType(String aType) {
if(aType == null)
return false;

View File

@@ -83,6 +83,33 @@ public class DeviceRepository extends BackupHandler {
return list;
}
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);
}

View File

@@ -18,12 +18,15 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.HomeManager;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
import com.bwssystems.HABridge.dao.ErrorMessage;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
/**
spark core server for bridge configuration
@@ -33,11 +36,13 @@ public class DeviceResource {
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
private DeviceRepository deviceRepository;
private HomeManager homeManager;
private Gson aGsonHandler;
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
homeManager = aHomeManager;
aGsonHandler = new GsonBuilder().create();
setupEndpoints();
}
@@ -65,14 +70,44 @@ public class DeviceResource {
else {
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
}
CallItem[] callItems = null;
String errorMessage = null;
for(int i = 0; i < devices.length; i++) {
if(devices[i].getContentBody() != null ) {
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
response.status(HttpStatus.SC_BAD_REQUEST);
log.debug("Bad http verb in create a Device(s): " + request.body());
return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
}
try {
if(devices[i].getOnUrl() != null && !devices[i].getOnUrl().isEmpty())
callItems = aGsonHandler.fromJson(devices[i].getOnUrl(), CallItem[].class);
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
if(devices[i].getDimUrl() != null && !devices[i].getDimUrl().isEmpty())
callItems = aGsonHandler.fromJson(devices[i].getDimUrl(), CallItem[].class);
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
if(devices[i].getOffUrl() != null && !devices[i].getOffUrl().isEmpty())
callItems = aGsonHandler.fromJson(devices[i].getOffUrl(), CallItem[].class);
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
}
deviceRepository.save(devices);
@@ -225,7 +260,13 @@ public class DeviceResource {
return homeManager.findResource(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/map/types", "application/json", (request, response) -> {
get (API_CONTEXT + "/somfy/devices", "application/json", (request, response) -> {
log.debug("Get somfy devices");
response.status(HttpStatus.SC_OK);
return homeManager.findResource(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/map/types", "application/json", (request, response) -> {
log.debug("Get map types");
return new DeviceMapTypes().getDeviceMapTypes();
}, new JsonTransformer());

View File

@@ -3,6 +3,8 @@ package com.bwssystems.HABridge.hue;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.Conversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.java.dev.eval.Expression;
@@ -10,10 +12,14 @@ import net.java.dev.eval.Expression;
public class BrightnessDecode {
private static final Logger log = LoggerFactory.getLogger(BrightnessDecode.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}";
private static final String INTENSITY_DECIMAL_PERCENT = "${intensity.decimal_percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}";
private static final String INTENSITY_MATH = "${intensity.math(";
private static final String INTENSITY_MATH_VALUE = "X";
private static final String INTENSITY_MATH_CLOSE = ")}";
private static final String INTENSITY_MATH_CLOSE_HEX = ").hex}";
private static final String INTENSITY_PERCENT_HEX = "${intensity.percent.hex}";
private static final String INTENSITY_BYTE_HEX = "${intensity.byte.hex}";
public static int calculateIntensity(int setIntensity, Integer targetBri, Integer targetBriInc) {
if (targetBri != null) {
@@ -42,45 +48,79 @@ public class BrightnessDecode {
if (request == null) {
return null;
}
if (request.contains(INTENSITY_BYTE)) {
if (isHex) {
String hexValue = Integer.toHexString(intensity);
request = request.replace(INTENSITY_BYTE, hexValue);
} else {
String intensityByte = String.valueOf(intensity);
request = request.replace(INTENSITY_BYTE, intensityByte);
}
} else if (request.contains(INTENSITY_PERCENT)) {
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
if (isHex) {
String hexValue = Integer.toHexString(percentBrightness);
request = request.replace(INTENSITY_PERCENT, hexValue);
} else {
String intensityPercent = String.valueOf(percentBrightness);
request = request.replace(INTENSITY_PERCENT, intensityPercent);
}
} else if (request.contains(INTENSITY_MATH)) {
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
request.indexOf(INTENSITY_MATH_CLOSE));
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
try {
boolean notDone = true;
String replaceValue = null;
String replaceTarget = null;
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
float decimalBrightness = (float) (intensity / 255.0);
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = null;
while(notDone) {
notDone = false;
if (request.contains(INTENSITY_BYTE)) {
if (isHex) {
replaceValue = convertToHex(intensity);
} else {
replaceValue = String.valueOf(intensity);
}
replaceTarget = INTENSITY_BYTE;
notDone = true;
} else if (request.contains(INTENSITY_BYTE_HEX)) {
replaceValue = convertToHex(intensity);
replaceTarget = INTENSITY_BYTE_HEX;
notDone = true;
} else if (request.contains(INTENSITY_PERCENT)) {
if (isHex) {
replaceValue = convertToHex(percentBrightness);
} else {
replaceValue = String.valueOf(percentBrightness);
}
replaceTarget = INTENSITY_PERCENT;
notDone = true;
} else if (request.contains(INTENSITY_PERCENT_HEX)) {
replaceValue = convertToHex(percentBrightness);
replaceTarget = INTENSITY_PERCENT_HEX;
notDone = true;
} else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
replaceValue = String.format("%1.2f", decimalBrightness);
replaceTarget = INTENSITY_DECIMAL_PERCENT;
notDone = true;
} else if (request.contains(INTENSITY_MATH_CLOSE)) {
mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
request.indexOf(INTENSITY_MATH_CLOSE));
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: "
+ String.valueOf(intensity));
Expression exp = new Expression(mathDescriptor);
BigDecimal result = exp.eval(variables);
Integer endResult = Math.round(result.floatValue());
if (isHex) {
String hexValue = Integer.toHexString(endResult);
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, hexValue);
} else {
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE,
endResult.toString());
Integer endResult = calculateMath(variables, mathDescriptor);
if(endResult != null) {
if (isHex) {
replaceValue = convertToHex(endResult);
} else {
replaceValue = endResult.toString();
}
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE;
notDone = true;
}
} else if (request.contains(INTENSITY_MATH_CLOSE_HEX)) {
mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
request.indexOf(INTENSITY_MATH_CLOSE_HEX));
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
Integer endResult = calculateMath(variables, mathDescriptor);
if(endResult != null) {
if (isHex) {
replaceValue = convertToHex(endResult);
} else {
replaceValue = endResult.toString();
}
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE_HEX;
notDone = true;
}
} catch (Exception e) {
log.warn("Could not execute Math: " + mathDescriptor, e);
}
if(notDone)
request = request.replace(replaceTarget, replaceValue);
}
return request;
}
@@ -89,4 +129,28 @@ public class BrightnessDecode {
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
}
}
// Apache Commons Conversion utils likes little endian too much
private static String convertToHex(int theValue) {
String destHex = "00";
String hexValue = Conversion.intToHex(theValue, 0, destHex, 0, 2);
byte[] theBytes = hexValue.getBytes();
byte[] newBytes = new byte[2];
newBytes[0] = theBytes[1];
newBytes[1] = theBytes[0];
return new String(newBytes);
}
private static Integer calculateMath(Map<String, BigDecimal> variables, String mathDescriptor) {
Integer endResult = null;
try {
Expression exp = new Expression(mathDescriptor);
BigDecimal result = exp.eval(variables);
endResult = Math.round(result.floatValue());
} catch (Exception e) {
log.warn("Could not execute Math: " + mathDescriptor, e);
endResult = null;
}
return endResult;
}
}

View File

@@ -0,0 +1,21 @@
package com.bwssystems.HABridge.hue;
import java.util.List;
public class ColorDecode {
public static String convertCIEtoRGB(List<Double> xy) {
double x;
double y;
double Y;
x = xy.get(0) * 100;
y = xy.get(1) * 100;
Y= y;
double R = 3.240479*((x*Y)/y) + -1.537150*Y + -0.498535*(((1-x-y)*Y)/y);
double G = -0.969256*((x*Y)/y) + 1.875992*Y + 0.041556*(((1-x-y)*Y)/y);
double B = 0.055648*((x*Y)/y) + -0.204043*Y + 1.057311*(((1-x-y)*Y)/y);
return null;
}
}

View File

@@ -0,0 +1,66 @@
package com.bwssystems.HABridge.hue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
public class DeviceDataDecode {
private static final Logger log = LoggerFactory.getLogger(DeviceDataDecode.class);
private static final String DEVICE_ID = "${device.id}";
private static final String DEVICE_UNIQUEID = "${device.uniqueid}";
private static final String DEVICE_NAME = "${device.name}";
private static final String DEVICE_MAPID = "${device.mapId}";
private static final String DEVICE_MAPTYPE = "${device.mapType}";
private static final String DEVICE_DEVICETYPE = "${device.deviceType}";
private static final String DEVICE_TARGETDEVICE = "${device.targetDevice}";
public static String replaceDeviceData(String request, DeviceDescriptor device) {
if (request == null) {
return null;
}
boolean notDone = true;
while(notDone) {
notDone = false;
if (request.contains(DEVICE_ID)) {
request = request.replace(DEVICE_ID, device.getId());
notDone = true;
}
if (request.contains(DEVICE_UNIQUEID)) {
request = request.replace(DEVICE_UNIQUEID, device.getUniqueid());
notDone = true;
}
if (request.contains(DEVICE_NAME)) {
request = request.replace(DEVICE_NAME, device.getName());
notDone = true;
}
if (request.contains(DEVICE_MAPID)) {
request = request.replace(DEVICE_MAPID, device.getMapId());
notDone = true;
}
if (request.contains(DEVICE_MAPTYPE)) {
request = request.replace(DEVICE_MAPTYPE, device.getMapType());
notDone = true;
}
if (request.contains(DEVICE_DEVICETYPE)) {
request = request.replace(DEVICE_DEVICETYPE, device.getDeviceType());
notDone = true;
}
if (request.contains(DEVICE_TARGETDEVICE)) {
request = request.replace(DEVICE_TARGETDEVICE, device.getTargetDevice());
notDone = true;
}
log.debug("Request <<" + request + ">>, not done: " + notDone);
}
return request;
}
}

View File

@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.HomeManager;
@@ -14,7 +15,6 @@ import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.HABridge.api.hue.StateChangeBody;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
import com.bwssystems.HABridge.dao.*;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.JsonTransformer;
@@ -33,12 +33,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;
/**
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
@@ -52,13 +48,15 @@ public class HueMulator {
private HomeManager homeManager;
private HueHome myHueHome;
private BridgeSettingsDescriptor bridgeSettings;
private BridgeSettings bridgeSettingMaster;
private Gson aGsonHandler;
private DeviceMapTypes validMapTypes;
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HomeManager aHomeManager) {
public HueMulator(BridgeSettings bridgeMaster, DeviceRepository aDeviceRepository, HomeManager aHomeManager) {
repository = aDeviceRepository;
validMapTypes = new DeviceMapTypes();
bridgeSettings = theBridgeSettings;
bridgeSettingMaster = bridgeMaster;
bridgeSettings = bridgeSettingMaster.getBridgeSettingsDescriptor();
homeManager= aHomeManager;
myHueHome = (HueHome) homeManager.findHome(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]);
aGsonHandler = new GsonBuilder().create();
@@ -393,7 +391,7 @@ public class HueMulator {
}
private String formatSuccessHueResponse(StateChangeBody stateChanges, String body, String lightId,
DeviceState deviceState, Integer targetBri, Integer targetBriInc) {
DeviceState deviceState, Integer targetBri, Integer targetBriInc, boolean offState) {
String responseString = "[";
boolean notFirstChange = false;
@@ -408,6 +406,8 @@ public class HueMulator {
deviceState.setOn(stateChanges.isOn());
if(!deviceState.isOn() && deviceState.getBri() == 254)
deviceState.setBri(0);
if(!deviceState.isOn() && offState)
deviceState.setBri(0);
}
notFirstChange = true;
}
@@ -556,50 +556,6 @@ public class HueMulator {
return responseString;
}
private String getNewUserID() {
UUID uid = UUID.randomUUID();
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
String newUser = "";
while (st.hasMoreTokens()) {
newUser = newUser + st.nextToken();
}
return newUser;
}
private HueError[] validateWhitelistUser(String aUser, boolean strict) {
String validUser = null;
boolean found = false;
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
&& !aUser.equalsIgnoreCase("")) {
if (bridgeSettings.getWhitelist() != null) {
Set<String> theUserIds = bridgeSettings.getWhitelist().keySet();
Iterator<String> userIterator = theUserIds.iterator();
while (userIterator.hasNext()) {
validUser = userIterator.next();
if (validUser.equals(aUser))
found = true;
}
}
if (!found && !strict) {
if (bridgeSettings.getWhitelist() == null) {
Map<String, WhitelistEntry> awhitelist = new HashMap<>();
bridgeSettings.setWhitelist(awhitelist);
}
bridgeSettings.getWhitelist().put(aUser, WhitelistEntry.createEntry("auto insert user"));
bridgeSettings.setSettingsChanged(true);
found = true;
}
}
if (!found) {
log.debug("Validate user, No User supplied");
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
}
return null;
}
private Boolean filterByRequester(String requesterFilterList, String anAddress) {
if (requesterFilterList == null || requesterFilterList.length() == 0)
return true;
@@ -620,9 +576,13 @@ public class HueMulator {
private String basicListHandler(String type, String userId, String requestIp) {
log.debug("hue " + type + " list requested: " + userId + " from " + requestIp);
HueError[] theErrors = validateWhitelistUser(userId, false);
if (theErrors != null)
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
if (theErrors != null) {
if(bridgeSettings.isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
return aGsonHandler.toJson(theErrors);
}
return "{}";
}
@@ -630,8 +590,11 @@ public class HueMulator {
log.debug("hue group list requested: " + userId + " from " + requestIp);
HueError[] theErrors = null;
Map<String, GroupResponse> groupResponseMap = null;
theErrors = validateWhitelistUser(userId, false);
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
if (theErrors == null) {
if(bridgeSettings.isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
groupResponseMap = new HashMap<String, GroupResponse>();
groupResponseMap.put("1", (GroupResponse) this.groupsIdHandler("1", userId, requestIp));
return groupResponseMap;
@@ -644,8 +607,11 @@ public class HueMulator {
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
HueError[] theErrors = null;
theErrors = validateWhitelistUser(userId, false);
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
if (theErrors == null) {
if(bridgeSettings.isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
if (groupId.equalsIgnoreCase("0")) {
GroupResponse theResponse = GroupResponse.createDefaultGroupResponse(repository.findActive());
return theResponse;
@@ -666,9 +632,13 @@ public class HueMulator {
if (bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
log.debug("hue lights list requested: " + userId + " from " + requestIp);
theErrors = validateWhitelistUser(userId, false);
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
if (theErrors == null) {
List<DeviceDescriptor> deviceList = repository.findActive();
if(bridgeSettings.isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
List<DeviceDescriptor> deviceList = repository.findAllByRequester(requestIp);
// List<DeviceDescriptor> deviceList = repository.findActive();
deviceResponseMap = new HashMap<String, DeviceResponse>();
for (DeviceDescriptor device : deviceList) {
DeviceResponse deviceResponse = null;
@@ -723,12 +693,20 @@ public class HueMulator {
newUser = aNewUser.getUsername();
aDeviceType = aNewUser.getDevicetype();
}
if (newUser == null)
newUser = getNewUserID();
validateWhitelistUser(newUser, false);
if (aDeviceType == null)
aDeviceType = "<not given>";
if (newUser == null) {
newUser = bridgeSettings.createWhitelistUser(aDeviceType);
}
else {
bridgeSettings.validateWhitelistUser(newUser, aDeviceType, false);
}
if(bridgeSettings.isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
if (bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: "
+ newUser + (followingSlash ? " /api/ called" : ""));
@@ -742,7 +720,7 @@ public class HueMulator {
if (bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress);
log.debug("hue api config requested: " + userId + " from " + ipAddress);
if (validateWhitelistUser(userId, true) != null) {
if (bridgeSettings.validateWhitelistUser(userId, null, true) != null) {
log.debug("hue api config requested, No User supplied, returning public config");
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
@@ -758,7 +736,7 @@ public class HueMulator {
@SuppressWarnings("unchecked")
private Object getFullState(String userId, String ipAddress) {
log.debug("hue api full state requested: " + userId + " from " + ipAddress);
HueError[] theErrors = validateWhitelistUser(userId, false);
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
if (theErrors != null)
return theErrors;
@@ -772,7 +750,7 @@ public class HueMulator {
private Object getLight(String userId, String lightId, String ipAddress) {
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + ipAddress);
HueError[] theErrors = validateWhitelistUser(userId, false);
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
if (theErrors != null)
return theErrors;
@@ -816,7 +794,7 @@ public class HueMulator {
Integer targetBri = null;
Integer targetBriInc = null;
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = validateWhitelistUser(userId, false);
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
if (theErrors != null)
return aGsonHandler.toJson(theErrors);
try {
@@ -848,7 +826,7 @@ public class HueMulator {
if (state == null)
state = DeviceState.createDeviceState();
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc);
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
device.setDeviceState(state);
return responseString;
@@ -866,7 +844,7 @@ public class HueMulator {
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
aMultiUtil.setSetCount(1);
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = validateWhitelistUser(userId, false);
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
if (theErrors != null)
return aGsonHandler.toJson(theErrors);
try {
@@ -944,8 +922,8 @@ public class HueMulator {
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
if(!filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.debug("filter for requester address not present in list: " + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
}
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
@@ -988,11 +966,11 @@ public class HueMulator {
if (responseString == null || !responseString.contains("[{\"error\":")) {
if(!device.isNoState()) {
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc);
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
device.setDeviceState(state);
} else {
DeviceState dummyState = DeviceState.createDeviceState();
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc);
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, device.isOffState());
}
}
return responseString;

View File

@@ -21,16 +21,22 @@ public class TimeDecode {
if (request == null) {
return null;
}
if (request.contains(TIME_FORMAT)) {
String timeFormatDescriptor = request.substring(request.indexOf(TIME_FORMAT) + TIME_FORMAT.length(),
request.indexOf(TIME_FORMAT_CLOSE));
try {
log.debug("Time eval is: " + timeFormatDescriptor);
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatDescriptor);
request = request.replace(TIME_FORMAT + timeFormatDescriptor + TIME_FORMAT_CLOSE, dateFormat.format(new Date()));
} catch (Exception e) {
log.warn("Could not format current time: " + timeFormatDescriptor, e);
boolean notDone = true;
while(notDone) {
notDone = false;
if (request.contains(TIME_FORMAT)) {
String timeFormatDescriptor = request.substring(request.indexOf(TIME_FORMAT) + TIME_FORMAT.length(),
request.indexOf(TIME_FORMAT_CLOSE));
try {
log.debug("Time eval is: " + timeFormatDescriptor);
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatDescriptor);
request = request.replace(TIME_FORMAT + timeFormatDescriptor + TIME_FORMAT_CLOSE, dateFormat.format(new Date()));
notDone = true;
} catch (Exception e) {
log.warn("Could not format current time: " + timeFormatDescriptor, e);
}
}
}
return request;

View File

@@ -161,7 +161,8 @@ public class DomoticzHome implements Home {
}
@Override
public void closeHome() {
httpClient.closeHandler();
if(httpClient != null)
httpClient.closeHandler();
}
}

View File

@@ -10,6 +10,7 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -31,6 +32,7 @@ public class CommandHome implements Home {
else
intermediate = anItem.getItem().getAsString();
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
intermediate = TimeDecode.replaceTimeValue(intermediate);
String anError = doExecRequest(intermediate, lightId);
if (anError != null) {

View File

@@ -17,6 +17,7 @@ import com.bwssystems.HABridge.IpList;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -161,6 +162,8 @@ public class HarmonyHome implements Home {
if (url.substring(0, 1).equalsIgnoreCase("{")) {
url = "[" + url + "]";
}
url = BrightnessDecode.calculateReplaceIntensityValue(url, intensity, targetBri, targetBriInc, false);
ButtonPress[] deviceButtons = aGsonHandler.fromJson(url, ButtonPress[].class);
Integer theCount = 1;
for(int z = 0; z < deviceButtons.length; z++) {

View File

@@ -4,6 +4,8 @@ import static java.lang.String.format;
import javax.inject.Inject;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,69 +20,98 @@ import net.whistlingfish.harmony.HarmonyClientModule;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.protocol.OAReplyProvider;
import java.net.URLEncoder;
public class HarmonyServer {
private static final String ACTIVIY_ID = "${activity.id}";
private static final String ACTIVIY_LABEL = "${activity.label}";
@Inject
private HarmonyClient harmonyClient;
private HarmonyHandler myHarmony;
private DevModeResponse devResponse;
private OAReplyProvider dummyProvider;
private NamedIP myNameAndIP;
private Boolean isDevMode;
private HTTPHandler httpClient;
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
public HarmonyServer(NamedIP theHarmonyAddress) {
super();
myHarmony = null;
dummyProvider = null;
myNameAndIP = theHarmonyAddress;
isDevMode = false;
}
public HarmonyServer(NamedIP theHarmonyAddress) {
super();
myHarmony = null;
dummyProvider = null;
myNameAndIP = theHarmonyAddress;
isDevMode = false;
httpClient = new HTTPHandler();
}
public static HarmonyServer setup(BridgeSettingsDescriptor bridgeSettings, Boolean harmonyDevMode, NamedIP theHarmonyAddress) throws Exception {
if(!bridgeSettings.isValidHarmony() && harmonyDevMode) {
return new HarmonyServer(theHarmonyAddress);
}
Injector injector = null;
if(!harmonyDevMode)
injector = Guice.createInjector(new HarmonyClientModule());
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
if(!harmonyDevMode)
injector.injectMembers(mainObject);
mainObject.execute(bridgeSettings, harmonyDevMode);
return mainObject;
}
private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
isDevMode = harmonyDevMode;
String modeString = "";
if(dummyProvider != null)
log.debug("something is very wrong as dummyProvider is not null...");
if(isDevMode)
modeString = " (development mode)";
else if(noopCalls)
modeString = " (no op calls to harmony)";
log.info("setup initiated " + modeString + "....");
if(isDevMode)
{
harmonyClient = null;
devResponse = new DevModeResponse();
public static HarmonyServer setup(
BridgeSettingsDescriptor bridgeSettings,
Boolean harmonyDevMode,
NamedIP theHarmonyAddress
) throws Exception {
if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
return new HarmonyServer(theHarmonyAddress);
}
else {
devResponse = null;
harmonyClient.addListener(new ActivityChangeListener() {
@Override
public void activityStarted(Activity activity) {
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
}
});
harmonyClient.connect(myNameAndIP.getIp());
Injector injector = null;
if (!harmonyDevMode) {
injector = Guice.createInjector(new HarmonyClientModule());
}
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
if (!harmonyDevMode) {
injector.injectMembers(mainObject);
}
mainObject.execute(bridgeSettings, harmonyDevMode);
return mainObject;
}
private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
isDevMode = harmonyDevMode;
String modeString = "";
if (dummyProvider != null) {
log.debug("something is very wrong as dummyProvider is not null...");
}
if (isDevMode) {
modeString = " (development mode)";
} else if (noopCalls) {
modeString = " (no op calls to harmony)";
}
log.info("setup initiated " + modeString + "....");
if (isDevMode) {
harmonyClient = null;
devResponse = new DevModeResponse();
} else {
devResponse = null;
harmonyClient.addListener(new ActivityChangeListener() {
@Override
public void activityStarted(Activity activity) {
String webhook = myNameAndIP.getWebhook();
if(webhook != null) {
try {
// Replacing variables
webhook = webhook.replace(ACTIVIY_ID, activity.getId().toString());
webhook = webhook.replace(ACTIVIY_LABEL, URLEncoder.encode(activity.getLabel(), "UTF-8"));
log.info(format("calling webhook: %s", webhook));
// Calling webhook
httpClient.doHttpRequest(webhook, HttpGet.METHOD_NAME, null, null, null);
} catch (Exception e) {
log.warn("could not call webhook: " + webhook, e);
}
}
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
}
});
harmonyClient.connect(myNameAndIP.getIp());
}
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
}
}
public HarmonyHandler getMyHarmony() {
return myHarmony;
}
public HarmonyHandler getMyHarmony() {
return myHarmony;
}
}

View File

@@ -41,7 +41,12 @@ public class HomeAssistant {
aUrl = "https";
else
aUrl = "http";
aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/" + aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
if(domain.equals("group"))
aUrl = aUrl + "homeassistant";
else
aUrl = aUrl + domain;
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
NameValue[] headers = null;
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
@@ -62,6 +67,7 @@ public class HomeAssistant {
aUrl = aUrl + "/turn_off";
aBody = aBody + "}";
}
log.debug("Calling HomeAssistant with url: " + aUrl);
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
log.debug("call Command return is: <" + theData + ">");
return true;

View File

@@ -5,16 +5,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
@@ -34,21 +24,11 @@ import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
// private HttpClient httpClient;
private CloseableHttpClient httpClient;
// private SSLContext sslcontext;
// private SSLConnectionSocketFactory sslsf;
private RequestConfig globalConfig;
public HTTPHandler() {
// httpClient = HttpClients.createDefault();
// Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
// Trust own CA and all self-signed certs
// sslcontext = SSLContexts.createDefault();
// Allow TLSv1 protocol only
// sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLS" }, null,
// SSLConnectionSocketFactory.getDefaultHostnameVerifier());
globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
}
@@ -101,40 +81,55 @@ public class HTTPHandler {
request.setHeader(headers[i].getName(), headers[i].getValue());
}
}
HttpResponse response;
try {
HttpResponse response;
// Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
// if (url.startsWith("xyzhttps"))
// response = httpclientSSL.execute(request);
// else
for(int retryCount = 0; retryCount < 2; retryCount++) {
response = httpClient.execute(request);
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute on URL responded: "
+ response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
if (response.getEntity() != null) {
try {
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
// content
// for
// data
EntityUtils.consume(response.getEntity()); // close out
// inputstream
// ignore
// content
} catch (Exception e) {
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
+ e.getMessage(), e);
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: "
+ response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
if (response.getEntity() != null) {
try {
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
// content
// for
// data
EntityUtils.consume(response.getEntity()); // close out
// inputstream
// ignore
// content
} catch (Exception e) {
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
+ e.getMessage(), e);
}
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
}
}
} else {
log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
try {
EntityUtils.consume(response.getEntity()); // close out
// inputstream
// ignore
// content
} catch (Exception e) {
//noop
retryCount = 2;
} else {
log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
try {
String someContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
// content
// for
// data
EntityUtils.consume(response.getEntity()); // close out
// inputstream
// ignore
// content
log.debug("Unsuccessfull response - The http response is <<<" + someContent + ">>>");
} catch (Exception e) {
//noop
}
if (response.getStatusLine().getStatusCode() == 504) {
log.warn("HTTP response code was 504, retrying...");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// noop
}
}
else
retryCount = 2;
}
}
} catch (IOException e) {

View File

@@ -11,6 +11,7 @@ import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.google.gson.Gson;
@@ -49,12 +50,14 @@ public class HTTPHome implements Home {
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
intensity, targetBri, targetBriInc, false);
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
anUrl = TimeDecode.replaceTimeValue(anUrl);
String aBody = null;
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
intensity, targetBri, targetBriInc, false);
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
aBody = TimeDecode.replaceTimeValue(aBody);
}
// make call

View File

@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.plugins.mqtt;
import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
@@ -47,7 +48,7 @@ public class MQTTHandler {
}
public void publishMessage(String topic, String content) {
MqttMessage message = new MqttMessage(content.getBytes());
MqttMessage message = new MqttMessage(StringEscapeUtils.unescapeJava(content).getBytes());
message.setQos(qos);
try {
myClient.publish(topic, message);

View File

@@ -14,6 +14,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.google.gson.Gson;
@@ -89,6 +90,7 @@ public class MQTTHome implements Home {
mqttObject =anItem.getItem().getAsString();
mqttObject = BrightnessDecode.calculateReplaceIntensityValue(mqttObject,
intensity, targetBri, targetBriInc, false);
mqttObject = DeviceDataDecode.replaceDeviceData(mqttObject, device);
mqttObject = TimeDecode.replaceTimeValue(mqttObject);
if (mqttObject.substring(0, 1).equalsIgnoreCase("{"))
mqttObject = "[" + mqttObject + "]";

View File

@@ -0,0 +1,67 @@
package com.bwssystems.HABridge.plugins.somfy;
public class SomfyDevice {
private String id;
private String room;
private String category;
private String somfyname;
private String name;
private String deviceUrl;
private String deviceType;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setRoom(String room) {
this.room = room;
}
public String getRoom() {
return room;
}
public void setCategory(String category) {
this.category = category;
}
public String getCategory() {
return category;
}
public void setSomfyname(String somfyname) {
this.somfyname = somfyname;
}
public String getSomfyname() {
return somfyname;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDeviceUrl(String deviceUrl) {
this.deviceUrl = deviceUrl;
}
public String getDeviceUrl() {
return deviceUrl;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getDeviceType() {
return deviceType;
}
}

View File

@@ -0,0 +1,118 @@
package com.bwssystems.HABridge.plugins.somfy;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
/**
* Support for Somfy Tahoma hub which allows control of IO Homecontrol devices such as Velux windows.
* Currently supports 'turn on' for open window, and 'turn off' for close.
*
* Known issues:
* //TODO - Fix bug on UI where bulk update seems to add the single device twice if 'update' is clicked (this is a general bug with Vera too I think)
* Enhancements:
* //TODO - support 'dimming' for partial window opening.
*
*/
public class SomfyHome implements Home {
private static final Logger log = LoggerFactory.getLogger(SomfyHome.class);
private Map<String, SomfyInfo> somfys;
private Boolean validSomfy;
public SomfyHome(BridgeSettingsDescriptor bridgeSettings) {
createHome(bridgeSettings);
}
public SomfyInfo getSomfyHandler(String somfyName) {
return somfys.get(somfyName);
}
public List<SomfyDevice> getDevices() {
log.debug("consolidating devices for somfy");
Iterator<String> keys = somfys.keySet().iterator();
ArrayList<SomfyDevice> deviceList = new ArrayList<>();
while(keys.hasNext()) {
String key = keys.next();
List<SomfyDevice> devices = somfys.get(key).getSomfyDevices();
deviceList.addAll(devices);
}
return deviceList;
}
@Override
public Object getItems(String type) {
if(validSomfy) {
if(type.equalsIgnoreCase(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]))
return getDevices();
}
return null;
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
String responseString = null;
if (!validSomfy) {
log.warn("Should not get here, no somfy hub available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no somfy hub available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} else {
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex])) {
log.debug("executing HUE api request to change activity to Somfy: " + anItem.getItem().toString());
String jsonToPost = anItem.getItem().toString();
SomfyInfo somfyHandler = getSomfyHandler(device.getTargetDevice());
if(somfyHandler == null) {
log.warn("Should not get here, no Somfy configured");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no somfy configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} else {
try {
somfyHandler.execApply(jsonToPost);
} catch (Exception e) {
log.warn("Error posting request to Somfy");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Error posting request to SomfyTahoma\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
}
}
}
return responseString;
}
@Override
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
validSomfy = bridgeSettings.isValidSomfy();
log.info("Somfy Home created." + (validSomfy ? "" : " No Somfys configured."));
if(validSomfy) {
somfys = new HashMap<>();
Iterator<NamedIP> theList = bridgeSettings.getSomfyAddress().getDevices().iterator();
while (theList.hasNext()) {
NamedIP aSomfy = theList.next();
somfys.put(aSomfy.getName(), new SomfyInfo(aSomfy, aSomfy.getName()));
}
}
return this;
}
@Override
public void closeHome() {
somfys = null;
}
}

View File

@@ -0,0 +1,116 @@
package com.bwssystems.HABridge.plugins.somfy;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup.Device;
import com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup.GetSetup;
import com.google.gson.Gson;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
public class SomfyInfo {
private static final Logger log = LoggerFactory.getLogger(SomfyInfo.class);
private final String somfyName;
private final NamedIP namedIP;
private HTTPHandler httpClient;
private static final String CONNECT_HOST = "https://www.tahomalink.com/";
private static final String BASE_URL = CONNECT_HOST + "enduser-mobile-web/externalAPI/";
private static final String BASE_URL_ENDUSER = CONNECT_HOST + "enduser-mobile-web/enduserAPI/";
public SomfyInfo(NamedIP namedIP, String somfyName) {
super();
this.somfyName = somfyName;
this.namedIP = namedIP;
}
private void initHttpClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
if(httpClient==null) {
httpClient = new HTTPHandler();
}
}
public List<SomfyDevice> getSomfyDevices() {
List<SomfyDevice> somfyDevices = new ArrayList<>();
try {
login(namedIP.getUsername(), namedIP.getPassword());
GetSetup setupData = getSetup();
for(Device device : setupData.getSetup().getDevices()) {
somfyDevices.add(mapDeviceToSomfyDevice(device));
}
} catch (Exception e) {
log.error("Could not get Somfy devices", e);
}
return somfyDevices;
}
public void login(String username, String password) throws Exception {
initHttpClient();
NameValue[] httpHeader = getHttpHeaders();
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("userId", username));
nvps.add(new BasicNameValuePair("userPassword", password));
log.debug("Making SOMFY http login call");
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nvps);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
urlEncodedFormEntity.writeTo(bos);
String body = bos.toString();
String response = httpClient.doHttpRequest(BASE_URL + "json/login",HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
log.debug(response);
}
private NameValue[] getHttpHeaders() {
NameValue userAgentHeader = new NameValue();
userAgentHeader.setName("User-Agent");
userAgentHeader.setValue("mine");
return new NameValue[]{userAgentHeader};
}
public GetSetup getSetup() throws IOException {
NameValue[] httpHeader = getHttpHeaders();
log.info("Making SOMFY http setup call");
String response = httpClient.doHttpRequest(BASE_URL + "json/getSetup", HttpGet.METHOD_NAME, "", "", httpHeader );
log.debug(response);
GetSetup setupData = new Gson().fromJson(response, GetSetup.class);
return setupData;
}
public void execApply(String jsonToPost) throws Exception {
login(namedIP.getUsername(), namedIP.getPassword());
log.info("Making SOMFY http exec call");
String response = httpClient.doHttpRequest(BASE_URL_ENDUSER + "exec/apply", HttpPost.METHOD_NAME, "application/json;charset=UTF-8", jsonToPost, getHttpHeaders());
log.info(response);
}
protected SomfyDevice mapDeviceToSomfyDevice(Device device) {
SomfyDevice somfyDevice = new SomfyDevice();
somfyDevice.setId(device.getOid());
somfyDevice.setCategory(device.getUiClass());
somfyDevice.setRoom("");
somfyDevice.setSomfyname(somfyName);
somfyDevice.setName(device.getLabel());
somfyDevice.setDeviceUrl(device.getDeviceURL());
somfyDevice.setDeviceType(device.getWidget());
return somfyDevice;
}
}

View File

@@ -0,0 +1,69 @@
package com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Device {
@SerializedName("label")
@Expose
private String label;
@SerializedName("deviceURL")
@Expose
private String deviceURL;
@SerializedName("widget")
@Expose
private String widget;
@SerializedName("oid")
@Expose
private String oid;
@SerializedName("uiClass")
@Expose
private String uiClass;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDeviceURL() {
return deviceURL;
}
public void setDeviceURL(String deviceURL) {
this.deviceURL = deviceURL;
}
public String getWidget() {
return widget;
}
public void setWidget(String widget) {
this.widget = widget;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public String getUiClass() {
return uiClass;
}
public void setUiClass(String uiClass) {
this.uiClass = uiClass;
}
}

View File

@@ -0,0 +1,21 @@
package com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class GetSetup {
@SerializedName("setup")
@Expose
private Setup setup;
public Setup getSetup() {
return setup;
}
public void setSetup(Setup setup) {
this.setup = setup;
}
}

View File

@@ -0,0 +1,35 @@
package com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Setup {
@SerializedName("id")
@Expose
private String id;
@SerializedName("devices")
@Expose
private List<Device> devices = null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Device> getDevices() {
return devices;
}
public void setDevices(List<Device> devices) {
this.devices = devices;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,17 @@
package com.bwssystems.HABridge.plugins.tcp;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,12 +20,14 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
public class TCPHome implements Home {
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
private byte[] sendData;
private Map<String, Socket> theSockets;
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
@@ -31,6 +38,7 @@ public class TCPHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Socket dataSendSocket = null;
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
String theUrl = anItem.getItem().getAsString();
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("tcp://")) {
@@ -40,34 +48,50 @@ public class TCPHome implements Home {
String hostAddr = null;
String port = null;
InetAddress IPAddress = null;
if (hostPortion.contains(":")) {
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
port = hostPortion.substring(intermediate.indexOf(':') + 1);
} else
hostAddr = hostPortion;
try {
IPAddress = InetAddress.getByName(hostAddr);
} catch (UnknownHostException e) {
// noop
dataSendSocket = theSockets.get(hostPortion);
if(dataSendSocket == null) {
if (hostPortion.contains(":")) {
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
port = hostPortion.substring(intermediate.indexOf(':') + 1);
} else
hostAddr = hostPortion;
try {
IPAddress = InetAddress.getByName(hostAddr);
} catch (UnknownHostException e) {
// noop
}
try {
dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
theSockets.put(hostPortion, dataSendSocket);
} catch (Exception e) {
// noop
}
}
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
if (theUrlBody.startsWith("0x")) {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();
}
try {
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
outToClient.write(sendData);
outToClient.flush();
dataSendSocket.close();
} catch (Exception e) {
// noop
log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
try {
dataSendSocket.close();
} catch (IOException e1) {
// noop
}
theSockets.remove(hostPortion);
}
} else
log.warn("Tcp Call to be presented as tcp://<ip_address>:<port>/payload, format of request unknown: " + theUrl);
@@ -77,6 +101,7 @@ public class TCPHome implements Home {
@Override
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
log.info("TCP Home created.");
theSockets = new HashMap<String, Socket>();
return this;
}
@@ -88,8 +113,18 @@ public class TCPHome implements Home {
@Override
public void closeHome() {
// noop
log.debug("Shutting down TCP sockets.");
if(theSockets != null && !theSockets.isEmpty()) {
Iterator<String> keys = theSockets.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
try {
theSockets.get(key).close();
} catch (IOException e) {
// noop
}
}
}
}
}

View File

@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,6 +15,7 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.bwssystems.HABridge.util.UDPDatagramSender;
@@ -56,9 +58,12 @@ public class UDPHome implements Home {
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
if (theUrlBody.startsWith("0x")) {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();
}
try {

View File

@@ -1,5 +1,5 @@
.scrollableContainer {
max-height: 436px; /* sets max-height value for all standards-compliant browsers */
height: 310px;
position: relative;
padding-top: 35px;
overflow: hidden;
@@ -28,17 +28,17 @@
}
.scrollArea {
_height: expression( this.scrollHeight > 599 ? "600px" : "auto" ); /* sets max-height for IE6 */
max-height: 400px; /* sets max-height value for all standards-compliant browsers */
height: 100%;
overflow-x: auto;
overflow-y: auto;
border: 1px solid #d5d5d5;
/* the implementation of this is still quite buggy; specifically, it doesn't like the
absolutely positioned headers within
-webkit-overflow-scrolling: touch; */
-webkit-overflow-scrolling: auto;
}
.scrollArea table {
overflow-x: hidden;
overflow-x: auto;
overflow-y: auto;
margin-bottom: 0;
width: 100%;
@@ -48,7 +48,7 @@
.scrollArea table th {
padding: 0 !important;
border: none !important;
min-width: 60px;
min-width: 40px;
}
.scrollArea table .th-inner {
overflow: hidden;

File diff suppressed because one or more lines are too long

View File

@@ -44,6 +44,11 @@ app.config (function ($locationProvider, $routeProvider) {
controller: 'HassController'
}).when ('/domoticzdevices', {
templateUrl: 'views/domoticzdevice.html',
controller: 'DomoticzController'
}).when('/somfydevices', {
templateUrl: 'views/somfydevice.html',
controller: 'SomfyController'
}).otherwise ({
controller: 'DomoticzController'
}).when ('/lifxdevices', {
templateUrl: 'views/lifxdevice.html',
@@ -57,6 +62,7 @@ app.config (function ($locationProvider, $routeProvider) {
app.run( function (bridgeService) {
bridgeService.loadBridgeSettings();
bridgeService.getHABridgeVersion();
bridgeService.getTestUser();
bridgeService.viewMapTypes();
});
@@ -74,7 +80,7 @@ String.prototype.replaceAll = function (search, 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: [], mapTypes: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, showDomoticz: false, showLifx: false, habridgeversion: ""};
this.state = {base: "./api/devices", bridgelocation: ".", systemsbase: "./system", huebase: "./api", configs: [], backups: [], devices: [], device: {}, mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], mapTypes: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: "", viewDevId: "", queueDevId: ""};
this.displayWarn = function(errorTitle, error) {
var toastContent = errorTitle;
@@ -146,7 +152,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
this.clearDevice = function () {
self.state.device = {};
self.state.olddevicename = "";
self.state.olddevicename = null;
};
this.getHABridgeVersion = function () {
@@ -160,6 +166,17 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
);
};
this.getTestUser = function () {
return $http.get(this.state.systemsbase + "/habridge/testuser").then(
function (response) {
self.state.testuser = response.data.user;
},
function (error) {
self.displayWarn("Cannot get testuser: ", error);
}
);
};
this.aContainsB = function (a, b) {
return a.indexOf(b) >= 0;
}
@@ -260,6 +277,11 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
return;
}
this.updateShowSomfy = function () {
this.state.showSomfy = self.state.settings.somfyconfigured;
return;
}
this.updateShowLifx = function () {
this.state.showLifx = self.state.settings.lifxconfigured;
return;
@@ -277,6 +299,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
self.updateShowMqtt();
self.updateShowHass();
self.updateShowDomoticz();
self.updateShowSomfy();
self.updateShowLifx();
},
function (error) {
@@ -459,6 +482,20 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
);
};
this.viewSomfyDevices = function () {
if(!this.state.showSomfy)
return;
return $http.get(this.state.base + "/somfy/devices").then(
function (response) {
self.state.somfydevices = response.data;
},
function (error) {
self.displayWarn("Get Somfy Devices Error: ", error);
}
);
};
this.viewLifxDevices = function () {
if (!this.state.showLifx)
return;
@@ -513,6 +550,20 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
type = self.getMapType(s.type[0])
s.type = type[0]
}
if(s.delay === "" || s.delay === null)
delete s.delay;
if(s.count === "" || s.count === null)
delete s.count;
if(s.filterIPs === "" || s.filterIPs === null)
delete s.filterIPs;
if(s.httpVerb === "" || s.httpVerb === null)
delete s.httpVerb;
if(s.httpBody === "" || s.httpBody === null)
delete s.httpBody;
if(s.httpHeaders === "" || s.httpHeaders === null)
delete s.httpHeaders;
if(s.contentType === "" || s.contentType === null)
delete s.contentType;
}
}
return theDevices
@@ -774,7 +825,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
this.testUrl = function (device, type, value) {
var msgDescription = "unknown";
var testUrl = this.state.huebase + "/test/lights/" + device.id + "/state";
var testUrl = this.state.huebase + "/" + this.state.testuser + "/lights/" + device.id + "/state";
var testBody = "{\"on\":";
if (type === "off") {
testBody = testBody + "false";
@@ -1024,6 +1075,25 @@ app.controller ('SystemController', function ($scope, $location, $http, $window,
}
}
};
$scope.addSomfytoSettings = function (newsomfyname, newsomfyip, newsomfyusername, newsomfypassword) {
if($scope.bridge.settings.somfyaddress == null) {
$scope.bridge.settings.somfyaddress = { devices: [] };
}
var newSomfy = {name: newsomfyname, ip: newsomfyip, username: newsomfyusername, password: newsomfypassword }
$scope.bridge.settings.somfyaddress.devices.push(newSomfy);
$scope.newsomfyname = null;
$scope.newsomfyip = null;
$scope.newsomfyusername = null;
$scope.newsomfypassword = null;
};
$scope.removeSomfytoSettings = function (somfyname, somfyip) {
for(var i = $scope.bridge.settings.somfyaddress.devices.length - 1; i >= 0; i--) {
if($scope.bridge.settings.somfyaddress.devices[i].name === somfyname && $scope.bridge.settings.somfyaddress.devices[i].ip === somfyip) {
$scope.bridge.settings.somfyaddress.devices.splice(i, 1);
}
}
};
$scope.bridgeReinit = function () {
bridgeService.reinit();
};
@@ -1096,6 +1166,26 @@ app.controller('LogsController', function ($scope, $location, $http, $window, br
};
});
app.directive('postrenderAction', postrenderAction);
/* @ngInject */
function postrenderAction($timeout) {
// ### Directive Interface
// Defines base properties for the directive.
var directive = {
restrict: 'A',
priority: 101,
link: link
};
return directive;
// ### Link Function
// Provides functionality for the directive during the DOM building/data binding stage.
function link(scope, element, attrs) {
$timeout(function() {
scope.$evalAsync(attrs.postrenderAction);
}, 0);
}
}
app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, ngDialog) {
bridgeService.viewDevices();
@@ -1161,7 +1251,16 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
else
$scope.imgBkUrl = "glyphicon glyphicon-plus";
};
});
$scope.goToRow = function() {
if (bridgeService.state.queueDevId !== null && bridgeService.state.queueDevId !== "") {
bridgeService.state.viewDevId = bridgeService.state.queueDevId;
$scope.$broadcast("rowSelected", bridgeService.state.viewDevId);
console.log("Go to Row selected Id <<" + bridgeService.state.viewDevId + ">>")
bridgeService.state.queueDevId = null;
}
};
});
app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
$scope.slider = {
@@ -2400,6 +2499,134 @@ app.controller('LifxController', function ($scope, $location, $http, bridgeServi
};
});
app.controller('SomfyController', function ($scope, $location, $http, bridgeService, ngDialog) {
$scope.bridge = bridgeService.state;
$scope.device = bridgeService.state.device;
$scope.device_dim_control = "";
$scope.bulk = { devices: [] };
$scope.selectAll = false;
$scope.somfy = {base: "http://", port: "3480", id: ""};
bridgeService.viewDevices(); //Needs this if you're navigating to the 'somfy' page directly without going to the home page first..
bridgeService.viewSomfyDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.comparatorUniqueId = bridgeService.compareUniqueId;
$scope.clearDevice = function () {
bridgeService.clearDevice();
$scope.device = bridgeService.state.device;
};
$scope.buildDeviceUrls = function (somfydevice, dim_control, buildonly) {
//TODO - support partial window opening - add back 'dim_control' second param in here, and in somfydevice.html
dimpayload = "";
onpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"open\",\"parameters\":[]}]}]}";
offpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"close\",\"parameters\":[]}]}]}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, somfydevice.id, somfydevice.name, somfydevice.somfyname, "switch", "somfyDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
}
};
$scope.bulkAddDevices = function(dim_control) {
var devicesList = [];
$scope.clearDevice();
for(var i = 0; i < $scope.bulk.devices.length; i++) {
for(var x = 0; x < bridgeService.state.somfydevices.length; x++) {
if(bridgeService.state.somfydevices[x].id === $scope.bulk.devices[i]) {
$scope.buildDeviceUrls(bridgeService.state.somfydevices[x],dim_control, true);
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
};
$scope.clearDevice();
}
}
}
bridgeService.bulkAddDevice(devicesList).then(
function () {
$scope.clearDevice();
bridgeService.viewDevices();
bridgeService.viewSomfyDevices();
},
function (error) {
bridgeService.displayWarn("Error adding Somfy 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.somfydevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.somfydevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.somfydevices[x].id, bridgeService.state.somfydevices[x].somfyname, "somfyDevice"))
$scope.bulk.devices.push(bridgeService.state.somfydevices[x].id);
}
}
};
$scope.toggleButtons = function () {
$scope.buttonsVisible = !$scope.buttonsVisible;
if($scope.buttonsVisible)
$scope.imgButtonsUrl = "glyphicon glyphicon-minus";
else
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
};
$scope.deleteDevice = function (device) {
$scope.bridge.device = device;
ngDialog.open({
template: 'deleteDialog',
controller: 'DeleteDialogCtrl',
className: 'ngdialog-theme-default'
});
};
$scope.editDevice = function (device) {
bridgeService.editDevice(device);
$location.path('/editdevice');
};
});
app.controller('EditController', function ($scope, $location, $http, bridgeService) {
bridgeService.viewMapTypes();
$scope.bridge = bridgeService.state;
@@ -2447,20 +2674,28 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
bridgeService.displayWarn("Error adding device. Name has not been changed from original.", null);
return;
}
if (copy)
if (copy) {
$scope.device.id = null;
$scope.device.uniqueid = null;
if($scope.bridge.olddevicename !== null && $scope.bridge.olddevicename !== "")
$scope.device.mapId = $scope.device.mapId + "-copy";
}
if($scope.mapTypeSelected !== undefined && $scope.mapTypeSelected !== null)
$scope.device.mapType = $scope.mapTypeSelected[0];
else
$scope.device.mapType = null;
if ($scope.onDevices !== null)
$scope.device.onUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices));
if ($scope.dimDevices !== null)
$scope.device.dimUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices));
if ($scope.offDevices !== null)
$scope.device.offUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices));
bridgeService.addDevice($scope.device).then(
function () {
bridgeService.state.queueDevId = $scope.device.id;
console.log("Device updated for Q Id <<" + bridgeService.state.queueDevId + ">>")
$scope.clearDevice();
$location.path('/');
},
@@ -2478,7 +2713,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
if ($scope.onDevices === null)
$scope.onDevices = [];
$scope.onDevices.push(newitem);
$scope.newOnItem = [];
$scope.newOnItem = {};
};
$scope.removeItemOn = function (anItem) {
for(var i = $scope.onDevices.length - 1; i >= 0; i--) {
@@ -2495,7 +2730,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
if ($scope.dimDevices === null)
$scope.dimDevices = [];
$scope.dimDevices.push(newitem);
$scope.newDimItem = [];
$scope.newDimItem = {};
};
$scope.removeItemDim = function (anItem) {
for(var i = $scope.dimDevices.length - 1; i >= 0; i--) {
@@ -2512,7 +2747,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
if ($scope.offDevices === null)
$scope.offDevices = [];
$scope.offDevices.push(newitem);
$scope.newOffItem = [];
$scope.newOffItem = {};
};
$scope.removeItemOff = function (anItem) {
for(var i = $scope.offDevices.length - 1; i >= 0; i--) {
@@ -2685,6 +2920,23 @@ app.filter('configuredLifxItems', function (bridgeService) {
}
});
app.filter('configuredSomfyDevices', function (bridgeService) {
return function(input) {
var out = [];
if(input === undefined || input === null || input.length === undefined)
return out;
for (var i = 0; i < input.length; i++) {
if(bridgeService.deviceContainsType(input[i], "somfyDevice")){
out.push(input[i]);
}
}
return out;
}
});
app.controller('VersionController', function ($scope, bridgeService) {
$scope.bridge = bridgeService.state;
});
});

View File

@@ -1,145 +1,148 @@
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">Current devices ({{bridge.devices.length}})</h1>
</div>
<div class="panel-body">
<p>
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
</p>
<scrollable-table watch="bridge.devices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">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="inactive">Inactive</th>
<th sortable-header col="noState">No State</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.inactive}}</td>
<td>{{device.noState}}</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"
ng-click="testUrl(device, 'dim')">Test Dim</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'off')">Test OFF</button>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit/Copy</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</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"></span></a>
</h1>
</div>
<div ng-if="visibleBk" 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>
</div>
</div>
<script type="text/ng-template" id="valueDialog">
<div class="ngdialog-message">
<h2>Select value</h2>
<p>
<input type="radio" ng-model="valueType" value="percentage" ng-change="changeScale()"> Percentage
<input type="radio" ng-model="valueType" value="raw" ng-change="changeScale()"> Raw
</p>
<p>
<rzslider rz-slider-model="slider.value" rz-slider-options="slider.options"></rzslider>
</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
</div>
</script>
<script type="text/ng-template" id="deleteDialog">
<div class="ngdialog-message">
<h2>Device to Delete?</h2>
<p>{{device.name}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
</div>
</script>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div postrender-action="goToRow()">
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">Current devices ({{bridge.devices.length}})</h1>
</div>
<div class="panel-body">
<p>
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
</p>
<scrollable-table watch="bridge.devices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">ID</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="description">Description</th>
<th sortable-header col="deviceType">Type</th>
<th sortable-header col="targetDevice">Target</th>
<th sortable-header col="inactive">Inactive</th>
<th sortable-header col="noState">No State</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices" row-id="{{device.id}}" ng-class="{info: bridge.viewDevId == device.id}" >
<td>{{$index+1}}</td>
<td>{{device.id}}</td>
<td>{{device.name}}</td>
<td class="cr">{{device.description}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.inactive}}</td>
<td>{{device.noState}}</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"
ng-click="testUrl(device, 'dim')">Test Dim</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'off')">Test OFF</button>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit/Copy</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
</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"></span></a>
</h1>
</div>
<div ng-if="visibleBk" 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>
</div>
</div>
<script type="text/ng-template" id="valueDialog">
<div class="ngdialog-message">
<h2>Select value</h2>
<p>
<input type="radio" ng-model="valueType" value="percentage" ng-change="changeScale()"> Percentage
<input type="radio" ng-model="valueType" value="raw" ng-change="changeScale()"> Raw
</p>
<p>
<rzslider rz-slider-model="slider.value" rz-slider-options="slider.options"></rzslider>
</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
</div>
</script>
<script type="text/ng-template" id="deleteDialog">
<div class="ngdialog-message">
<h2>Device to Delete?</h2>
<p>{{device.name}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
</div>
</script>

View File

@@ -18,6 +18,7 @@
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li role="presentation" class="active"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -43,6 +44,7 @@
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>

View File

@@ -20,6 +20,7 @@
<li ng-if="bridge.showHass" role="presentation"><a
href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation" class="active"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -33,7 +34,7 @@
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 class="text-muted">This area allows you to create any http or
<p class="text-muted">This area allows you to create any http, tcp 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. For Execution of a
@@ -41,7 +42,7 @@
can use Json notation of array with [{&quot;item&quot;:&quot;the
payload&quot;},{&quot;item&quot;:&quot;another payload&quot;}] to
execute multiple entries. Adding the value replacements
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
(${intensity.byte},${intensity.percent},${intensity.decimal_percent},${intensity.math(X*1)}) will
also work. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command.</p>
<p class="text-muted">When copying, update the name and select the "Add Bridge
@@ -65,17 +66,40 @@
ng-model="device.name" placeholder="Device Name"></td>
</tr>
<tr>
<td>Inactive</td>
<td><label>Description</label></td>
<td><input type="text" class="form-control" id="device-description"
ng-model="device.description" placeholder="Device Description"></td>
</tr>
<tr>
<td><label>Comments</label></td>
<td><input type="text" class="form-control" id="device-comments"
ng-model="device.comments" placeholder="Device Comments"></td>
</tr>
<tr>
<td><label>Inactive</label></td>
<td><input type="checkbox"
ng-model="device.inactive" ng-true-value=true
ng-false-value=false> {{device.inactive}}</td>
</tr>
<tr>
<td>No State (Do not update state for device)</td>
<td><label>No State (Do not update state for device)</label></td>
<td><input type="checkbox"
ng-model="device.noState" ng-true-value=true
ng-false-value=false> {{device.noState}}</td>
</tr>
<tr>
<td><label>Off State Resets Bri</label></td>
<td><input type="checkbox"
ng-model="device.offState" ng-true-value=true
ng-false-value=false> {{device.offState}}</td>
</tr>
<tr>
<td><label>Filter Address (comma separated list)</label></td>
<td><input type="text" class="form-control" id="device-requester-addr"
ng-model="device.requesterAddress" placeholder="Only use if you want to restrict this device to a specific caller(s)"></td>
</tr>
<tr>
<td><label>Target</label></td>

View File

@@ -1,177 +1,179 @@
<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.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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</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 build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">
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 class="text-muted">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>
<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>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="haldevice in bridge.haldevices">
<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, false)">Build Item</button>
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
ng-click="buildHALHomeUrls(haldevice, false)">Build Home/Away</button>
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
ng-click="buildButtonUrls(haldevice, button_on, button_off, false)">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, false)">Heat</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALCoolUrls(haldevice, false)">Cool</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALAutoUrls(haldevice, false)">Auto</button>
</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="buildHALOffUrls(haldevice, false)">Off</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALFanUrls(haldevice, false)">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>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table 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>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHalItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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.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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</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 build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">
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.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p class="text-muted">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>
<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>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="haldevice in bridge.haldevices">
<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, false)">Build Item</button>
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
ng-click="buildHALHomeUrls(haldevice, false)">Build Home/Away</button>
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
ng-click="buildButtonUrls(haldevice, button_on, button_off, false)">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, false)">Heat</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALCoolUrls(haldevice, false)">Cool</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALAutoUrls(haldevice, false)">Auto</button>
</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="buildHALOffUrls(haldevice, false)">Off</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALFanUrls(haldevice, false)">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>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table 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>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHalItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -1,112 +1,113 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li role="presentation" class="active"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li role="presentation"><a href="#!/harmonydevices">Harmony
Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li 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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Harmony Activity List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Harmony Activity, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen.
Then you can modify the name to anything you want that
will be the keyword for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="harmonyactivity in bridge.harmonyactivities">
<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)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<div class="panel panel-default">
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Hub</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHarmonyActivities">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Harmony Activity List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Harmony Activity, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen.
Then you can modify the name to anything you want that
will be the keyword for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="harmonyactivity in bridge.harmonyactivities">
<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)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<div class="panel panel-default">
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Hub</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHarmonyActivities">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -1,131 +1,132 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li 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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Harmony Device List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Harmony Device and Buttons, use the
build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then you can modify the name
to anything you want that will be the keyword for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>On Button</th>
<th>Off Button</th>
<th>Build 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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Hub</th>
<th>Harmony Device-Button On-Button Off</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHarmonyButtons | orderBy:predicate:reverse">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Harmony Device List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Harmony Device and Buttons, use the
build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then you can modify the name
to anything you want that will be the keyword for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>On Button</th>
<th>Off Button</th>
<th>Build 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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Hub</th>
<th>Harmony Device-Button On-Button Off</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHarmonyButtons | orderBy:predicate:reverse">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -18,6 +18,7 @@
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li role="presentation" class="active"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -43,6 +44,7 @@
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>

View File

@@ -1,127 +1,128 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li role="presentation" class="active"><a href="#!/huedevices">Hue
Devices</a></li>
<li 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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Hue Device List
({{bridge.huedevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Hue Device, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">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, off and dim 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"><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>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="huedevice in bridge.huedevices">
<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, false)">Build Item</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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">hue</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHueItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Hue Device List
({{bridge.huedevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Hue Device, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">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, off and dim 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"><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>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="huedevice in bridge.huedevices">
<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, false)">Build Item</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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">hue</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredHueItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -12,6 +12,7 @@
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li role="presentation" class="active"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -1,89 +1,90 @@
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<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>
<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="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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<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>
<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="panel-body">
<p>
<button class="btn btn-primary" type="submit"
ng-click="updateLoggers()">Update Log Levels</button>
Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll"
ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false>
{{bridge.logShowAll}}
</p>
<scrollable-table watch="bridge.loggerInfo">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th sortable-header col="logLevel">Log Level</th>
<th sortable-header col="loggerName">Component</th>
<th>New Log Level</th>
</tr>
</thead>
<tr ng-repeat="logInfo in bridge.loggerInfo">
<td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td>
<td>{{logInfo.loggerName}}</td>
<td><select name="new-log-level" id="new-log-level"
ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel">
<option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option>
</select></td>
</tr>
</table>
</scrollable-table>
</div>
</div>

View File

@@ -1,117 +1,118 @@
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</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 action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen.
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 the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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>
<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>Build 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>
</div>
</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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table 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="targetDevice">ClientID</th>
<th>Map 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>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</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 action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen.
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 the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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>
<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>Build 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>
</div>
</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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table 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="targetDevice">ClientID</th>
<th>Map 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>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -1,133 +1,134 @@
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Nest Items List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Nest Item, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="nestitem in bridge.nestitems | 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>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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">Location</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices | configuredNestItems | orderBy:predicate:reverse">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Nest Items List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Nest Item, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="nestitem in bridge.nestitems | 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>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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">Location</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices | configuredNestItems | orderBy:predicate:reverse">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -0,0 +1,143 @@
<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"><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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation" class="active"><a href="#!/somfydevices">Somfy Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Somfy Device List
({{bridge.somfydevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Somfy Device, use the build action buttons
to generate the item addition information into the ha-bridge device
and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Somfy Devices' list below will show
what is already setup for your Somfy.</p>
<!-- TODO - dim support for partial window opening.. --<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, then click
bulk add below. Your items will be added with the name of the device from the Somfy Tahoma.</p>
</div>
<scrollable-table watch="bridge.somfydevices">
<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" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="somfyname">Somfy</th>
<th>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="somfydevice in bridge.somfydevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{somfydevice.id}}"
ng-checked="bulk.devices.indexOf(somfydevice.id) > -1"
ng-click="toggleSelection(somfydevice.id)">
{{somfydevice.name}}</td>
<td>{{somfydevice.id}}</td>
<td>{{somfydevice.category}}</td>
<td>{{somfydevice.room}}</td>
<td>{{somfydevice.somfyname}}</td>
<td>
<!--TODO - taken device_dim_control out of here since not yet used-->
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(somfydevice)">Build Item</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>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured Somfy Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
</h2>
</div>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.devices">
<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="targetDevice">Somfy</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices |configuredSomfyDevices">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -19,6 +19,7 @@
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -141,25 +142,30 @@
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>IP</th>
<th>Webhook</th>
<th>Manage</th>
</tr>
</thead>
<tr ng-repeat="harmony in bridge.settings.harmonyaddress.devices">
<td>{{harmony.name}}</td>
<td>{{harmony.ip}}</td>
<td>{{harmony.ip}}</td>
<td>{{harmony.webhook}}</td>
<td><button class="btn btn-danger" type="submit"
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td>
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip, harmony.webhook)">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><input id="bridge-settings-next-harmony-ip"
class="form-control" type="text" ng-model="newharmonyip"
placeholder="192.168.1.3"></td>
<td><input id="bridge-settings-next-harmony-webhook"
class="form-control" type="text" ng-model="newharmonywebhook"
placeholder="http://hook?a=${activity.label}"></td>
<td><button class="btn btn-success" type="submit"
ng-click="addHarmonytoSettings(newharmonyname, newharmonyip)">Add</button></td>
ng-click="addHarmonytoSettings(newharmonyname, newharmonyip, newharmonywebhook)">Add</button></td>
</tr>
</table></td>
</tr>
@@ -358,6 +364,46 @@
</tr>
</table></td>
</tr>
<tr>
<td>Somfy Names and IP Addresses</td>
<td><table
class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>IP/hostname</th>
<th>Username</th>
<th>Password </th>
<th>Manage</th>
</tr>
</thead>
<tr ng-repeat="somfy in bridge.settings.somfyaddress.devices">
<td>{{somfy.name}}</td>
<td>{{somfy.ip}}</td>
<td>{{somfy.username}}</td>
<td ng-if="somfy.password">*******</td>
<td ng-if="!somfy.password"> </td>
<td><button class="btn btn-danger" type="submit"
ng-click="removeSomfytoSettings(somfy.name, somfy.ip)">Del</button></td>
</tr>
<tr>
<td><input id="bridge-settings-next-somfy-name"
class="form-control" type="text" ng-model="newsomfyname"
placeholder="A Somfy"></td>
<td><input id="bridge-settings-next-somfy-ip"
class="form-control" type="text" ng-model="newsomfyip"
placeholder="https://www.tahomalink.com"></td>
<td><input id="bridge-settings-next-somfy-username"
class="form-control" type="text" ng-model="newsomfyusername"
placeholder="Somfy username"></td>
<td><input id="bridge-settings-next-somfy-password"
class="form-control" type="password" ng-model="newsomfypassword"
placeholder="Somfy password"></td>
<td><button class="btn btn-success" type="submit"
ng-click="addSomfytoSettings(newsomfyname, newsomfyip, newsomfyusername, newsomfypassword)">Add</button></td>
</tr>
</table></td>
</tr>
<tr>
<td>Nest Username</td>
<td><input id="bridge-settings-nestuser" class="form-control"

View File

@@ -1,142 +1,144 @@
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Vera Device List
({{bridge.veradevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Vera Device, use the build action buttons
to generate the item addition information into the ha-bridge device
and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">
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 class="text-muted">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"><span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>
<th>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="veradevice in bridge.veradevices">
<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, false)">Build Item</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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.devices">
<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="targetDevice">Vera</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredVeraDevices">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Vera Device List
({{bridge.veradevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Vera Device, use the build action buttons
to generate the item addition information into the ha-bridge device
and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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 class="text-muted">
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.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p class="text-muted">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"><span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>
<th>Build Actions</th>
</tr>
</thead>
<tr
ng-repeat="veradevice in bridge.veradevices">
<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, false)">Build Item</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>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.devices">
<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="targetDevice">Vera</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredVeraDevices">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -1,112 +1,113 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li 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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Vera Scene List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Vera Scene, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>
<th>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="verascene in bridge.verascenes">
<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)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Vera</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredVeraScenes">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</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>
<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 ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Vera Scene List</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Vera Scene, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, 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" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>
<th>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="verascene in bridge.verascenes">
<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)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<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>
<div ng-if="buttonsVisible" class="panel-body">
<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="targetDevice">Vera</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredVeraScenes">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -0,0 +1,21 @@
package com.bwssystems.color.test;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
import com.bwssystems.HABridge.hue.ColorDecode;
public class ConvertCIEColorTestCase {
@Test
public void testColorConversion() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(new Double(0.3972), new Double(0.4564)));
String colorDecode = ColorDecode.convertCIEtoRGB(xy);
Assert.assertEquals(colorDecode, null);
}
}