mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bcec27861 | ||
|
|
bb0ffeb570 | ||
|
|
0c4292bfd7 | ||
|
|
0083c5854f | ||
|
|
c13b9bd8f4 | ||
|
|
ca5a6c6667 | ||
|
|
c9c6d6e66d | ||
|
|
c8b1827150 | ||
|
|
d7d83e866e | ||
|
|
fb24e9d1a3 | ||
|
|
d15a1c58d0 | ||
|
|
08c87eb3aa | ||
|
|
7da4bf13e0 | ||
|
|
cd701ca02e | ||
|
|
1b676632fe | ||
|
|
62e366c028 | ||
|
|
838b86a266 | ||
|
|
ed8fc95782 | ||
|
|
f6cb41b880 | ||
|
|
a578aa9fd8 | ||
|
|
7b97bd75ae | ||
|
|
4de14217b4 | ||
|
|
02918dc49d | ||
|
|
3a8c64aac6 | ||
|
|
10df2f1c3e | ||
|
|
c7cf48bb6b | ||
|
|
54e9303708 | ||
|
|
6b4344bbe8 | ||
|
|
745986f08f | ||
|
|
5e59b33ed7 | ||
|
|
c45cb24b20 | ||
|
|
adc34ddaa6 | ||
|
|
88f34f3221 | ||
|
|
15223630eb | ||
|
|
2f456aa0d0 | ||
|
|
201aaa8bca | ||
|
|
6e7b48aa5b | ||
|
|
afd1af4094 | ||
|
|
61156e9820 | ||
|
|
6116d37675 | ||
|
|
f8474f5f41 | ||
|
|
0305646b4f | ||
|
|
3fea7f4f1a | ||
|
|
44fbaa68f8 | ||
|
|
dd0032a567 | ||
|
|
470f6b3c15 | ||
|
|
3016712ad8 | ||
|
|
2fbf26a5fa | ||
|
|
6b3ae1b971 | ||
|
|
71258c7e52 | ||
|
|
ee066f1449 | ||
|
|
e5871e61b5 | ||
|
|
6b8a714959 | ||
|
|
cf3ec7cfe4 | ||
|
|
805aac9fde | ||
|
|
1221df4c96 | ||
|
|
1c897e3b36 | ||
|
|
0ac8061118 | ||
|
|
65b0d6e470 | ||
|
|
99e2243e2d | ||
|
|
7a354619d0 | ||
|
|
2dc245bb96 | ||
|
|
c679548bbd | ||
|
|
16a248ba8e | ||
|
|
0ce23c0f00 | ||
|
|
babf81ea31 | ||
|
|
e36145f216 | ||
|
|
8cd571c183 |
128
README.md
128
README.md
@@ -1,6 +1,32 @@
|
|||||||
# ha-bridge
|
# 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.
|
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.**
|
**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!**
|
**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**
|
**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.
|
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.
|
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
|
||||||
|
|
||||||
```
|
```
|
||||||
java -jar ha-bridge-4.1.1.jar
|
java -jar ha-bridge-4.3.0.jar
|
||||||
```
|
```
|
||||||
### Automation on Linux systems
|
### 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
|
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.1.1.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:~ $ mkdir habridge
|
||||||
pi@raspberrypi:~ $ cd habridge
|
pi@raspberrypi:~ $ cd habridge
|
||||||
|
|
||||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.1/ha-bridge-4.1.1.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.1.1.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:~ $ mkdir habridge
|
||||||
pi@raspberrypi:~ $ cd habridge
|
pi@raspberrypi:~ $ cd habridge
|
||||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.1.1/ha-bridge-4.1.1.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)
|
#### 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
|
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]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
|
|
||||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.1.jar
|
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.0.jar
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
@@ -104,7 +130,7 @@ Then cut and past this, modify any locations that are not correct
|
|||||||
```
|
```
|
||||||
cd /home/pi/habridge
|
cd /home/pi/habridge
|
||||||
rm /home/pi/habridge/habridge-log.txt
|
rm /home/pi/habridge/habridge-log.txt
|
||||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.1.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
|
chmod 777 /home/pi/habridge/habridge-log.txt
|
||||||
```
|
```
|
||||||
@@ -149,54 +175,6 @@ Added the following lines to my Apache config file “000-default”
|
|||||||
</VirtualHost>
|
</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
|
service apache2 restart
|
||||||
### lighthttpd Example
|
### lighthttpd Example
|
||||||
```
|
```
|
||||||
@@ -263,11 +241,7 @@ The upnp response port that will be used. The default is 50000.
|
|||||||
#### Vera Names and IP Addresses
|
#### 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
|
#### 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.
|
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}
|
||||||
#### Harmony Username
|
|
||||||
deprecated
|
|
||||||
#### Harmony Password
|
|
||||||
deprecated
|
|
||||||
#### Hue Names and IP Addresses
|
#### 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.
|
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.
|
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
|
#### 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.
|
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)
|
#### 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).
|
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
|
#### 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:
|
Here are the fields that can be put into the call item:
|
||||||
Json Type | field name | What | Use
|
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 | 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
|
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
|
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 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",
|
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:
|
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.
|
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:
|
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.
|
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":"exec://C:\\Users\\John\\Documents\\Applications\\putty.exe 192.168.1.1","type":"cmdDevice"},{"item":"exec://notepad.exe","type":"cmdDevice"}]
|
||||||
{"item":"notepad.exe","type":"cmdDevice"}]
|
|
||||||
|
|
||||||
OR
|
|
||||||
|
|
||||||
[{"item":"exec://notepad.exe","type":"cmdDevice"}]
|
|
||||||
|
|
||||||
|
[{"item":"/home/pi/scripts/dothisscript.sh","type":"cmdDevice"}]
|
||||||
```
|
```
|
||||||
#### Value Passing Controls
|
#### 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)}".
|
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
|
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.
|
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"}]
|
[{"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"}]
|
||||||
@@ -472,8 +450,8 @@ Dim a light | "Dim the <light name>"
|
|||||||
Brighten a light | "Brighten the <light name>"
|
Brighten a light | "Brighten the <light name>"
|
||||||
Set a light brightness to a certain percentage | "Set <light name> to 50%"
|
Set a light brightness to a certain percentage | "Set <light name> to 50%"
|
||||||
Dim/Brighten lights by a certain percentage | "Dim/Brighten <light name> by 50%"
|
Dim/Brighten lights by a certain percentage | "Dim/Brighten <light name> by 50%"
|
||||||
Turn on/off all lights in room | “Turn on/off lights in <room name>"
|
Turn on/off all lights in room | "Turn on/off lights in <room name>"
|
||||||
Turn on/off all lights | “Turn on/off all of the lightsâ€<EFBFBD>
|
Turn on/off all lights | "Turn on/off all of the lights"
|
||||||
|
|
||||||
To see what Home thinks you said, you can ask "Hey Google, What did I say?" or check the history in the app.
|
To see what Home thinks you said, you can ask "Hey Google, What did I say?" or check the history in the app.
|
||||||
|
|
||||||
@@ -518,7 +496,7 @@ contentBodyOff | string | This is the content body that you would like to send w
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Dimming Control Example
|
#### 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.
|
e.g.
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
@@ -692,7 +670,7 @@ This call returns a null json "{}".
|
|||||||
### Get HA Bridge Version
|
### Get HA Bridge Version
|
||||||
Get current version of the HA bridge software.
|
Get current version of the HA bridge software.
|
||||||
```
|
```
|
||||||
GET http://host:port/api/devices/habridge/version
|
GET http://host:port/system/habridge/version
|
||||||
```
|
```
|
||||||
#### Response
|
#### Response
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
|
|||||||
144
kodivolume.md
144
kodivolume.md
@@ -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 doesn’t include **“volume”** as it will cause conflicts with the Echo’s 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 don’t see something that looks like the code above, then go back and double check your settings.
|
|
||||||
#### The JSON request
|
|
||||||
|
|
||||||
The URL is what connects you to Kodi, JSON is what is used to communicate with it. The JSON that is used to set the volume level is:
|
|
||||||
|
|
||||||
``` json
|
|
||||||
{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
|
||||||
```
|
|
||||||
##### Joining the URL and JSON
|
|
||||||
|
|
||||||
Join the two together by adding `?request=` to the end of the URL and then add the JSON to the end of the request. You will end up with something like:
|
|
||||||
|
|
||||||
```
|
|
||||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
|
||||||
```
|
|
||||||
### Testing the request in a browser
|
|
||||||
|
|
||||||
Go ahead and test the combined URL/JSON in a browser changing **100** to whatever level you want to set. Kodi should adjust the volume accordingly, try a few different levels to be sure it is working correctly.
|
|
||||||
|
|
||||||
The browser will reformat the URL each time you press return so don’t build the URL in the browser bar without making a copy first.
|
|
||||||
|
|
||||||
Ideally build the URL in a text document which you can easily edit and then copy/paste each time.
|
|
||||||
|
|
||||||
### Prepare the three URLs
|
|
||||||
|
|
||||||
You want to end up with three full URLs in your text file, one for each of the commands.
|
|
||||||
|
|
||||||
**ON**
|
|
||||||
|
|
||||||
```
|
|
||||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
|
|
||||||
```
|
|
||||||
|
|
||||||
**DIM**
|
|
||||||
|
|
||||||
```
|
|
||||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":45},"id":1}
|
|
||||||
```
|
|
||||||
|
|
||||||
**OFF**
|
|
||||||
|
|
||||||
```
|
|
||||||
http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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 can’t get it to work in a browser then you won’t 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.
|
|
||||||
14
pom.xml
14
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>4.1.2</version>
|
<version>4.3.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.bwssytems</groupId>
|
<groupId>com.github.bwssytems</groupId>
|
||||||
<artifactId>nest-controller</artifactId>
|
<artifactId>nest-controller</artifactId>
|
||||||
<version>1.0.13</version>
|
<version>1.0.14</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
@@ -121,6 +121,16 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.bwssytems</groupId>
|
||||||
|
<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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
public void buildSettings() {
|
public void buildSettings() {
|
||||||
String addressString = null;
|
String addressString = null;
|
||||||
String theVeraAddress = null;
|
String theVeraAddress = null;
|
||||||
|
String theSomfyAddress = null;
|
||||||
String theHarmonyAddress = null;
|
String theHarmonyAddress = null;
|
||||||
String configFileProperty = System.getProperty("config.file");
|
String configFileProperty = System.getProperty("config.file");
|
||||||
if(configFileProperty == null) {
|
if(configFileProperty == null) {
|
||||||
@@ -103,6 +104,23 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
theBridgeSettings.setHarmonyAddress(theHarmonyList);
|
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.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||||
theBridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
theBridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||||
theBridgeSettings.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DEFAULT_BUTTON_SLEEP)));
|
theBridgeSettings.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DEFAULT_BUTTON_SLEEP)));
|
||||||
@@ -148,11 +166,15 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
theBridgeSettings.setMqttconfigured(theBridgeSettings.isValidMQTT());
|
theBridgeSettings.setMqttconfigured(theBridgeSettings.isValidMQTT());
|
||||||
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
|
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
|
||||||
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
|
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
|
||||||
|
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
|
||||||
|
// Lifx is either configured or not, so it does not need an update.
|
||||||
if(serverPortOverride != null)
|
if(serverPortOverride != null)
|
||||||
theBridgeSettings.setServerPort(serverPortOverride);
|
theBridgeSettings.setServerPort(serverPortOverride);
|
||||||
if(serverIpOverride != null)
|
if(serverIpOverride != null)
|
||||||
theBridgeSettings.setWebaddress(serverIpOverride);
|
theBridgeSettings.setWebaddress(serverIpOverride);
|
||||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||||
|
|
||||||
|
setupInternalTestUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadConfig() {
|
public void loadConfig() {
|
||||||
@@ -187,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) {
|
private void configWriter(String content, Path filePath) {
|
||||||
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||||
log.error("Error file is not writable: " + filePath);
|
log.error("Error file is not writable: " + filePath);
|
||||||
@@ -278,4 +310,9 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
return addressString;
|
return addressString;
|
||||||
}
|
}
|
||||||
|
private void setupInternalTestUser() {
|
||||||
|
theBridgeSettings.setupInternalTestUser();
|
||||||
|
if(theBridgeSettings.isSettingsChanged())
|
||||||
|
this.updateConfigFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.HueConstants;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueError;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||||
|
|
||||||
public class BridgeSettingsDescriptor {
|
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 String upnpconfigaddress;
|
||||||
private Integer serverport;
|
private Integer serverport;
|
||||||
private Integer upnpresponseport;
|
private Integer upnpresponseport;
|
||||||
@@ -40,6 +49,10 @@ public class BridgeSettingsDescriptor {
|
|||||||
private String hubversion;
|
private String hubversion;
|
||||||
private IpList domoticzaddress;
|
private IpList domoticzaddress;
|
||||||
private boolean domoticzconfigured;
|
private boolean domoticzconfigured;
|
||||||
|
private IpList somfyaddress;
|
||||||
|
private boolean somfyconfigured;
|
||||||
|
|
||||||
|
private boolean lifxconfigured;
|
||||||
|
|
||||||
public BridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor() {
|
||||||
super();
|
super();
|
||||||
@@ -47,6 +60,7 @@ public class BridgeSettingsDescriptor {
|
|||||||
this.traceupnp = false;
|
this.traceupnp = false;
|
||||||
this.nestconfigured = false;
|
this.nestconfigured = false;
|
||||||
this.veraconfigured = false;
|
this.veraconfigured = false;
|
||||||
|
this.somfyconfigured = false;
|
||||||
this.harmonyconfigured = false;
|
this.harmonyconfigured = false;
|
||||||
this.hueconfigured = false;
|
this.hueconfigured = false;
|
||||||
this.halconfigured = false;
|
this.halconfigured = false;
|
||||||
@@ -92,9 +106,15 @@ public class BridgeSettingsDescriptor {
|
|||||||
public IpList getVeraAddress() {
|
public IpList getVeraAddress() {
|
||||||
return veraaddress;
|
return veraaddress;
|
||||||
}
|
}
|
||||||
|
public IpList getSomfyAddress() {
|
||||||
|
return somfyaddress;
|
||||||
|
}
|
||||||
public void setVeraAddress(IpList veraAddress) {
|
public void setVeraAddress(IpList veraAddress) {
|
||||||
this.veraaddress = veraAddress;
|
this.veraaddress = veraAddress;
|
||||||
}
|
}
|
||||||
|
public void setSomfyAddress(IpList somfyAddress) {
|
||||||
|
this.somfyaddress = somfyAddress;
|
||||||
|
}
|
||||||
public IpList getHarmonyAddress() {
|
public IpList getHarmonyAddress() {
|
||||||
return harmonyaddress;
|
return harmonyaddress;
|
||||||
}
|
}
|
||||||
@@ -128,9 +148,15 @@ public class BridgeSettingsDescriptor {
|
|||||||
public boolean isVeraconfigured() {
|
public boolean isVeraconfigured() {
|
||||||
return veraconfigured;
|
return veraconfigured;
|
||||||
}
|
}
|
||||||
|
public boolean isSomfyconfigured() {
|
||||||
|
return somfyconfigured;
|
||||||
|
}
|
||||||
public void setVeraconfigured(boolean veraconfigured) {
|
public void setVeraconfigured(boolean veraconfigured) {
|
||||||
this.veraconfigured = veraconfigured;
|
this.veraconfigured = veraconfigured;
|
||||||
}
|
}
|
||||||
|
public void setSomfyconfigured(boolean somfyconfigured) {
|
||||||
|
this.somfyconfigured = somfyconfigured;
|
||||||
|
}
|
||||||
public boolean isHarmonyconfigured() {
|
public boolean isHarmonyconfigured() {
|
||||||
return harmonyconfigured;
|
return harmonyconfigured;
|
||||||
}
|
}
|
||||||
@@ -263,6 +289,12 @@ public class BridgeSettingsDescriptor {
|
|||||||
public void setDomoticzconfigured(boolean domoticzconfigured) {
|
public void setDomoticzconfigured(boolean domoticzconfigured) {
|
||||||
this.domoticzconfigured = domoticzconfigured;
|
this.domoticzconfigured = domoticzconfigured;
|
||||||
}
|
}
|
||||||
|
public boolean isLifxconfigured() {
|
||||||
|
return lifxconfigured;
|
||||||
|
}
|
||||||
|
public void setLifxconfigured(boolean lifxconfigured) {
|
||||||
|
this.lifxconfigured = lifxconfigured;
|
||||||
|
}
|
||||||
public Boolean isValidVera() {
|
public Boolean isValidVera() {
|
||||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -328,4 +360,88 @@ public class BridgeSettingsDescriptor {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ public class DeviceMapTypes {
|
|||||||
public final static String[] UDP_DEVICE_COMPAT = { "UDP", "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[] HTTP_DEVICE = { "httpDevice", "HTTP Device"};
|
||||||
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz 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 typeIndex = 0;
|
||||||
public final static int displayIndex = 1;
|
public final static int displayIndex = 1;
|
||||||
@@ -46,13 +48,16 @@ public class DeviceMapTypes {
|
|||||||
deviceMapTypes.add(HASS_DEVICE);
|
deviceMapTypes.add(HASS_DEVICE);
|
||||||
deviceMapTypes.add(HTTP_DEVICE);
|
deviceMapTypes.add(HTTP_DEVICE);
|
||||||
deviceMapTypes.add(HUE_DEVICE);
|
deviceMapTypes.add(HUE_DEVICE);
|
||||||
|
deviceMapTypes.add(LIFX_DEVICE);
|
||||||
deviceMapTypes.add(MQTT_MESSAGE);
|
deviceMapTypes.add(MQTT_MESSAGE);
|
||||||
deviceMapTypes.add(NEST_HOMEAWAY);
|
deviceMapTypes.add(NEST_HOMEAWAY);
|
||||||
deviceMapTypes.add(NEST_THERMO_SET);
|
deviceMapTypes.add(NEST_THERMO_SET);
|
||||||
|
deviceMapTypes.add(SOMFY_DEVICE);
|
||||||
deviceMapTypes.add(TCP_DEVICE);
|
deviceMapTypes.add(TCP_DEVICE);
|
||||||
deviceMapTypes.add(UDP_DEVICE);
|
deviceMapTypes.add(UDP_DEVICE);
|
||||||
deviceMapTypes.add(VERA_DEVICE);
|
deviceMapTypes.add(VERA_DEVICE);
|
||||||
deviceMapTypes.add(VERA_SCENE);
|
deviceMapTypes.add(VERA_SCENE);
|
||||||
|
deviceMapTypes.add(SOMFY_DEVICE);
|
||||||
}
|
}
|
||||||
public static int getTypeIndex() {
|
public static int getTypeIndex() {
|
||||||
return typeIndex;
|
return typeIndex;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class HABridge {
|
|||||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
theSettingResponder.setupServer();
|
theSettingResponder.setupServer();
|
||||||
// setup the class to handle the hue emulator rest api
|
// 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();
|
theHueMulator.setupServer();
|
||||||
// wait for the sparkjava initialization of the rest api classes to be complete
|
// wait for the sparkjava initialization of the rest api classes to be complete
|
||||||
awaitInitialization();
|
awaitInitialization();
|
||||||
@@ -87,6 +87,7 @@ public class HABridge {
|
|||||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
homeManager.closeHomes();
|
homeManager.closeHomes();
|
||||||
udpSender.closeResponseSocket();
|
udpSender.closeResponseSocket();
|
||||||
|
udpSender = null;
|
||||||
}
|
}
|
||||||
bridgeSettings.getBridgeControl().setReinit(false);
|
bridgeSettings.getBridgeControl().setReinit(false);
|
||||||
stop();
|
stop();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -12,7 +13,9 @@ import com.bwssystems.HABridge.plugins.harmony.HarmonyHome;
|
|||||||
import com.bwssystems.HABridge.plugins.hass.HassHome;
|
import com.bwssystems.HABridge.plugins.hass.HassHome;
|
||||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
import com.bwssystems.HABridge.plugins.hue.HueHome;
|
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.mqtt.MQTTHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.somfy.SomfyHome;
|
||||||
import com.bwssystems.HABridge.plugins.tcp.TCPHome;
|
import com.bwssystems.HABridge.plugins.tcp.TCPHome;
|
||||||
import com.bwssystems.HABridge.plugins.udp.UDPHome;
|
import com.bwssystems.HABridge.plugins.udp.UDPHome;
|
||||||
import com.bwssystems.HABridge.plugins.vera.VeraHome;
|
import com.bwssystems.HABridge.plugins.vera.VeraHome;
|
||||||
@@ -70,7 +73,6 @@ public class HomeManager {
|
|||||||
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
|
||||||
//setup the tcp handler Home
|
//setup the tcp handler Home
|
||||||
aHome = new TCPHome(bridgeSettings);
|
aHome = new TCPHome(bridgeSettings);
|
||||||
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
@@ -79,13 +81,22 @@ public class HomeManager {
|
|||||||
aHome = new UDPHome(bridgeSettings, aUdpDatagramSender);
|
aHome = new UDPHome(bridgeSettings, aUdpDatagramSender);
|
||||||
homeList.put(DeviceMapTypes.UDP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.UDP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.UDP_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.UDP_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
// Setup Vera Home if available
|
||||||
aHome = new VeraHome(bridgeSettings);
|
aHome = new VeraHome(bridgeSettings);
|
||||||
resourceList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
resourceList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||||
//setup the HomeAssistant configuration if available
|
//setup the Domoticz configuration if available
|
||||||
aHome = new DomoticzHome(bridgeSettings);
|
aHome = new DomoticzHome(bridgeSettings);
|
||||||
|
homeList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
resourceList.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);
|
||||||
|
homeList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Home findHome(String type) {
|
public Home findHome(String type) {
|
||||||
@@ -96,6 +107,11 @@ public class HomeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void closeHomes() {
|
public void closeHomes() {
|
||||||
|
Collection<Home> theHomes = homeList.values();
|
||||||
|
for(Home aHome : theHomes) {
|
||||||
|
aHome.closeHome();
|
||||||
|
}
|
||||||
|
homeList.clear();
|
||||||
|
homeList = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.bwssystems.HABridge;
|
|||||||
public class NamedIP {
|
public class NamedIP {
|
||||||
private String name;
|
private String name;
|
||||||
private String ip;
|
private String ip;
|
||||||
|
private String webhook;
|
||||||
private String port;
|
private String port;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
@@ -20,6 +21,12 @@ public class NamedIP {
|
|||||||
public void setIp(String ip) {
|
public void setIp(String ip) {
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
}
|
}
|
||||||
|
public String getWebhook() {
|
||||||
|
return webhook;
|
||||||
|
}
|
||||||
|
public void setWebhook(final String webhook) {
|
||||||
|
this.webhook = webhook;
|
||||||
|
}
|
||||||
public String getPort() {
|
public String getPort() {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ public class SystemControl {
|
|||||||
return "{\"version\":\"" + version.getVersion() + "\"}";
|
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
|
// http://ip_address:port/system/logmsgs gets the log messages for the bridge
|
||||||
get (SYSTEM_CONTEXT + "/logmsgs", "application/json", (request, response) -> {
|
get (SYSTEM_CONTEXT + "/logmsgs", "application/json", (request, response) -> {
|
||||||
log.debug("Get logmsgs.");
|
log.debug("Get logmsgs.");
|
||||||
|
|||||||
@@ -62,6 +62,18 @@ public class DeviceDescriptor{
|
|||||||
@SerializedName("noState")
|
@SerializedName("noState")
|
||||||
@Expose
|
@Expose
|
||||||
private boolean noState;
|
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;
|
private DeviceState deviceState;
|
||||||
|
|
||||||
@@ -219,6 +231,38 @@ public class DeviceDescriptor{
|
|||||||
this.noState = noState;
|
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) {
|
public boolean containsType(String aType) {
|
||||||
if(aType == null)
|
if(aType == null)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -83,6 +83,33 @@ public class DeviceRepository extends BackupHandler {
|
|||||||
return list;
|
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) {
|
public DeviceDescriptor findOne(String id) {
|
||||||
return devices.get(id);
|
return devices.get(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
import com.bwssystems.HABridge.HomeManager;
|
import com.bwssystems.HABridge.HomeManager;
|
||||||
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.BackupFilename;
|
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||||
import com.bwssystems.HABridge.dao.ErrorMessage;
|
import com.bwssystems.HABridge.dao.ErrorMessage;
|
||||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
spark core server for bridge configuration
|
spark core server for bridge configuration
|
||||||
@@ -33,11 +36,13 @@ public class DeviceResource {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
private HomeManager homeManager;
|
private HomeManager homeManager;
|
||||||
|
private Gson aGsonHandler;
|
||||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||||
|
|
||||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
|
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
|
||||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
homeManager = aHomeManager;
|
homeManager = aHomeManager;
|
||||||
|
aGsonHandler = new GsonBuilder().create();
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,14 +70,44 @@ public class DeviceResource {
|
|||||||
else {
|
else {
|
||||||
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
||||||
}
|
}
|
||||||
|
CallItem[] callItems = null;
|
||||||
|
String errorMessage = null;
|
||||||
for(int i = 0; i < devices.length; i++) {
|
for(int i = 0; i < devices.length; i++) {
|
||||||
if(devices[i].getContentBody() != null ) {
|
if(devices[i].getContentBody() != null ) {
|
||||||
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
|
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
log.debug("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();
|
||||||
return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
|
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);
|
deviceRepository.save(devices);
|
||||||
@@ -219,6 +254,18 @@ public class DeviceResource {
|
|||||||
return homeManager.findResource(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]);
|
return homeManager.findResource(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/lifx/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get LIFX devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
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) -> {
|
get (API_CONTEXT + "/map/types", "application/json", (request, response) -> {
|
||||||
log.debug("Get map types");
|
log.debug("Get map types");
|
||||||
return new DeviceMapTypes().getDeviceMapTypes();
|
return new DeviceMapTypes().getDeviceMapTypes();
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import org.apache.commons.lang3.Conversion;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.java.dev.eval.Expression;
|
import net.java.dev.eval.Expression;
|
||||||
|
|
||||||
public class BrightnessDecode {
|
public class BrightnessDecode {
|
||||||
private static final Logger log = LoggerFactory.getLogger(BrightnessDecode.class);
|
private static final Logger log = LoggerFactory.getLogger(BrightnessDecode.class);
|
||||||
private static final String INTENSITY_PERCENT = "${intensity.percent}";
|
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_BYTE = "${intensity.byte}";
|
||||||
private static final String INTENSITY_MATH = "${intensity.math(";
|
private static final String INTENSITY_MATH = "${intensity.math(";
|
||||||
private static final String INTENSITY_MATH_VALUE = "X";
|
private static final String INTENSITY_MATH_VALUE = "X";
|
||||||
private static final String INTENSITY_MATH_CLOSE = ")}";
|
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) {
|
public static int calculateIntensity(int setIntensity, Integer targetBri, Integer targetBriInc) {
|
||||||
if (targetBri != null) {
|
if (targetBri != null) {
|
||||||
@@ -47,51 +48,79 @@ public class BrightnessDecode {
|
|||||||
if (request == null) {
|
if (request == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
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 (request.contains(INTENSITY_BYTE)) {
|
||||||
if (isHex) {
|
if (isHex) {
|
||||||
BigInteger bigInt = BigInteger.valueOf(intensity);
|
replaceValue = convertToHex(intensity);
|
||||||
byte[] theBytes = bigInt.toByteArray();
|
|
||||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
|
||||||
request = request.replace(INTENSITY_BYTE, hexValue);
|
|
||||||
} else {
|
} else {
|
||||||
String intensityByte = String.valueOf(intensity);
|
replaceValue = String.valueOf(intensity);
|
||||||
request = request.replace(INTENSITY_BYTE, intensityByte);
|
|
||||||
}
|
}
|
||||||
|
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)) {
|
} else if (request.contains(INTENSITY_PERCENT)) {
|
||||||
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
|
|
||||||
if (isHex) {
|
if (isHex) {
|
||||||
BigInteger bigInt = BigInteger.valueOf(percentBrightness);
|
replaceValue = convertToHex(percentBrightness);
|
||||||
byte[] theBytes = bigInt.toByteArray();
|
|
||||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
|
||||||
request = request.replace(INTENSITY_PERCENT, hexValue);
|
|
||||||
} else {
|
} else {
|
||||||
String intensityPercent = String.valueOf(percentBrightness);
|
replaceValue = String.valueOf(percentBrightness);
|
||||||
request = request.replace(INTENSITY_PERCENT, intensityPercent);
|
|
||||||
}
|
}
|
||||||
} else if (request.contains(INTENSITY_MATH)) {
|
replaceTarget = INTENSITY_PERCENT;
|
||||||
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
notDone = true;
|
||||||
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
|
} 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));
|
request.indexOf(INTENSITY_MATH_CLOSE));
|
||||||
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
||||||
|
|
||||||
try {
|
|
||||||
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: "
|
log.debug("Math eval is: " + mathDescriptor + ", Where " + INTENSITY_MATH_VALUE + " is: "
|
||||||
+ String.valueOf(intensity));
|
+ String.valueOf(intensity));
|
||||||
Expression exp = new Expression(mathDescriptor);
|
Integer endResult = calculateMath(variables, mathDescriptor);
|
||||||
BigDecimal result = exp.eval(variables);
|
if(endResult != null) {
|
||||||
Integer endResult = Math.round(result.floatValue());
|
|
||||||
if (isHex) {
|
if (isHex) {
|
||||||
BigInteger bigInt = BigInteger.valueOf(endResult);
|
replaceValue = convertToHex(endResult);
|
||||||
byte[] theBytes = bigInt.toByteArray();
|
|
||||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
|
||||||
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, hexValue);
|
|
||||||
} else {
|
} else {
|
||||||
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE,
|
replaceValue = endResult.toString();
|
||||||
endResult.toString());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE;
|
||||||
log.warn("Could not execute Math: " + mathDescriptor, e);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(notDone)
|
||||||
|
request = request.replace(replaceTarget, replaceValue);
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -100,4 +129,28 @@ public class BrightnessDecode {
|
|||||||
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
|
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
|
||||||
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
21
src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java
Normal file
21
src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
import com.bwssystems.HABridge.HomeManager;
|
import com.bwssystems.HABridge.HomeManager;
|
||||||
@@ -14,9 +15,7 @@ import com.bwssystems.HABridge.api.hue.HueError;
|
|||||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||||
import com.bwssystems.HABridge.api.hue.StateChangeBody;
|
import com.bwssystems.HABridge.api.hue.StateChangeBody;
|
||||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
|
||||||
import com.bwssystems.HABridge.dao.*;
|
import com.bwssystems.HABridge.dao.*;
|
||||||
import com.bwssystems.HABridge.plugins.hue.HueDeviceIdentifier;
|
|
||||||
import com.bwssystems.HABridge.plugins.hue.HueHome;
|
import com.bwssystems.HABridge.plugins.hue.HueHome;
|
||||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -34,12 +33,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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
|
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
||||||
@@ -53,13 +48,15 @@ public class HueMulator {
|
|||||||
private HomeManager homeManager;
|
private HomeManager homeManager;
|
||||||
private HueHome myHueHome;
|
private HueHome myHueHome;
|
||||||
private BridgeSettingsDescriptor bridgeSettings;
|
private BridgeSettingsDescriptor bridgeSettings;
|
||||||
|
private BridgeSettings bridgeSettingMaster;
|
||||||
private Gson aGsonHandler;
|
private Gson aGsonHandler;
|
||||||
private DeviceMapTypes validMapTypes;
|
private DeviceMapTypes validMapTypes;
|
||||||
|
|
||||||
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HomeManager aHomeManager) {
|
public HueMulator(BridgeSettings bridgeMaster, DeviceRepository aDeviceRepository, HomeManager aHomeManager) {
|
||||||
repository = aDeviceRepository;
|
repository = aDeviceRepository;
|
||||||
validMapTypes = new DeviceMapTypes();
|
validMapTypes = new DeviceMapTypes();
|
||||||
bridgeSettings = theBridgeSettings;
|
bridgeSettingMaster = bridgeMaster;
|
||||||
|
bridgeSettings = bridgeSettingMaster.getBridgeSettingsDescriptor();
|
||||||
homeManager= aHomeManager;
|
homeManager= aHomeManager;
|
||||||
myHueHome = (HueHome) homeManager.findHome(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]);
|
myHueHome = (HueHome) homeManager.findHome(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
aGsonHandler = new GsonBuilder().create();
|
aGsonHandler = new GsonBuilder().create();
|
||||||
@@ -394,7 +391,7 @@ public class HueMulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String formatSuccessHueResponse(StateChangeBody stateChanges, String body, String lightId,
|
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 = "[";
|
String responseString = "[";
|
||||||
boolean notFirstChange = false;
|
boolean notFirstChange = false;
|
||||||
@@ -409,6 +406,8 @@ public class HueMulator {
|
|||||||
deviceState.setOn(stateChanges.isOn());
|
deviceState.setOn(stateChanges.isOn());
|
||||||
if(!deviceState.isOn() && deviceState.getBri() == 254)
|
if(!deviceState.isOn() && deviceState.getBri() == 254)
|
||||||
deviceState.setBri(0);
|
deviceState.setBri(0);
|
||||||
|
if(!deviceState.isOn() && offState)
|
||||||
|
deviceState.setBri(0);
|
||||||
}
|
}
|
||||||
notFirstChange = true;
|
notFirstChange = true;
|
||||||
}
|
}
|
||||||
@@ -557,50 +556,6 @@ public class HueMulator {
|
|||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNewUserID() {
|
|
||||||
UUID uid = UUID.randomUUID();
|
|
||||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
|
||||||
String newUser = "";
|
|
||||||
while (st.hasMoreTokens()) {
|
|
||||||
newUser = newUser + st.nextToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
return newUser;
|
|
||||||
}
|
|
||||||
private 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) {
|
private Boolean filterByRequester(String requesterFilterList, String anAddress) {
|
||||||
if (requesterFilterList == null || requesterFilterList.length() == 0)
|
if (requesterFilterList == null || requesterFilterList.length() == 0)
|
||||||
return true;
|
return true;
|
||||||
@@ -621,9 +576,13 @@ public class HueMulator {
|
|||||||
|
|
||||||
private String basicListHandler(String type, String userId, String requestIp) {
|
private String basicListHandler(String type, String userId, String requestIp) {
|
||||||
log.debug("hue " + type + " list requested: " + userId + " from " + requestIp);
|
log.debug("hue " + type + " list requested: " + userId + " from " + requestIp);
|
||||||
HueError[] theErrors = validateWhitelistUser(userId, false);
|
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||||
if (theErrors != null)
|
if (theErrors != null) {
|
||||||
|
if(bridgeSettings.isSettingsChanged())
|
||||||
|
bridgeSettingMaster.updateConfigFile();
|
||||||
|
|
||||||
return aGsonHandler.toJson(theErrors);
|
return aGsonHandler.toJson(theErrors);
|
||||||
|
}
|
||||||
|
|
||||||
return "{}";
|
return "{}";
|
||||||
}
|
}
|
||||||
@@ -631,8 +590,11 @@ public class HueMulator {
|
|||||||
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
||||||
HueError[] theErrors = null;
|
HueError[] theErrors = null;
|
||||||
Map<String, GroupResponse> groupResponseMap = null;
|
Map<String, GroupResponse> groupResponseMap = null;
|
||||||
theErrors = validateWhitelistUser(userId, false);
|
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||||
if (theErrors == null) {
|
if (theErrors == null) {
|
||||||
|
if(bridgeSettings.isSettingsChanged())
|
||||||
|
bridgeSettingMaster.updateConfigFile();
|
||||||
|
|
||||||
groupResponseMap = new HashMap<String, GroupResponse>();
|
groupResponseMap = new HashMap<String, GroupResponse>();
|
||||||
groupResponseMap.put("1", (GroupResponse) this.groupsIdHandler("1", userId, requestIp));
|
groupResponseMap.put("1", (GroupResponse) this.groupsIdHandler("1", userId, requestIp));
|
||||||
return groupResponseMap;
|
return groupResponseMap;
|
||||||
@@ -645,8 +607,11 @@ public class HueMulator {
|
|||||||
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
||||||
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
||||||
HueError[] theErrors = null;
|
HueError[] theErrors = null;
|
||||||
theErrors = validateWhitelistUser(userId, false);
|
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||||
if (theErrors == null) {
|
if (theErrors == null) {
|
||||||
|
if(bridgeSettings.isSettingsChanged())
|
||||||
|
bridgeSettingMaster.updateConfigFile();
|
||||||
|
|
||||||
if (groupId.equalsIgnoreCase("0")) {
|
if (groupId.equalsIgnoreCase("0")) {
|
||||||
GroupResponse theResponse = GroupResponse.createDefaultGroupResponse(repository.findActive());
|
GroupResponse theResponse = GroupResponse.createDefaultGroupResponse(repository.findActive());
|
||||||
return theResponse;
|
return theResponse;
|
||||||
@@ -667,9 +632,13 @@ public class HueMulator {
|
|||||||
if (bridgeSettings.isTraceupnp())
|
if (bridgeSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
||||||
log.debug("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) {
|
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>();
|
deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||||
for (DeviceDescriptor device : deviceList) {
|
for (DeviceDescriptor device : deviceList) {
|
||||||
DeviceResponse deviceResponse = null;
|
DeviceResponse deviceResponse = null;
|
||||||
@@ -724,12 +693,20 @@ public class HueMulator {
|
|||||||
newUser = aNewUser.getUsername();
|
newUser = aNewUser.getUsername();
|
||||||
aDeviceType = aNewUser.getDevicetype();
|
aDeviceType = aNewUser.getDevicetype();
|
||||||
}
|
}
|
||||||
if (newUser == null)
|
|
||||||
newUser = getNewUserID();
|
|
||||||
|
|
||||||
validateWhitelistUser(newUser, false);
|
|
||||||
if (aDeviceType == null)
|
if (aDeviceType == null)
|
||||||
aDeviceType = "<not given>";
|
aDeviceType = "<not given>";
|
||||||
|
|
||||||
|
if (newUser == null) {
|
||||||
|
newUser = bridgeSettings.createWhitelistUser(aDeviceType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bridgeSettings.validateWhitelistUser(newUser, aDeviceType, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bridgeSettings.isSettingsChanged())
|
||||||
|
bridgeSettingMaster.updateConfigFile();
|
||||||
|
|
||||||
if (bridgeSettings.isTraceupnp())
|
if (bridgeSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: "
|
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: "
|
||||||
+ newUser + (followingSlash ? " /api/ called" : ""));
|
+ newUser + (followingSlash ? " /api/ called" : ""));
|
||||||
@@ -743,7 +720,7 @@ public class HueMulator {
|
|||||||
if (bridgeSettings.isTraceupnp())
|
if (bridgeSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress);
|
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress);
|
||||||
log.debug("hue api 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");
|
log.debug("hue api config requested, No User supplied, returning public config");
|
||||||
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
|
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
|
||||||
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
|
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
|
||||||
@@ -759,7 +736,7 @@ public class HueMulator {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Object getFullState(String userId, String ipAddress) {
|
private Object getFullState(String userId, String ipAddress) {
|
||||||
log.debug("hue api full state requested: " + userId + " from " + 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)
|
if (theErrors != null)
|
||||||
return theErrors;
|
return theErrors;
|
||||||
|
|
||||||
@@ -773,7 +750,7 @@ public class HueMulator {
|
|||||||
|
|
||||||
private Object getLight(String userId, String lightId, String ipAddress) {
|
private Object getLight(String userId, String lightId, String ipAddress) {
|
||||||
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + 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)
|
if (theErrors != null)
|
||||||
return theErrors;
|
return theErrors;
|
||||||
|
|
||||||
@@ -817,7 +794,7 @@ public class HueMulator {
|
|||||||
Integer targetBri = null;
|
Integer targetBri = null;
|
||||||
Integer targetBriInc = null;
|
Integer targetBriInc = null;
|
||||||
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
|
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)
|
if (theErrors != null)
|
||||||
return aGsonHandler.toJson(theErrors);
|
return aGsonHandler.toJson(theErrors);
|
||||||
try {
|
try {
|
||||||
@@ -849,7 +826,7 @@ public class HueMulator {
|
|||||||
if (state == null)
|
if (state == null)
|
||||||
state = DeviceState.createDeviceState();
|
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);
|
device.setDeviceState(state);
|
||||||
|
|
||||||
return responseString;
|
return responseString;
|
||||||
@@ -867,7 +844,7 @@ public class HueMulator {
|
|||||||
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
|
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
|
||||||
aMultiUtil.setSetCount(1);
|
aMultiUtil.setSetCount(1);
|
||||||
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
|
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)
|
if (theErrors != null)
|
||||||
return aGsonHandler.toJson(theErrors);
|
return aGsonHandler.toJson(theErrors);
|
||||||
try {
|
try {
|
||||||
@@ -945,8 +922,8 @@ public class HueMulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||||
if(!filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
|
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
|
||||||
log.debug("filter for requester address not present in list: " + callItems[i].getFilterIPs() + " with request ip of: " + 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
|
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
|
||||||
@@ -989,11 +966,11 @@ public class HueMulator {
|
|||||||
|
|
||||||
if (responseString == null || !responseString.contains("[{\"error\":")) {
|
if (responseString == null || !responseString.contains("[{\"error\":")) {
|
||||||
if(!device.isNoState()) {
|
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);
|
device.setDeviceState(state);
|
||||||
} else {
|
} else {
|
||||||
DeviceState dummyState = DeviceState.createDeviceState();
|
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;
|
return responseString;
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ public class TimeDecode {
|
|||||||
if (request == null) {
|
if (request == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
boolean notDone = true;
|
||||||
|
|
||||||
|
while(notDone) {
|
||||||
|
notDone = false;
|
||||||
if (request.contains(TIME_FORMAT)) {
|
if (request.contains(TIME_FORMAT)) {
|
||||||
String timeFormatDescriptor = request.substring(request.indexOf(TIME_FORMAT) + TIME_FORMAT.length(),
|
String timeFormatDescriptor = request.substring(request.indexOf(TIME_FORMAT) + TIME_FORMAT.length(),
|
||||||
request.indexOf(TIME_FORMAT_CLOSE));
|
request.indexOf(TIME_FORMAT_CLOSE));
|
||||||
@@ -29,10 +33,12 @@ public class TimeDecode {
|
|||||||
log.debug("Time eval is: " + timeFormatDescriptor);
|
log.debug("Time eval is: " + timeFormatDescriptor);
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatDescriptor);
|
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatDescriptor);
|
||||||
request = request.replace(TIME_FORMAT + timeFormatDescriptor + TIME_FORMAT_CLOSE, dateFormat.format(new Date()));
|
request = request.replace(TIME_FORMAT + timeFormatDescriptor + TIME_FORMAT_CLOSE, dateFormat.format(new Date()));
|
||||||
|
notDone = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Could not format current time: " + timeFormatDescriptor, e);
|
log.warn("Could not format current time: " + timeFormatDescriptor, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,11 +94,11 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
|||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
if(theSession != null) {
|
if(theSession != null) {
|
||||||
theNest.endNestSession();
|
theNest.endNestSession();
|
||||||
|
}
|
||||||
theNest = null;
|
theNest = null;
|
||||||
theSession = null;
|
theSession = null;
|
||||||
nestItems = null;
|
nestItems = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ package com.bwssystems.HABridge.plugins.domoticz;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Base64;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.NameValue;
|
||||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@@ -16,32 +17,33 @@ public class DomoticzHandler {
|
|||||||
private static final String GET_REQUEST = "/json.htm?type=";
|
private static final String GET_REQUEST = "/json.htm?type=";
|
||||||
private static final String DEVICES_TYPE = "devices";
|
private static final String DEVICES_TYPE = "devices";
|
||||||
private static final String SCENES_TYPE = "scenes";
|
private static final String SCENES_TYPE = "scenes";
|
||||||
private static final String FILTER_USED = "&used=";
|
private static final String FILTER_USED = "&used=true";
|
||||||
private HTTPHandler httpClient;
|
|
||||||
private NamedIP domoticzAddress;
|
private NamedIP domoticzAddress;
|
||||||
|
|
||||||
public DomoticzHandler(NamedIP addressName) {
|
public DomoticzHandler(NamedIP addressName) {
|
||||||
super();
|
super();
|
||||||
httpClient = new HTTPHandler();
|
|
||||||
domoticzAddress = addressName;
|
domoticzAddress = addressName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DomoticzDevice> getDevices() {
|
public List<DomoticzDevice> getDevices(HTTPHandler httpClient) {
|
||||||
return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED);
|
return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED, httpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DomoticzDevice> getScenes() {
|
public List<DomoticzDevice> getScenes(HTTPHandler httpClient) {
|
||||||
return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null);
|
return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null, httpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DomoticzDevice> getDomoticzDevices(String rootRequest, String type, String postpend) {
|
private List<DomoticzDevice> getDomoticzDevices(String rootRequest, String type, String postpend, HTTPHandler httpClient) {
|
||||||
Devices theDomoticzApiResponse = null;
|
Devices theDomoticzApiResponse = null;
|
||||||
List<DomoticzDevice> deviceList = null;
|
List<DomoticzDevice> deviceList = null;
|
||||||
|
|
||||||
String theUrl = null;
|
String theUrl = null;
|
||||||
String theData;
|
String theData;
|
||||||
theUrl = "http://" + domoticzAddress.getIp() + ":" + domoticzAddress.getPort() + rootRequest + type;
|
if(postpend != null && !postpend.isEmpty())
|
||||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
theUrl = buildUrl(rootRequest + type + postpend);
|
||||||
|
else
|
||||||
|
theUrl = buildUrl(rootRequest + type);
|
||||||
|
theData = httpClient.doHttpRequest(theUrl, null, null, null, buildHeaders());
|
||||||
if(theData != null) {
|
if(theData != null) {
|
||||||
log.debug("GET " + type + " DomoticzApiResponse - data: " + theData);
|
log.debug("GET " + type + " DomoticzApiResponse - data: " + theData);
|
||||||
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
|
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
|
||||||
@@ -70,6 +72,44 @@ public class DomoticzHandler {
|
|||||||
return deviceList;
|
return deviceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String buildUrl(String thePayload) {
|
||||||
|
String newUrl = null;
|
||||||
|
|
||||||
|
if(thePayload != null && !thePayload.isEmpty()) {
|
||||||
|
if(domoticzAddress.getSecure() != null && domoticzAddress.getSecure())
|
||||||
|
newUrl = "https://";
|
||||||
|
else
|
||||||
|
newUrl = "http://";
|
||||||
|
|
||||||
|
newUrl = newUrl + domoticzAddress.getIp();
|
||||||
|
|
||||||
|
if(domoticzAddress.getPort() != null && !domoticzAddress.getPort().isEmpty())
|
||||||
|
newUrl = newUrl + ":" + domoticzAddress.getPort();
|
||||||
|
|
||||||
|
if(thePayload.startsWith("/"))
|
||||||
|
newUrl = newUrl + thePayload;
|
||||||
|
else
|
||||||
|
newUrl = newUrl + "/" + thePayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameValue[] buildHeaders() {
|
||||||
|
NameValue[] headers = null;
|
||||||
|
|
||||||
|
if(domoticzAddress.getUsername() != null && !domoticzAddress.getUsername().isEmpty()
|
||||||
|
&& domoticzAddress.getPassword() != null && !domoticzAddress.getPassword().isEmpty()) {
|
||||||
|
NameValue theAuth = new NameValue();
|
||||||
|
theAuth.setName("Authorization");
|
||||||
|
String encoding = Base64.getEncoder().encodeToString((domoticzAddress.getUsername() + ":" + domoticzAddress.getPassword()).getBytes());
|
||||||
|
theAuth.setValue("Basic " + encoding);
|
||||||
|
headers = new NameValue[1];
|
||||||
|
headers[0] = theAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
public NamedIP getDomoticzAddress() {
|
public NamedIP getDomoticzAddress() {
|
||||||
return domoticzAddress;
|
return domoticzAddress;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,19 @@ import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
|||||||
import com.bwssystems.HABridge.Home;
|
import com.bwssystems.HABridge.Home;
|
||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueError;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class DomoticzHome implements Home {
|
public class DomoticzHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(DomoticzHome.class);
|
private static final Logger log = LoggerFactory.getLogger(DomoticzHome.class);
|
||||||
private Map<String, DomoticzHandler> domoticzs;
|
private Map<String, DomoticzHandler> domoticzs;
|
||||||
private Boolean validDomoticz;
|
private Boolean validDomoticz;
|
||||||
|
private HTTPHandler httpClient;
|
||||||
|
|
||||||
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
|
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
@@ -36,14 +42,14 @@ public class DomoticzHome implements Home {
|
|||||||
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
|
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
|
||||||
while(keys.hasNext()) {
|
while(keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
theResponse = domoticzs.get(key).getDevices();
|
theResponse = domoticzs.get(key).getDevices(httpClient);
|
||||||
if(theResponse != null)
|
if(theResponse != null)
|
||||||
addDomoticzDevices(deviceList, theResponse, key);
|
addDomoticzDevices(deviceList, theResponse, key);
|
||||||
else {
|
else {
|
||||||
log.warn("Cannot get lights for Domoticz with name: " + key + ", skipping this Domoticz.");
|
log.warn("Cannot get lights for Domoticz with name: " + key + ", skipping this Domoticz.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
theResponse = domoticzs.get(key).getScenes();
|
theResponse = domoticzs.get(key).getScenes(httpClient);
|
||||||
if(theResponse != null)
|
if(theResponse != null)
|
||||||
addDomoticzDevices(deviceList, theResponse, key);
|
addDomoticzDevices(deviceList, theResponse, key);
|
||||||
else
|
else
|
||||||
@@ -66,8 +72,54 @@ public class DomoticzHome implements Home {
|
|||||||
@Override
|
@Override
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||||
// Not a device handler
|
Devices theDomoticzApiResponse = null;
|
||||||
return null;
|
String responseString = null;
|
||||||
|
|
||||||
|
String theUrl = anItem.getItem().getAsString();
|
||||||
|
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
||||||
|
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||||
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
|
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||||
|
String hostAddr = null;
|
||||||
|
if (hostPortion.contains(":")) {
|
||||||
|
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||||
|
} else
|
||||||
|
hostAddr = hostPortion;
|
||||||
|
DomoticzHandler theHandler = findHandlerByAddress(hostAddr);
|
||||||
|
if(theHandler != null){
|
||||||
|
String theData;
|
||||||
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
|
||||||
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, null, theHandler.buildHeaders());
|
||||||
|
try {
|
||||||
|
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
|
||||||
|
if(theDomoticzApiResponse.getStatus().equals("OK"))
|
||||||
|
responseString = null;
|
||||||
|
else {
|
||||||
|
log.warn("Call failed for Domoticz " + theHandler.getDomoticzAddress().getName() + " with status " + theDomoticzApiResponse.getStatus() + " for item " + theDomoticzApiResponse.getTitle());
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"Error on calling url to change device state", "/lights/"
|
||||||
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Cannot interrpret result from call for Domoticz " + theHandler.getDomoticzAddress().getName() + " as response is not parsable.");
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"Error on calling url to change device state", "/lights/"
|
||||||
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("Domoticz Call could not complete, no address found: " + theUrl);
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"Error on calling url to change device state", "/lights/"
|
||||||
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("Domoticz Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"Error on calling url to change device state", "/lights/"
|
||||||
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,6 +128,7 @@ public class DomoticzHome implements Home {
|
|||||||
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
|
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
|
||||||
if(!validDomoticz)
|
if(!validDomoticz)
|
||||||
return null;
|
return null;
|
||||||
|
httpClient = new HTTPHandler();
|
||||||
domoticzs = new HashMap<String, DomoticzHandler>();
|
domoticzs = new HashMap<String, DomoticzHandler>();
|
||||||
Iterator<NamedIP> theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
|
||||||
while(theList.hasNext()) {
|
while(theList.hasNext()) {
|
||||||
@@ -90,9 +143,26 @@ public class DomoticzHome implements Home {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DomoticzHandler findHandlerByAddress(String hostAddress) {
|
||||||
|
DomoticzHandler aHandler = null;
|
||||||
|
boolean found = false;
|
||||||
|
Iterator<String> keys = domoticzs.keySet().iterator();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
aHandler = domoticzs.get(key);
|
||||||
|
if(aHandler != null && aHandler.getDomoticzAddress().getIp().equals(hostAddress)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
aHandler = null;
|
||||||
|
return aHandler;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
// noop
|
if(httpClient != null)
|
||||||
|
httpClient.closeHandler();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.bwssystems.HABridge.Home;
|
|||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ public class CommandHome implements Home {
|
|||||||
else
|
else
|
||||||
intermediate = anItem.getItem().getAsString();
|
intermediate = anItem.getItem().getAsString();
|
||||||
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
|
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
|
||||||
|
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
||||||
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
||||||
String anError = doExecRequest(intermediate, lightId);
|
String anError = doExecRequest(intermediate, lightId);
|
||||||
if (anError != null) {
|
if (anError != null) {
|
||||||
|
|||||||
@@ -185,4 +185,11 @@ public class HalInfo {
|
|||||||
this.halAddress = halAddress;
|
this.halAddress = halAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeInfo() {
|
||||||
|
if(httpClient != null)
|
||||||
|
httpClient.closeHandler();
|
||||||
|
httpClient = null;
|
||||||
|
halAddress = null;
|
||||||
|
theToken = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.bwssystems.HABridge.IpList;
|
|||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
@@ -161,6 +162,8 @@ public class HarmonyHome implements Home {
|
|||||||
if (url.substring(0, 1).equalsIgnoreCase("{")) {
|
if (url.substring(0, 1).equalsIgnoreCase("{")) {
|
||||||
url = "[" + url + "]";
|
url = "[" + url + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url = BrightnessDecode.calculateReplaceIntensityValue(url, intensity, targetBri, targetBriInc, false);
|
||||||
ButtonPress[] deviceButtons = aGsonHandler.fromJson(url, ButtonPress[].class);
|
ButtonPress[] deviceButtons = aGsonHandler.fromJson(url, ButtonPress[].class);
|
||||||
Integer theCount = 1;
|
Integer theCount = 1;
|
||||||
for(int z = 0; z < deviceButtons.length; z++) {
|
for(int z = 0; z < deviceButtons.length; z++) {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import static java.lang.String.format;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -18,7 +20,13 @@ import net.whistlingfish.harmony.HarmonyClientModule;
|
|||||||
import net.whistlingfish.harmony.config.Activity;
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
public class HarmonyServer {
|
public class HarmonyServer {
|
||||||
|
|
||||||
|
private static final String ACTIVIY_ID = "${activity.id}";
|
||||||
|
private static final String ACTIVIY_LABEL = "${activity.label}";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private HarmonyClient harmonyClient;
|
private HarmonyClient harmonyClient;
|
||||||
|
|
||||||
@@ -27,6 +35,7 @@ public class HarmonyServer {
|
|||||||
private OAReplyProvider dummyProvider;
|
private OAReplyProvider dummyProvider;
|
||||||
private NamedIP myNameAndIP;
|
private NamedIP myNameAndIP;
|
||||||
private Boolean isDevMode;
|
private Boolean isDevMode;
|
||||||
|
private HTTPHandler httpClient;
|
||||||
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||||
|
|
||||||
public HarmonyServer(NamedIP theHarmonyAddress) {
|
public HarmonyServer(NamedIP theHarmonyAddress) {
|
||||||
@@ -35,18 +44,25 @@ public class HarmonyServer {
|
|||||||
dummyProvider = null;
|
dummyProvider = null;
|
||||||
myNameAndIP = theHarmonyAddress;
|
myNameAndIP = theHarmonyAddress;
|
||||||
isDevMode = false;
|
isDevMode = false;
|
||||||
|
httpClient = new HTTPHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HarmonyServer setup(BridgeSettingsDescriptor bridgeSettings, Boolean harmonyDevMode, NamedIP theHarmonyAddress) throws Exception {
|
public static HarmonyServer setup(
|
||||||
if(!bridgeSettings.isValidHarmony() && harmonyDevMode) {
|
BridgeSettingsDescriptor bridgeSettings,
|
||||||
|
Boolean harmonyDevMode,
|
||||||
|
NamedIP theHarmonyAddress
|
||||||
|
) throws Exception {
|
||||||
|
if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
|
||||||
return new HarmonyServer(theHarmonyAddress);
|
return new HarmonyServer(theHarmonyAddress);
|
||||||
}
|
}
|
||||||
Injector injector = null;
|
Injector injector = null;
|
||||||
if(!harmonyDevMode)
|
if (!harmonyDevMode) {
|
||||||
injector = Guice.createInjector(new HarmonyClientModule());
|
injector = Guice.createInjector(new HarmonyClientModule());
|
||||||
|
}
|
||||||
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
||||||
if(!harmonyDevMode)
|
if (!harmonyDevMode) {
|
||||||
injector.injectMembers(mainObject);
|
injector.injectMembers(mainObject);
|
||||||
|
}
|
||||||
mainObject.execute(bridgeSettings, harmonyDevMode);
|
mainObject.execute(bridgeSettings, harmonyDevMode);
|
||||||
return mainObject;
|
return mainObject;
|
||||||
}
|
}
|
||||||
@@ -55,23 +71,38 @@ public class HarmonyServer {
|
|||||||
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||||
isDevMode = harmonyDevMode;
|
isDevMode = harmonyDevMode;
|
||||||
String modeString = "";
|
String modeString = "";
|
||||||
if(dummyProvider != null)
|
if (dummyProvider != null) {
|
||||||
log.debug("something is very wrong as dummyProvider is not null...");
|
log.debug("something is very wrong as dummyProvider is not null...");
|
||||||
if(isDevMode)
|
}
|
||||||
|
if (isDevMode) {
|
||||||
modeString = " (development mode)";
|
modeString = " (development mode)";
|
||||||
else if(noopCalls)
|
} else if (noopCalls) {
|
||||||
modeString = " (no op calls to harmony)";
|
modeString = " (no op calls to harmony)";
|
||||||
|
}
|
||||||
log.info("setup initiated " + modeString + "....");
|
log.info("setup initiated " + modeString + "....");
|
||||||
if(isDevMode)
|
if (isDevMode) {
|
||||||
{
|
|
||||||
harmonyClient = null;
|
harmonyClient = null;
|
||||||
devResponse = new DevModeResponse();
|
devResponse = new DevModeResponse();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
devResponse = null;
|
devResponse = null;
|
||||||
harmonyClient.addListener(new ActivityChangeListener() {
|
harmonyClient.addListener(new ActivityChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void activityStarted(Activity activity) {
|
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()));
|
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -151,10 +151,14 @@ public class HassHome implements Home {
|
|||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
if(!validHass)
|
if(!validHass)
|
||||||
return;
|
return;
|
||||||
|
if(hassMap == null)
|
||||||
|
return;
|
||||||
Iterator<String> keys = hassMap.keySet().iterator();
|
Iterator<String> keys = hassMap.keySet().iterator();
|
||||||
while(keys.hasNext()) {
|
while(keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
hassMap.get(key).closeClient();
|
hassMap.get(key).closeClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hassMap = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,12 @@ public class HomeAssistant {
|
|||||||
aUrl = "https";
|
aUrl = "https";
|
||||||
else
|
else
|
||||||
aUrl = "http";
|
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() + "\"";
|
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
|
||||||
NameValue[] headers = null;
|
NameValue[] headers = null;
|
||||||
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
||||||
@@ -62,6 +67,7 @@ public class HomeAssistant {
|
|||||||
aUrl = aUrl + "/turn_off";
|
aUrl = aUrl + "/turn_off";
|
||||||
aBody = aBody + "}";
|
aBody = aBody + "}";
|
||||||
}
|
}
|
||||||
|
log.debug("Calling HomeAssistant with url: " + aUrl);
|
||||||
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
|
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
|
||||||
log.debug("call Command return is: <" + theData + ">");
|
log.debug("call Command return is: <" + theData + ">");
|
||||||
return true;
|
return true;
|
||||||
@@ -104,5 +110,6 @@ public class HomeAssistant {
|
|||||||
|
|
||||||
protected void closeClient() {
|
protected void closeClient() {
|
||||||
anHttpHandler.closeHandler();
|
anHttpHandler.closeHandler();
|
||||||
|
anHttpHandler = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,18 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.Charset;
|
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.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
import org.apache.http.client.config.CookieSpecs;
|
import org.apache.http.client.config.CookieSpecs;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.config.RequestConfig;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.ssl.SSLContexts;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -33,23 +24,13 @@ import com.bwssystems.HABridge.api.NameValue;
|
|||||||
|
|
||||||
public class HTTPHandler {
|
public class HTTPHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
|
||||||
private HttpClient httpClient;
|
private CloseableHttpClient httpClient;
|
||||||
// private CloseableHttpClient httpclientSSL;
|
private RequestConfig globalConfig;
|
||||||
// private SSLContext sslcontext;
|
|
||||||
// private SSLConnectionSocketFactory sslsf;
|
|
||||||
// private RequestConfig globalConfig;
|
|
||||||
|
|
||||||
|
|
||||||
public HTTPHandler() {
|
public HTTPHandler() {
|
||||||
httpClient = HttpClients.createDefault();
|
globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
||||||
// Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
|
httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
|
||||||
// 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();
|
|
||||||
// httpclientSSL = HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(globalConfig).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -100,14 +81,11 @@ public class HTTPHandler {
|
|||||||
request.setHeader(headers[i].getName(), headers[i].getValue());
|
request.setHeader(headers[i].getName(), headers[i].getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
// Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
|
try {
|
||||||
// if (url.startsWith("xyzhttps"))
|
for(int retryCount = 0; retryCount < 2; retryCount++) {
|
||||||
// response = httpclientSSL.execute(request);
|
|
||||||
// else
|
|
||||||
response = httpClient.execute(request);
|
response = httpClient.execute(request);
|
||||||
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute on URL responded: "
|
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: "
|
||||||
+ response.getStatusLine().getStatusCode());
|
+ response.getStatusLine().getStatusCode());
|
||||||
if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
|
if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
|
||||||
if (response.getEntity() != null) {
|
if (response.getEntity() != null) {
|
||||||
@@ -124,9 +102,35 @@ public class HTTPHandler {
|
|||||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
|
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
|
||||||
+ e.getMessage(), e);
|
+ e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
if (theContent == null)
|
|
||||||
theContent = "";
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||||
@@ -134,23 +138,22 @@ public class HTTPHandler {
|
|||||||
return theContent;
|
return theContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpClient getHttpClient() {
|
// public HttpClient getHttpClient() {
|
||||||
|
// return httpClient;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
public CloseableHttpClient getHttpClient() {
|
||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public CloseableHttpClient getHttpclientSSL() {
|
|
||||||
// return httpclientSSL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
public void closeHandler() {
|
public void closeHandler() {
|
||||||
|
try {
|
||||||
|
httpClient.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
httpClient = null;
|
httpClient = null;
|
||||||
// try {
|
|
||||||
// httpclientSSL.close();
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// // noop
|
|
||||||
// }
|
|
||||||
// httpclientSSL = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.bwssystems.HABridge.api.hue.HueError;
|
|||||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -29,6 +30,8 @@ public class HTTPHome implements Home {
|
|||||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
|
|
||||||
|
String theUrl = anItem.getItem().getAsString();
|
||||||
|
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
||||||
//Backwards Compatibility Items
|
//Backwards Compatibility Items
|
||||||
if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
|
if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
|
||||||
{
|
{
|
||||||
@@ -45,14 +48,16 @@ public class HTTPHome implements Home {
|
|||||||
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
||||||
+ anItem.getItem().getAsString());
|
+ anItem.getItem().getAsString());
|
||||||
|
|
||||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(anItem.getItem().getAsString(),
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
|
||||||
intensity, targetBri, targetBriInc, false);
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
String aBody = null;
|
String aBody = null;
|
||||||
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
|
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
|
||||||
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
|
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
|
||||||
intensity, targetBri, targetBriInc, false);
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
|
||||||
aBody = TimeDecode.replaceTimeValue(aBody);
|
aBody = TimeDecode.replaceTimeValue(aBody);
|
||||||
}
|
}
|
||||||
// make call
|
// make call
|
||||||
@@ -63,6 +68,13 @@ public class HTTPHome implements Home {
|
|||||||
"Error on calling url to change device state", "/lights/"
|
"Error on calling url to change device state", "/lights/"
|
||||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("HTTP Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"Error on calling url to change device state", "/lights/"
|
||||||
|
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +93,9 @@ public class HTTPHome implements Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
|
if(anHttpHandler != null)
|
||||||
anHttpHandler.closeHandler();
|
anHttpHandler.closeHandler();
|
||||||
|
anHttpHandler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,10 +124,13 @@ public class HueHome implements Home {
|
|||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
if(!validHue)
|
if(!validHue)
|
||||||
return;
|
return;
|
||||||
|
if(hues == null)
|
||||||
|
return;
|
||||||
Iterator<String> keys = hues.keySet().iterator();
|
Iterator<String> keys = hues.keySet().iterator();
|
||||||
while(keys.hasNext()) {
|
while(keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
hues.get(key).closeHue();;
|
hues.get(key).closeHue();;
|
||||||
}
|
}
|
||||||
|
hues = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.lifx;
|
||||||
|
|
||||||
|
import com.github.besherman.lifx.LFXGroup;
|
||||||
|
import com.github.besherman.lifx.LFXLight;
|
||||||
|
|
||||||
|
public class LifxDevice {
|
||||||
|
private Object lifxObject;
|
||||||
|
private String type;
|
||||||
|
public final static String LIGHT_TYPE = "Light";
|
||||||
|
public final static String GROUP_TYPE = "Group";
|
||||||
|
|
||||||
|
public LifxDevice(Object lifxObject, String type) {
|
||||||
|
super();
|
||||||
|
this.lifxObject = lifxObject;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LifxEntry toEntry() {
|
||||||
|
LifxEntry anEntry = null;
|
||||||
|
if(type.equals(LIGHT_TYPE)) {
|
||||||
|
anEntry = new LifxEntry();
|
||||||
|
anEntry.setId(((LFXLight)lifxObject).getID());
|
||||||
|
anEntry.setName(((LFXLight)lifxObject).getLabel());
|
||||||
|
anEntry.setType(LIGHT_TYPE);
|
||||||
|
}
|
||||||
|
if(type.equals(GROUP_TYPE)) {
|
||||||
|
anEntry = new LifxEntry();
|
||||||
|
anEntry.setId("na");
|
||||||
|
anEntry.setName(((LFXGroup)lifxObject).getLabel());
|
||||||
|
anEntry.setType(GROUP_TYPE);
|
||||||
|
}
|
||||||
|
return anEntry;
|
||||||
|
}
|
||||||
|
public Object getLifxObject() {
|
||||||
|
return lifxObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLifxObject(Object lifxObject) {
|
||||||
|
this.lifxObject = lifxObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.lifx;
|
||||||
|
|
||||||
|
public class LifxEntry {
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
private String type;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
257
src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java
Normal file
257
src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.lifx;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InterfaceAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.Home;
|
||||||
|
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.github.besherman.lifx.LFXClient;
|
||||||
|
import com.github.besherman.lifx.LFXGroup;
|
||||||
|
import com.github.besherman.lifx.LFXGroupCollection;
|
||||||
|
import com.github.besherman.lifx.LFXGroupCollectionListener;
|
||||||
|
import com.github.besherman.lifx.LFXLight;
|
||||||
|
import com.github.besherman.lifx.LFXLightCollection;
|
||||||
|
import com.github.besherman.lifx.LFXLightCollectionListener;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
public class LifxHome implements Home {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LifxHome.class);
|
||||||
|
private static final float DIM_DIVISOR = (float)254.00;
|
||||||
|
private Map<String, LifxDevice> lifxMap;
|
||||||
|
private LFXClient client;
|
||||||
|
private Boolean validLifx;
|
||||||
|
private Gson aGsonHandler;
|
||||||
|
|
||||||
|
public LifxHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
super();
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
lifxMap = null;
|
||||||
|
aGsonHandler = null;
|
||||||
|
validLifx = bridgeSettings.isValidLifx();
|
||||||
|
log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
|
||||||
|
if(validLifx) {
|
||||||
|
try {
|
||||||
|
log.info("Open Lifx client....");
|
||||||
|
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getUpnpConfigAddress());
|
||||||
|
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
|
||||||
|
InetAddress bcastInetAddr = null;
|
||||||
|
if (networkInterface != null) {
|
||||||
|
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
|
||||||
|
InetAddress addr = ifaceAddr.getAddress();
|
||||||
|
if (addr instanceof Inet4Address) {
|
||||||
|
bcastInetAddr = ifaceAddr.getBroadcast();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bcastInetAddr != null) {
|
||||||
|
lifxMap = new HashMap<String, LifxDevice>();
|
||||||
|
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
|
||||||
|
client = new LFXClient(bcastInetAddr.getHostAddress());
|
||||||
|
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
|
||||||
|
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
|
||||||
|
client.open(false);
|
||||||
|
aGsonHandler =
|
||||||
|
new GsonBuilder()
|
||||||
|
.create();
|
||||||
|
} else {
|
||||||
|
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
|
||||||
|
client = null;
|
||||||
|
validLifx = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not open LIFX, with IO Exception", e);
|
||||||
|
client = null;
|
||||||
|
validLifx = false;
|
||||||
|
return this;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("Could not open LIFX, with Interruprted Exception", e);
|
||||||
|
client = null;
|
||||||
|
validLifx = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LifxDevice getLifxDevice(String aName) {
|
||||||
|
if(!validLifx)
|
||||||
|
return null;
|
||||||
|
LifxDevice aLifxDevice = null;
|
||||||
|
if(aName == null || aName.equals("")) {
|
||||||
|
log.debug("Cannot get LifxDevice for name as it is empty.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
aLifxDevice = lifxMap.get(aName);
|
||||||
|
log.debug("Retrieved a LifxDevice for name: " + aName);
|
||||||
|
}
|
||||||
|
return aLifxDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItems(String type) {
|
||||||
|
log.debug("consolidating devices for lifx");
|
||||||
|
if(!validLifx)
|
||||||
|
return null;
|
||||||
|
LifxEntry theResponse = null;
|
||||||
|
Iterator<String> keys = lifxMap.keySet().iterator();
|
||||||
|
List<LifxEntry> deviceList = new ArrayList<LifxEntry>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
theResponse = lifxMap.get(key).toEntry();
|
||||||
|
if(theResponse != null)
|
||||||
|
deviceList.add(theResponse);
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get LifxDevice with name: " + key + ", skipping this Lifx.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean addLifxLights(LFXLightCollection theDeviceList) {
|
||||||
|
if(!validLifx)
|
||||||
|
return false;
|
||||||
|
Iterator<LFXLight> devices = theDeviceList.iterator();;
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
LFXLight theDevice = devices.next();
|
||||||
|
LifxDevice aNewLifxDevice = new LifxDevice(theDevice, LifxDevice.LIGHT_TYPE);
|
||||||
|
lifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean addLifxGroups(LFXGroupCollection theDeviceList) {
|
||||||
|
if(!validLifx)
|
||||||
|
return false;
|
||||||
|
Iterator<LFXGroup> devices = theDeviceList.iterator();;
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
LFXGroup theDevice = devices.next();
|
||||||
|
LifxDevice aNewLifxDevice = new LifxDevice(theDevice, LifxDevice.GROUP_TYPE);
|
||||||
|
lifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||||
|
String theReturn = null;
|
||||||
|
float aBriValue;
|
||||||
|
float theValue;
|
||||||
|
log.debug("executing HUE api request to send message to LifxDevice: " + anItem.getItem().toString());
|
||||||
|
if(!validLifx) {
|
||||||
|
log.warn("Should not get here, no LifxDevice clients configured");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "state\"}}]";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LifxEntry lifxCommand = null;
|
||||||
|
if(anItem.getItem().isJsonObject())
|
||||||
|
lifxCommand = aGsonHandler.fromJson(anItem.getItem(), LifxEntry.class);
|
||||||
|
else
|
||||||
|
lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), LifxEntry.class);
|
||||||
|
LifxDevice theDevice = getLifxDevice(lifxCommand.getName());
|
||||||
|
if (theDevice == null) {
|
||||||
|
log.warn("Should not get here, no LifxDevices available");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no Lifx clients available\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "state\"}}]";
|
||||||
|
} else {
|
||||||
|
log.debug("calling LifxDevice: " + lifxCommand.getName());
|
||||||
|
if(theDevice.getType().equals(LifxDevice.LIGHT_TYPE)) {
|
||||||
|
LFXLight theLight = (LFXLight)theDevice.getLifxObject();
|
||||||
|
if(body.contains("true"))
|
||||||
|
theLight.setPower(true);
|
||||||
|
if(body.contains("false"))
|
||||||
|
theLight.setPower(false);
|
||||||
|
if(targetBri != null || targetBriInc != null) {
|
||||||
|
aBriValue = (float)BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc);
|
||||||
|
theValue = aBriValue/DIM_DIVISOR;
|
||||||
|
if(theValue > (float)1.0)
|
||||||
|
theValue = (float)0.99;
|
||||||
|
theLight.setBrightness(theValue);
|
||||||
|
}
|
||||||
|
} else if (theDevice.getType().equals(LifxDevice.GROUP_TYPE)) {
|
||||||
|
LFXGroup theGroup = (LFXGroup)theDevice.getLifxObject();
|
||||||
|
if(body.contains("true"))
|
||||||
|
theGroup.setPower(true);
|
||||||
|
if(body.contains("false"))
|
||||||
|
theGroup.setPower(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
if(!validLifx)
|
||||||
|
return;
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
private static class MyLightListener implements LFXLightCollectionListener {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MyLightListener.class);
|
||||||
|
private Map<String, LifxDevice> aLifxMap;
|
||||||
|
public MyLightListener(Map<String, LifxDevice> theMap) {
|
||||||
|
aLifxMap = theMap;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void lightAdded(LFXLight light) {
|
||||||
|
log.debug("Light added, label: " + light.getLabel() + " and id: " + light.getID());
|
||||||
|
LifxDevice aNewLifxDevice = new LifxDevice(light, LifxDevice.LIGHT_TYPE);
|
||||||
|
aLifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lightRemoved(LFXLight light) {
|
||||||
|
log.debug("Light removed, label: " + light.getLabel() + " and id: " + light.getID());
|
||||||
|
aLifxMap.remove(light.getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
private static class MyGroupListener implements LFXGroupCollectionListener {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MyLightListener.class);
|
||||||
|
private Map<String, LifxDevice> aLifxMap;
|
||||||
|
public MyGroupListener(Map<String, LifxDevice> theMap) {
|
||||||
|
aLifxMap = theMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void groupAdded(LFXGroup group) {
|
||||||
|
log.debug("Group: " + group.getLabel() + " added: " + group.size());
|
||||||
|
LifxDevice aNewLifxDevice = new LifxDevice(group, LifxDevice.GROUP_TYPE);
|
||||||
|
aLifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void groupRemoved(LFXGroup group) {
|
||||||
|
log.debug("Group: " + group.getLabel() + " removed");
|
||||||
|
aLifxMap.remove(group.getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.plugins.mqtt;
|
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.MqttClient;
|
||||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
@@ -47,7 +48,7 @@ public class MQTTHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void publishMessage(String topic, String content) {
|
public void publishMessage(String topic, String content) {
|
||||||
MqttMessage message = new MqttMessage(content.getBytes());
|
MqttMessage message = new MqttMessage(StringEscapeUtils.unescapeJava(content).getBytes());
|
||||||
message.setQos(qos);
|
message.setQos(qos);
|
||||||
try {
|
try {
|
||||||
myClient.publish(topic, message);
|
myClient.publish(topic, message);
|
||||||
@@ -68,5 +69,6 @@ public class MQTTHandler {
|
|||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
log.warn("Could not disconnect MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp());
|
log.warn("Could not disconnect MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp());
|
||||||
}
|
}
|
||||||
|
myClient = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.bwssystems.HABridge.NamedIP;
|
|||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -42,6 +43,7 @@ public class MQTTHome implements Home {
|
|||||||
handlers.get(key).shutdown();
|
handlers.get(key).shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handlers = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MQTTHandler getMQTTHandler(String aName) {
|
public MQTTHandler getMQTTHandler(String aName) {
|
||||||
@@ -88,6 +90,7 @@ public class MQTTHome implements Home {
|
|||||||
mqttObject =anItem.getItem().getAsString();
|
mqttObject =anItem.getItem().getAsString();
|
||||||
mqttObject = BrightnessDecode.calculateReplaceIntensityValue(mqttObject,
|
mqttObject = BrightnessDecode.calculateReplaceIntensityValue(mqttObject,
|
||||||
intensity, targetBri, targetBriInc, false);
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
mqttObject = DeviceDataDecode.replaceDeviceData(mqttObject, device);
|
||||||
mqttObject = TimeDecode.replaceTimeValue(mqttObject);
|
mqttObject = TimeDecode.replaceTimeValue(mqttObject);
|
||||||
if (mqttObject.substring(0, 1).equalsIgnoreCase("{"))
|
if (mqttObject.substring(0, 1).equalsIgnoreCase("{"))
|
||||||
mqttObject = "[" + mqttObject + "]";
|
mqttObject = "[" + mqttObject + "]";
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -1,12 +1,17 @@
|
|||||||
package com.bwssystems.HABridge.plugins.tcp;
|
package com.bwssystems.HABridge.plugins.tcp;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -15,12 +20,14 @@ import com.bwssystems.HABridge.Home;
|
|||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
|
||||||
public class TCPHome implements Home {
|
public class TCPHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
|
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
|
||||||
private byte[] sendData;
|
private byte[] sendData;
|
||||||
|
private Map<String, Socket> theSockets;
|
||||||
|
|
||||||
|
|
||||||
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
|
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
@@ -31,13 +38,18 @@ public class TCPHome implements Home {
|
|||||||
@Override
|
@Override
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||||
|
Socket dataSendSocket = null;
|
||||||
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
||||||
String intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
String theUrl = anItem.getItem().getAsString();
|
||||||
|
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("tcp://")) {
|
||||||
|
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||||
String hostAddr = null;
|
String hostAddr = null;
|
||||||
String port = null;
|
String port = null;
|
||||||
InetAddress IPAddress = null;
|
InetAddress IPAddress = null;
|
||||||
|
dataSendSocket = theSockets.get(hostPortion);
|
||||||
|
if(dataSendSocket == null) {
|
||||||
if (hostPortion.contains(":")) {
|
if (hostPortion.contains(":")) {
|
||||||
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||||
port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||||
@@ -49,29 +61,47 @@ public class TCPHome implements Home {
|
|||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
|
|
||||||
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
|
|
||||||
if (theUrlBody.startsWith("0x")) {
|
|
||||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
|
||||||
} else {
|
|
||||||
sendData = theUrlBody.getBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
theSockets.put(hostPortion, dataSendSocket);
|
||||||
outToClient.write(sendData);
|
|
||||||
outToClient.flush();
|
|
||||||
dataSendSocket.close();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// noop
|
// 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 {
|
||||||
|
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||||
|
outToClient.write(sendData);
|
||||||
|
outToClient.flush();
|
||||||
|
} catch (Exception e) {
|
||||||
|
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);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
log.info("TCP Home created.");
|
log.info("TCP Home created.");
|
||||||
|
theSockets = new HashMap<String, Socket>();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,8 +113,18 @@ public class TCPHome implements Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
|
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
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
|
|||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ import com.bwssystems.HABridge.Home;
|
|||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||||
@@ -33,7 +35,9 @@ public class UDPHome implements Home {
|
|||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||||
log.debug("executing HUE api request to UDP: " + anItem.getItem().getAsString());
|
log.debug("executing HUE api request to UDP: " + anItem.getItem().getAsString());
|
||||||
String intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
String theUrl = anItem.getItem().getAsString();
|
||||||
|
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("udp://")) {
|
||||||
|
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||||
String hostAddr = null;
|
String hostAddr = null;
|
||||||
@@ -51,11 +55,15 @@ public class UDPHome implements Home {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
|
|
||||||
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
|
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
|
||||||
if (theUrlBody.startsWith("0x")) {
|
if (theUrlBody.startsWith("0x")) {
|
||||||
|
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
|
||||||
|
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
|
||||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||||
} else {
|
} else {
|
||||||
|
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
|
||||||
|
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
|
||||||
|
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
|
||||||
sendData = theUrlBody.getBytes();
|
sendData = theUrlBody.getBytes();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -65,6 +73,9 @@ public class UDPHome implements Home {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn("IO exception on udp call, continuing...");
|
log.warn("IO exception on udp call, continuing...");
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
log.warn("Udp Call to be presented as udp://<ip_address>:<port>/payload, format of request unknown: " + theUrl);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ public class VeraHome implements Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
// TODO Auto-generated method stub
|
veras = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.scrollableContainer {
|
.scrollableContainer {
|
||||||
max-height: 436px; /* sets max-height value for all standards-compliant browsers */
|
height: 310px;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-top: 35px;
|
padding-top: 35px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -28,17 +28,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scrollArea {
|
.scrollArea {
|
||||||
_height: expression( this.scrollHeight > 599 ? "600px" : "auto" ); /* sets max-height for IE6 */
|
height: 100%;
|
||||||
max-height: 400px; /* sets max-height value for all standards-compliant browsers */
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border: 1px solid #d5d5d5;
|
border: 1px solid #d5d5d5;
|
||||||
/* the implementation of this is still quite buggy; specifically, it doesn't like the
|
/* the implementation of this is still quite buggy; specifically, it doesn't like the
|
||||||
absolutely positioned headers within
|
absolutely positioned headers within
|
||||||
-webkit-overflow-scrolling: touch; */
|
-webkit-overflow-scrolling: touch; */
|
||||||
|
-webkit-overflow-scrolling: auto;
|
||||||
}
|
}
|
||||||
.scrollArea table {
|
.scrollArea table {
|
||||||
overflow-x: hidden;
|
overflow-x: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
.scrollArea table th {
|
.scrollArea table th {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
min-width: 60px;
|
min-width: 40px;
|
||||||
}
|
}
|
||||||
.scrollArea table .th-inner {
|
.scrollArea table .th-inner {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -45,6 +45,14 @@ app.config (function ($locationProvider, $routeProvider) {
|
|||||||
}).when ('/domoticzdevices', {
|
}).when ('/domoticzdevices', {
|
||||||
templateUrl: 'views/domoticzdevice.html',
|
templateUrl: 'views/domoticzdevice.html',
|
||||||
controller: 'DomoticzController'
|
controller: 'DomoticzController'
|
||||||
|
}).when('/somfydevices', {
|
||||||
|
templateUrl: 'views/somfydevice.html',
|
||||||
|
controller: 'SomfyController'
|
||||||
|
}).otherwise ({
|
||||||
|
controller: 'DomoticzController'
|
||||||
|
}).when ('/lifxdevices', {
|
||||||
|
templateUrl: 'views/lifxdevice.html',
|
||||||
|
controller: 'LifxController'
|
||||||
}).otherwise ({
|
}).otherwise ({
|
||||||
templateUrl: 'views/configuration.html',
|
templateUrl: 'views/configuration.html',
|
||||||
controller: 'ViewingController'
|
controller: 'ViewingController'
|
||||||
@@ -54,6 +62,7 @@ app.config (function ($locationProvider, $routeProvider) {
|
|||||||
app.run( function (bridgeService) {
|
app.run( function (bridgeService) {
|
||||||
bridgeService.loadBridgeSettings();
|
bridgeService.loadBridgeSettings();
|
||||||
bridgeService.getHABridgeVersion();
|
bridgeService.getHABridgeVersion();
|
||||||
|
bridgeService.getTestUser();
|
||||||
bridgeService.viewMapTypes();
|
bridgeService.viewMapTypes();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -71,7 +80,7 @@ String.prototype.replaceAll = function (search, replace)
|
|||||||
|
|
||||||
app.service ('bridgeService', function ($http, $window, ngToast) {
|
app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||||
var self = this;
|
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, 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) {
|
this.displayWarn = function(errorTitle, error) {
|
||||||
var toastContent = errorTitle;
|
var toastContent = errorTitle;
|
||||||
@@ -143,7 +152,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
|||||||
|
|
||||||
this.clearDevice = function () {
|
this.clearDevice = function () {
|
||||||
self.state.device = {};
|
self.state.device = {};
|
||||||
self.state.olddevicename = "";
|
self.state.olddevicename = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getHABridgeVersion = function () {
|
this.getHABridgeVersion = function () {
|
||||||
@@ -157,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) {
|
this.aContainsB = function (a, b) {
|
||||||
return a.indexOf(b) >= 0;
|
return a.indexOf(b) >= 0;
|
||||||
}
|
}
|
||||||
@@ -257,6 +277,16 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateShowSomfy = function () {
|
||||||
|
this.state.showSomfy = self.state.settings.somfyconfigured;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateShowLifx = function () {
|
||||||
|
this.state.showLifx = self.state.settings.lifxconfigured;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loadBridgeSettings = function () {
|
this.loadBridgeSettings = function () {
|
||||||
return $http.get(this.state.systemsbase + "/settings").then(
|
return $http.get(this.state.systemsbase + "/settings").then(
|
||||||
function (response) {
|
function (response) {
|
||||||
@@ -269,6 +299,8 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
|||||||
self.updateShowMqtt();
|
self.updateShowMqtt();
|
||||||
self.updateShowHass();
|
self.updateShowHass();
|
||||||
self.updateShowDomoticz();
|
self.updateShowDomoticz();
|
||||||
|
self.updateShowSomfy();
|
||||||
|
self.updateShowLifx();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
self.displayWarn("Load Bridge Settings Error: ", error);
|
self.displayWarn("Load Bridge Settings Error: ", error);
|
||||||
@@ -450,6 +482,33 @@ 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;
|
||||||
|
return $http.get(this.state.base + "/lifx/devices").then(
|
||||||
|
function (response) {
|
||||||
|
self.state.lifxdevices = response.data;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
self.displayWarn("Get Lifx Devices Error: ", error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
this.formatCallItem = function (currentItem) {
|
this.formatCallItem = function (currentItem) {
|
||||||
if(!currentItem.startsWith("{\"item") && !currentItem.startsWith("[{\"item")) {
|
if(!currentItem.startsWith("{\"item") && !currentItem.startsWith("[{\"item")) {
|
||||||
if (currentItem.startsWith("[") || currentItem.startsWith("{"))
|
if (currentItem.startsWith("[") || currentItem.startsWith("{"))
|
||||||
@@ -491,6 +550,20 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
|||||||
type = self.getMapType(s.type[0])
|
type = self.getMapType(s.type[0])
|
||||||
s.type = 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
|
return theDevices
|
||||||
@@ -752,7 +825,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
|||||||
|
|
||||||
this.testUrl = function (device, type, value) {
|
this.testUrl = function (device, type, value) {
|
||||||
var msgDescription = "unknown";
|
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\":";
|
var testBody = "{\"on\":";
|
||||||
if (type === "off") {
|
if (type === "off") {
|
||||||
testBody = testBody + "false";
|
testBody = testBody + "false";
|
||||||
@@ -1002,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 () {
|
$scope.bridgeReinit = function () {
|
||||||
bridgeService.reinit();
|
bridgeService.reinit();
|
||||||
};
|
};
|
||||||
@@ -1074,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) {
|
app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, ngDialog) {
|
||||||
|
|
||||||
bridgeService.viewDevices();
|
bridgeService.viewDevices();
|
||||||
@@ -1139,13 +1251,22 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
|||||||
else
|
else
|
||||||
$scope.imgBkUrl = "glyphicon glyphicon-plus";
|
$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) {
|
app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||||
$scope.slider = {
|
$scope.slider = {
|
||||||
value: 100,
|
value: 100,
|
||||||
options: {
|
options: {
|
||||||
floor: 0,
|
floor: 1,
|
||||||
ceil: 100,
|
ceil: 100,
|
||||||
showSelectionBar: true
|
showSelectionBar: true
|
||||||
}
|
}
|
||||||
@@ -1154,8 +1275,8 @@ app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
|||||||
$scope.valueType = "percentage";
|
$scope.valueType = "percentage";
|
||||||
$scope.changeScale = function () {
|
$scope.changeScale = function () {
|
||||||
if($scope.valueType === "raw") {
|
if($scope.valueType === "raw") {
|
||||||
$scope.slider.options.ceil = 255;
|
$scope.slider.options.ceil = 254;
|
||||||
$scope.slider.value = 255;
|
$scope.slider.value = 254;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$scope.slider.options.ceil = 100;
|
$scope.slider.options.ceil = 100;
|
||||||
@@ -1164,7 +1285,7 @@ app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
|||||||
};
|
};
|
||||||
$scope.setValue = function () {
|
$scope.setValue = function () {
|
||||||
ngDialog.close('ngdialog1');
|
ngDialog.close('ngdialog1');
|
||||||
var theValue = 0;
|
var theValue = 1;
|
||||||
if($scope.valueType === "percentage")
|
if($scope.valueType === "percentage")
|
||||||
theValue = Math.round(($scope.slider.value * .01) * 255);
|
theValue = Math.round(($scope.slider.value * .01) * 255);
|
||||||
else
|
else
|
||||||
@@ -1205,7 +1326,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildDeviceUrls = function (veradevice, dim_control) {
|
$scope.buildDeviceUrls = function (veradevice, dim_control, buildonly) {
|
||||||
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) {
|
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) {
|
||||||
dimpayload = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
dimpayload = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||||
+ "/data_request?id=action&output_format=json&DeviceNum="
|
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||||
@@ -1226,8 +1347,10 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, veradevice.id, veradevice.name, veradevice.veraname, "switch", "veraDevice", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, veradevice.id, veradevice.name, veradevice.veraname, "switch", "veraDevice", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildSceneUrls = function (verascene) {
|
$scope.buildSceneUrls = function (verascene) {
|
||||||
@@ -1246,10 +1369,11 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
|
|
||||||
$scope.bulkAddDevices = function(dim_control) {
|
$scope.bulkAddDevices = function(dim_control) {
|
||||||
var devicesList = [];
|
var devicesList = [];
|
||||||
|
$scope.clearDevice();
|
||||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
|
||||||
if(bridgeService.state.veradevices[x].id === $scope.bulk.devices[i]) {
|
if(bridgeService.state.veradevices[x].id === $scope.bulk.devices[i]) {
|
||||||
$scope.buildDeviceUrls(bridgeService.state.veradevices[x],dim_control);
|
$scope.buildDeviceUrls(bridgeService.state.veradevices[x],dim_control,true);
|
||||||
devicesList[i] = {
|
devicesList[i] = {
|
||||||
name: $scope.device.name,
|
name: $scope.device.name,
|
||||||
mapId: $scope.device.mapId,
|
mapId: $scope.device.mapId,
|
||||||
@@ -1266,6 +1390,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
contentBodyDim: $scope.device.contentBodyDim,
|
contentBodyDim: $scope.device.contentBodyDim,
|
||||||
contentBodyOff: $scope.device.contentBodyOff
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
};
|
};
|
||||||
|
$scope.clearDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1309,7 +1434,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
else {
|
else {
|
||||||
$scope.selectAll = true;
|
$scope.selectAll = true;
|
||||||
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
|
||||||
if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.veradevices[x].id, bridgeService.state.veradevices[x].veraname, "veraDevice"))
|
if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0)
|
||||||
$scope.bulk.devices.push(bridgeService.state.veradevices[x].id);
|
$scope.bulk.devices.push(bridgeService.state.veradevices[x].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1519,16 +1644,19 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
|||||||
offpayload = "{\"ipAddress\":\"" + huedevice.hueaddress + "\",\"deviceId\":\"" + huedevice.huedeviceid +"\",\"hueName\":\"" + huedevice.huename + "\"}";
|
offpayload = "{\"ipAddress\":\"" + huedevice.hueaddress + "\",\"deviceId\":\"" + huedevice.huedeviceid +"\",\"hueName\":\"" + huedevice.huename + "\"}";
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, true, huedevice.device.uniqueid, huedevice.device.name, huedevice.huename, "passthru", "hueDevice", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, true, huedevice.device.uniqueid, huedevice.device.name, huedevice.huename, "passthru", "hueDevice", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.bulkAddDevices = function() {
|
$scope.bulkAddDevices = function() {
|
||||||
var devicesList = [];
|
var devicesList = [];
|
||||||
|
$scope.clearDevice();
|
||||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
|
||||||
if(bridgeService.state.huedevices[x].device.uniqueid === $scope.bulk.devices[i]) {
|
if(bridgeService.state.huedevices[x].device.uniqueid === $scope.bulk.devices[i]) {
|
||||||
$scope.buildDeviceUrls(bridgeService.state.huedevices[x]);
|
$scope.buildDeviceUrls(bridgeService.state.huedevices[x],true);
|
||||||
devicesList[i] = {
|
devicesList[i] = {
|
||||||
name: $scope.device.name,
|
name: $scope.device.name,
|
||||||
mapId: $scope.device.mapId,
|
mapId: $scope.device.mapId,
|
||||||
@@ -1545,6 +1673,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
|||||||
contentBodyDim: $scope.device.contentBodyDim,
|
contentBodyDim: $scope.device.contentBodyDim,
|
||||||
contentBodyOff: $scope.device.contentBodyOff
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
};
|
};
|
||||||
|
$scope.clearDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1632,7 +1761,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildDeviceUrls = function (haldevice, dim_control) {
|
$scope.buildDeviceUrls = function (haldevice, dim_control, buildonly) {
|
||||||
var preOnCmd = "";
|
var preOnCmd = "";
|
||||||
var preDimCmd = "";
|
var preDimCmd = "";
|
||||||
var preOffCmd = "";
|
var preOffCmd = "";
|
||||||
@@ -1687,11 +1816,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
+ postCmd;
|
+ postCmd;
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname, haldevice.haldevicename, haldevice.halname, aDeviceType, "halDevice", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname, haldevice.haldevicename, haldevice.halname, aDeviceType, "halDevice", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildButtonUrls = function (haldevice, onbutton, offbutton) {
|
$scope.buildButtonUrls = function (haldevice, onbutton, offbutton, buildonly) {
|
||||||
var actionOn = angular.fromJson(onbutton);
|
var actionOn = angular.fromJson(onbutton);
|
||||||
var actionOff = angular.fromJson(offbutton);
|
var actionOff = angular.fromJson(offbutton);
|
||||||
onpayload = "http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken;
|
onpayload = "http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken;
|
||||||
@@ -1699,20 +1830,24 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
|
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-" + actionOn.DeviceName, haldevice.haldevicename, haldevice.halname, "button", "halButton", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-" + actionOn.DeviceName, haldevice.haldevicename, haldevice.halname, "button", "halButton", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALHomeUrls = function (haldevice) {
|
$scope.buildHALHomeUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken;
|
onpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken;
|
||||||
offpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken;
|
offpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken;
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-HomeAway", haldevice.haldevicename, haldevice.halname, "home", "halHome", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-HomeAway", haldevice.haldevicename, haldevice.halname, "home", "halHome", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALHeatUrls = function (haldevice) {
|
$scope.buildHALHeatUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress
|
onpayload = "http://" + haldevice.haladdress
|
||||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||||
@@ -1730,11 +1865,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
+ $scope.bridge.settings.haltoken;
|
+ $scope.bridge.settings.haltoken;
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetHeat", haldevice.haldevicename + " Heat", haldevice.halname, "thermo", "halThermoSet", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetHeat", haldevice.haldevicename + " Heat", haldevice.halname, "thermo", "halThermoSet", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALCoolUrls = function (haldevice) {
|
$scope.buildHALCoolUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress
|
onpayload = "http://" + haldevice.haladdress
|
||||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||||
@@ -1752,11 +1889,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
+ $scope.bridge.settings.haltoken;
|
+ $scope.bridge.settings.haltoken;
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetCool", haldevice.haldevicename + " Cool", haldevice.halname, "thermo", "halThermoSet", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetCool", haldevice.haldevicename + " Cool", haldevice.halname, "thermo", "halThermoSet", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALAutoUrls = function (haldevice) {
|
$scope.buildHALAutoUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress
|
onpayload = "http://" + haldevice.haladdress
|
||||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||||
@@ -1768,11 +1907,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
+ "!HVACMode=Off?Token="
|
+ "!HVACMode=Off?Token="
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetAuto", haldevice.haldevicename + " Auto", haldevice.halname, "thermo", "halThermoSet", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetAuto", haldevice.haldevicename + " Auto", haldevice.halname, "thermo", "halThermoSet", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALOffUrls = function (haldevice) {
|
$scope.buildHALOffUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress
|
onpayload = "http://" + haldevice.haladdress
|
||||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||||
@@ -1785,11 +1926,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
$scope.device.offUrl = "http://" + haldevice.haladdress
|
$scope.device.offUrl = "http://" + haldevice.haladdress
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-TurnOff", haldevice.haldevicename + " Thermostat", haldevice.halname, "thermo", "halThermoSet", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-TurnOff", haldevice.haldevicename + " Thermostat", haldevice.halname, "thermo", "halThermoSet", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildHALFanUrls = function (haldevice) {
|
$scope.buildHALFanUrls = function (haldevice, buildonly) {
|
||||||
onpayload = "http://" + haldevice.haladdress
|
onpayload = "http://" + haldevice.haladdress
|
||||||
+ "/HVACService!HVACCmd=Set!HVACName="
|
+ "/HVACService!HVACCmd=Set!HVACName="
|
||||||
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
+ haldevice.haldevicename.replaceAll(" ", "%20")
|
||||||
@@ -1802,21 +1945,24 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
+ $scope.bridge.settings.haltoken;
|
+ $scope.bridge.settings.haltoken;
|
||||||
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetFan", haldevice.haldevicename + " Fan", haldevice.halname, "thermo", "halThermoSet", null, null);
|
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetFan", haldevice.haldevicename + " Fan", haldevice.halname, "thermo", "halThermoSet", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.bulkAddDevices = function(dim_control) {
|
$scope.bulkAddDevices = function(dim_control) {
|
||||||
var devicesList = [];
|
var devicesList = [];
|
||||||
|
$scope.clearDevice();
|
||||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||||
if(bridgeService.state.haldevices[x].haldevicename === $scope.bulk.devices[i]) {
|
if(bridgeService.state.haldevices[x].haldevicename === $scope.bulk.devices[i]) {
|
||||||
if(bridgeService.state.haldevices[x].haldevicetype === "HVAC")
|
if(bridgeService.state.haldevices[x].haldevicetype === "HVAC")
|
||||||
$scope.buildHALAutoUrls(bridgeService.state.haldevices[x]);
|
$scope.buildHALAutoUrls(bridgeService.state.haldevices[x], true);
|
||||||
else if(bridgeService.state.haldevices[x].haldevicetype === "HOME")
|
else if(bridgeService.state.haldevices[x].haldevicetype === "HOME")
|
||||||
$scope.buildHALHomeUrls(bridgeService.state.haldevices[x]);
|
$scope.buildHALHomeUrls(bridgeService.state.haldevices[x], true);
|
||||||
else
|
else
|
||||||
$scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control);
|
$scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control, true);
|
||||||
devicesList[i] = {
|
devicesList[i] = {
|
||||||
name: $scope.device.name,
|
name: $scope.device.name,
|
||||||
mapId: $scope.device.mapId,
|
mapId: $scope.device.mapId,
|
||||||
@@ -1833,6 +1979,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
contentBodyDim: $scope.device.contentBodyDim,
|
contentBodyDim: $scope.device.contentBodyDim,
|
||||||
contentBodyOff: $scope.device.contentBodyOff
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
};
|
};
|
||||||
|
$scope.clearDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1875,7 +2022,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
|||||||
else {
|
else {
|
||||||
$scope.selectAll = true;
|
$scope.selectAll = true;
|
||||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||||
if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
|
if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0)
|
||||||
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
|
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1964,77 +2111,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
|||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildDeviceUrls = function (hassdevice, dim_control) {
|
$scope.buildDeviceUrls = function (hassdevice, dim_control, buildonly) {
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
|
||||||
else
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
|
|
||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
|
||||||
$scope.device = bridgeService.state.device;
|
|
||||||
bridgeService.editNewDevice($scope.device);
|
|
||||||
$location.path('/editdevice');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.buildHassHeatUrls = function (hassdevice) {
|
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
|
||||||
else
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
|
|
||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
|
||||||
$scope.device = bridgeService.state.device;
|
|
||||||
bridgeService.editNewDevice($scope.device);
|
|
||||||
$location.path('/editdevice');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.buildHassCoolUrls = function (hassdevice) {
|
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
|
||||||
else
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
|
|
||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
|
||||||
$scope.device = bridgeService.state.device;
|
|
||||||
bridgeService.editNewDevice($scope.device);
|
|
||||||
$location.path('/editdevice');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.buildHassAutoUrls = function (hassdevice) {
|
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
|
||||||
else
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
|
|
||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
|
||||||
$scope.device = bridgeService.state.device;
|
|
||||||
bridgeService.editNewDevice($scope.device);
|
|
||||||
$location.path('/editdevice');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.buildHassOffUrls = function (hassdevice) {
|
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
|
||||||
else
|
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
|
||||||
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
|
|
||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
|
||||||
$scope.device = bridgeService.state.device;
|
|
||||||
bridgeService.editNewDevice($scope.device);
|
|
||||||
$location.path('/editdevice');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.buildHassFanUrls = function (hassdevice) {
|
|
||||||
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
|
||||||
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
|
||||||
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
|
||||||
@@ -2044,19 +2121,19 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
|||||||
|
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.bulkAddDevices = function(dim_control) {
|
$scope.bulkAddDevices = function(dim_control) {
|
||||||
var devicesList = [];
|
var devicesList = [];
|
||||||
|
$scope.clearDevice();
|
||||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
for(var x = 0; x < bridgeService.state.hassdevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.hassdevices.length; x++) {
|
||||||
if(bridgeService.state.hassdevices[x].deviceName === $scope.bulk.devices[i]) {
|
if(bridgeService.state.hassdevices[x].deviceState.entity_id === $scope.bulk.devices[i] && bridgeService.state.hassdevices[x].domain !== "sensor" && bridgeService.state.hassdevices[x].domain !== "sun") {
|
||||||
if(bridgeService.state.hassdevices[x].domain === "climate")
|
$scope.buildDeviceUrls(bridgeService.state.hassdevices[x],dim_control,true);
|
||||||
$scope.buildHassAutoUrls(bridgeService.state.hassdevices[x]);
|
|
||||||
else
|
|
||||||
$scope.buildDeviceUrls(bridgeService.state.hassdevices[x],dim_control);
|
|
||||||
devicesList[i] = {
|
devicesList[i] = {
|
||||||
name: $scope.device.name,
|
name: $scope.device.name,
|
||||||
mapId: $scope.device.mapId,
|
mapId: $scope.device.mapId,
|
||||||
@@ -2073,6 +2150,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
|||||||
contentBodyDim: $scope.device.contentBodyDim,
|
contentBodyDim: $scope.device.contentBodyDim,
|
||||||
contentBodyOff: $scope.device.contentBodyOff
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
};
|
};
|
||||||
|
$scope.clearDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2080,7 +2158,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
|||||||
function () {
|
function () {
|
||||||
$scope.clearDevice();
|
$scope.clearDevice();
|
||||||
bridgeService.viewDevices();
|
bridgeService.viewDevices();
|
||||||
bridgeService.viewhassdevices();
|
bridgeService.viewHassDevices();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
bridgeService.displayWarn("Error adding Hass devices in bulk.", error)
|
bridgeService.displayWarn("Error adding Hass devices in bulk.", error)
|
||||||
@@ -2115,8 +2193,8 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
|||||||
else {
|
else {
|
||||||
$scope.selectAll = true;
|
$scope.selectAll = true;
|
||||||
for(var x = 0; x < bridgeService.state.hassdevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.hassdevices.length; x++) {
|
||||||
if($scope.bulk.devices.indexOf(bridgeService.state.hassdevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.hassdevices[x].hassdevicename + "-" + bridgeService.state.hassdevices[x].halname, bridgeService.state.hassdevices[x].halname, "hassdevice"))
|
if($scope.bulk.devices.indexOf(bridgeService.state.hassdevices[x].deviceState.entity_id) < 0 && bridgeService.state.hassdevices[x].domain !== "sensor" && bridgeService.state.hassdevices[x].domain !== "sun")
|
||||||
$scope.bulk.devices.push(bridgeService.state.hassdevices[x].hassdevicename);
|
$scope.bulk.devices.push(bridgeService.state.hassdevices[x].deviceState.entity_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2159,7 +2237,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
|||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.buildDeviceUrls = function (domoticzdevice, dim_control) {
|
$scope.buildDeviceUrls = function (domoticzdevice, dim_control, buildonly) {
|
||||||
var preCmd = "";
|
var preCmd = "";
|
||||||
var postOnCmd = "";
|
var postOnCmd = "";
|
||||||
var postDimCmd = "";
|
var postDimCmd = "";
|
||||||
@@ -2198,16 +2276,19 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
|||||||
+ postOffCmd;
|
+ postOffCmd;
|
||||||
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, domoticzdevice.devicename + "-" + domoticzdevice.domoticzname, domoticzdevice.devicename, domoticzdevice.domoticzname, aDeviceType, "domoticzDevice", null, null);
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, domoticzdevice.devicename + "-" + domoticzdevice.domoticzname, domoticzdevice.devicename, domoticzdevice.domoticzname, aDeviceType, "domoticzDevice", null, null);
|
||||||
$scope.device = bridgeService.state.device;
|
$scope.device = bridgeService.state.device;
|
||||||
|
if (!buildonly) {
|
||||||
bridgeService.editNewDevice($scope.device);
|
bridgeService.editNewDevice($scope.device);
|
||||||
$location.path('/editdevice');
|
$location.path('/editdevice');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.bulkAddDevices = function(dim_control) {
|
$scope.bulkAddDevices = function(dim_control) {
|
||||||
var devicesList = [];
|
var devicesList = [];
|
||||||
|
$scope.clearDevice();
|
||||||
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
for(var x = 0; x < bridgeService.state.domoticzdevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.domoticzdevices.length; x++) {
|
||||||
if(bridgeService.state.domoticzdevices[x].devicename === $scope.bulk.devices[i]) {
|
if(bridgeService.state.domoticzdevices[x].devicename === $scope.bulk.devices[i]) {
|
||||||
$scope.buildDeviceUrls(bridgeService.state.domoticzdevices[x],dim_control);
|
$scope.buildDeviceUrls(bridgeService.state.domoticzdevices[x],dim_control,true);
|
||||||
devicesList[i] = {
|
devicesList[i] = {
|
||||||
name: $scope.device.name,
|
name: $scope.device.name,
|
||||||
mapId: $scope.device.mapId,
|
mapId: $scope.device.mapId,
|
||||||
@@ -2224,6 +2305,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
|||||||
contentBodyDim: $scope.device.contentBodyDim,
|
contentBodyDim: $scope.device.contentBodyDim,
|
||||||
contentBodyOff: $scope.device.contentBodyOff
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
};
|
};
|
||||||
|
$scope.clearDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2234,7 +2316,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
|||||||
bridgeService.viewHalDevices();
|
bridgeService.viewHalDevices();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
bridgeService.displayWarn("Error adding HAL devices in bulk.", error)
|
bridgeService.displayWarn("Error adding Domoticz devices in bulk.", error)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$scope.bulk = { devices: [] };
|
$scope.bulk = { devices: [] };
|
||||||
@@ -2266,8 +2348,258 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
|||||||
else {
|
else {
|
||||||
$scope.selectAll = true;
|
$scope.selectAll = true;
|
||||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||||
if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
|
if($scope.bulk.devices.indexOf(bridgeService.state.domoticzdevices[x]) < 0)
|
||||||
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
|
$scope.bulk.devices.push(bridgeService.state.domoticzdevices[x].devicename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$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('LifxController', 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;
|
||||||
|
bridgeService.viewLifxDevices();
|
||||||
|
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||||
|
$scope.buttonsVisible = false;
|
||||||
|
|
||||||
|
$scope.clearDevice = function () {
|
||||||
|
bridgeService.clearDevice();
|
||||||
|
$scope.device = bridgeService.state.device;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.buildDeviceUrls = function (lifxdevice, dim_control, buildonly) {
|
||||||
|
dimpayload = angular.toJson(lifxdevice);
|
||||||
|
onpayload = angular.toJson(lifxdevice);
|
||||||
|
offpayload = angular.toJson(lifxdevice);
|
||||||
|
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, lifxdevice.name, lifxdevice.name, lifxdevice.name, null, "lifxDevice", 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.lifxdevices.length; x++) {
|
||||||
|
if(bridgeService.state.lifxdevices[x].devicename === $scope.bulk.devices[i]) {
|
||||||
|
$scope.buildDeviceUrls(bridgeService.state.lifxdevices[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.viewHalDevices();
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
bridgeService.displayWarn("Error adding LIFX devices in bulk.", error)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$scope.bulk = { devices: [] };
|
||||||
|
$scope.selectAll = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleSelection = function toggleSelection(deviceId) {
|
||||||
|
var idx = $scope.bulk.devices.indexOf(deviceId);
|
||||||
|
|
||||||
|
// is currently selected
|
||||||
|
if (idx > -1) {
|
||||||
|
$scope.bulk.devices.splice(idx, 1);
|
||||||
|
if($scope.bulk.devices.length === 0 && $scope.selectAll)
|
||||||
|
$scope.selectAll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is newly selected
|
||||||
|
else {
|
||||||
|
$scope.bulk.devices.push(deviceId);
|
||||||
|
$scope.selectAll = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleSelectAll = function toggleSelectAll() {
|
||||||
|
if($scope.selectAll) {
|
||||||
|
$scope.selectAll = false;
|
||||||
|
$scope.bulk = { devices: [] };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$scope.selectAll = true;
|
||||||
|
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||||
|
if($scope.bulk.devices.indexOf(bridgeService.state.lifxdevices[x]) < 0)
|
||||||
|
$scope.bulk.devices.push(bridgeService.state.lifxdevices[x].devicename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$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('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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2342,20 +2674,28 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
|||||||
bridgeService.displayWarn("Error adding device. Name has not been changed from original.", null);
|
bridgeService.displayWarn("Error adding device. Name has not been changed from original.", null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (copy)
|
if (copy) {
|
||||||
$scope.device.id = null;
|
$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)
|
if($scope.mapTypeSelected !== undefined && $scope.mapTypeSelected !== null)
|
||||||
$scope.device.mapType = $scope.mapTypeSelected[0];
|
$scope.device.mapType = $scope.mapTypeSelected[0];
|
||||||
else
|
else
|
||||||
$scope.device.mapType = null;
|
$scope.device.mapType = null;
|
||||||
|
|
||||||
if ($scope.onDevices !== null)
|
if ($scope.onDevices !== null)
|
||||||
$scope.device.onUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices));
|
$scope.device.onUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices));
|
||||||
if ($scope.dimDevices !== null)
|
if ($scope.dimDevices !== null)
|
||||||
$scope.device.dimUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices));
|
$scope.device.dimUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices));
|
||||||
if ($scope.offDevices !== null)
|
if ($scope.offDevices !== null)
|
||||||
$scope.device.offUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices));
|
$scope.device.offUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices));
|
||||||
|
|
||||||
bridgeService.addDevice($scope.device).then(
|
bridgeService.addDevice($scope.device).then(
|
||||||
function () {
|
function () {
|
||||||
|
bridgeService.state.queueDevId = $scope.device.id;
|
||||||
|
console.log("Device updated for Q Id <<" + bridgeService.state.queueDevId + ">>")
|
||||||
$scope.clearDevice();
|
$scope.clearDevice();
|
||||||
$location.path('/');
|
$location.path('/');
|
||||||
},
|
},
|
||||||
@@ -2373,7 +2713,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
|||||||
if ($scope.onDevices === null)
|
if ($scope.onDevices === null)
|
||||||
$scope.onDevices = [];
|
$scope.onDevices = [];
|
||||||
$scope.onDevices.push(newitem);
|
$scope.onDevices.push(newitem);
|
||||||
$scope.newOnItem = [];
|
$scope.newOnItem = {};
|
||||||
};
|
};
|
||||||
$scope.removeItemOn = function (anItem) {
|
$scope.removeItemOn = function (anItem) {
|
||||||
for(var i = $scope.onDevices.length - 1; i >= 0; i--) {
|
for(var i = $scope.onDevices.length - 1; i >= 0; i--) {
|
||||||
@@ -2390,7 +2730,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
|||||||
if ($scope.dimDevices === null)
|
if ($scope.dimDevices === null)
|
||||||
$scope.dimDevices = [];
|
$scope.dimDevices = [];
|
||||||
$scope.dimDevices.push(newitem);
|
$scope.dimDevices.push(newitem);
|
||||||
$scope.newDimItem = [];
|
$scope.newDimItem = {};
|
||||||
};
|
};
|
||||||
$scope.removeItemDim = function (anItem) {
|
$scope.removeItemDim = function (anItem) {
|
||||||
for(var i = $scope.dimDevices.length - 1; i >= 0; i--) {
|
for(var i = $scope.dimDevices.length - 1; i >= 0; i--) {
|
||||||
@@ -2407,7 +2747,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
|||||||
if ($scope.offDevices === null)
|
if ($scope.offDevices === null)
|
||||||
$scope.offDevices = [];
|
$scope.offDevices = [];
|
||||||
$scope.offDevices.push(newitem);
|
$scope.offDevices.push(newitem);
|
||||||
$scope.newOffItem = [];
|
$scope.newOffItem = {};
|
||||||
};
|
};
|
||||||
$scope.removeItemOff = function (anItem) {
|
$scope.removeItemOff = function (anItem) {
|
||||||
for(var i = $scope.offDevices.length - 1; i >= 0; i--) {
|
for(var i = $scope.offDevices.length - 1; i >= 0; i--) {
|
||||||
@@ -2566,6 +2906,37 @@ app.filter('configuredDomoticzItems', function (bridgeService) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.filter('configuredLifxItems', 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], "lifx")) {
|
||||||
|
out.push(input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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) {
|
app.controller('VersionController', function ($scope, bridgeService) {
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
});
|
});
|
||||||
@@ -20,9 +20,11 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div postrender-action="goToRow()">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h1 class="panel-title">Current devices ({{bridge.devices.length}})</h1>
|
<h1 class="panel-title">Current devices ({{bridge.devices.length}})</h1>
|
||||||
@@ -32,7 +34,6 @@
|
|||||||
<p>
|
<p>
|
||||||
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
|
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<scrollable-table watch="bridge.devices">
|
<scrollable-table watch="bridge.devices">
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
<th>Row</th>
|
<th>Row</th>
|
||||||
<th sortable-header col="id" comparator-fn="comparatorUniqueId">ID</th>
|
<th sortable-header col="id" comparator-fn="comparatorUniqueId">ID</th>
|
||||||
<th sortable-header col="name">Name</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="deviceType">Type</th>
|
||||||
<th sortable-header col="targetDevice">Target</th>
|
<th sortable-header col="targetDevice">Target</th>
|
||||||
<th sortable-header col="inactive">Inactive</th>
|
<th sortable-header col="inactive">Inactive</th>
|
||||||
@@ -47,10 +49,11 @@
|
|||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="device in bridge.devices">
|
<tr ng-repeat="device in bridge.devices" row-id="{{device.id}}" ng-class="{info: bridge.viewDevId == device.id}" >
|
||||||
<td>{{$index+1}}</td>
|
<td>{{$index+1}}</td>
|
||||||
<td>{{device.id}}</td>
|
<td>{{device.id}}</td>
|
||||||
<td>{{device.name}}</td>
|
<td>{{device.name}}</td>
|
||||||
|
<td class="cr">{{device.description}}</td>
|
||||||
<td>{{device.deviceType}}</td>
|
<td>{{device.deviceType}}</td>
|
||||||
<td>{{device.targetDevice}}</td>
|
<td>{{device.targetDevice}}</td>
|
||||||
<td>{{device.inactive}}</td>
|
<td>{{device.inactive}}</td>
|
||||||
@@ -74,6 +77,7 @@
|
|||||||
</scrollable-table>
|
</scrollable-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h1 class="panel-title">
|
<h1 class="panel-title">
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
|
||||||
<li role="presentation" class="active"><a href="#!/domoticzdevices">Domoticz 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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -35,17 +37,18 @@
|
|||||||
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
||||||
setup. The 'Already Configured Domoticz Devices' list below will show what
|
setup. The 'Already Configured Domoticz Devices' list below will show what
|
||||||
is already setup for your Domoticz.</p>
|
is already setup for your Domoticz.</p>
|
||||||
<p>
|
<p class="text-muted">
|
||||||
Also, use this select menu for which type of dim control you would
|
Also, use this select menu for which type of dim control you would
|
||||||
like to be generated: <select name="device-dim-control"
|
like to be generated: <select name="device-dim-control"
|
||||||
id="device-dim-control" ng-model="device_dim_control">
|
id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
<option value="${intensity.byte}">Pass-thru Value</option>
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
<option value="${intensity.percent}">Percentage</option>
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
|
||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p>Use the check boxes by the names to use the bulk addition
|
<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
|
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
|
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 Domoticz.</p>
|
off if selected with the name of the device from the Domoticz.</p>
|
||||||
@@ -75,7 +78,7 @@
|
|||||||
<td>{{domoticzdevice.domoticzname}}</td>
|
<td>{{domoticzdevice.domoticzname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(domoticzdevice, device_dim_control)">Build Item</button>
|
ng-click="buildDeviceUrls(domoticzdevice, device_dim_control,false)">Build Item</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
<li ng-if="bridge.showHass" role="presentation"><a
|
<li ng-if="bridge.showHass" role="presentation"><a
|
||||||
href="#!/hassdevices">HomeAssistant Devices</a></li>
|
href="#!/hassdevices">HomeAssistant Devices</a></li>
|
||||||
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz 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>
|
<li role="presentation" class="active"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@
|
|||||||
fields the bridge uses. Please use care when updating these fields as
|
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
|
you may break the settings used by the bridge to call a specific end
|
||||||
point device.</p>
|
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
|
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
|
http verb type below and configure a payload for either on, dim or
|
||||||
off methods. For Execution of a
|
off methods. For Execution of a
|
||||||
@@ -40,10 +42,10 @@
|
|||||||
can use Json notation of array with [{"item":"the
|
can use Json notation of array with [{"item":"the
|
||||||
payload"},{"item":"another payload"}] to
|
payload"},{"item":"another payload"}] to
|
||||||
execute multiple entries. Adding the value replacements
|
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
|
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>
|
action button to add another item for a multi-command.</p>
|
||||||
<p>When copying, update the name and select the "Add Bridge
|
<p class="text-muted">When copying, update the name and select the "Add Bridge
|
||||||
Device" Button.</p>
|
Device" Button.</p>
|
||||||
|
|
||||||
<form name="form">
|
<form name="form">
|
||||||
@@ -64,17 +66,40 @@
|
|||||||
ng-model="device.name" placeholder="Device Name"></td>
|
ng-model="device.name" placeholder="Device Name"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<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"
|
<td><input type="checkbox"
|
||||||
ng-model="device.inactive" ng-true-value=true
|
ng-model="device.inactive" ng-true-value=true
|
||||||
ng-false-value=false> {{device.inactive}}</td>
|
ng-false-value=false> {{device.inactive}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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"
|
<td><input type="checkbox"
|
||||||
ng-model="device.noState" ng-true-value=true
|
ng-model="device.noState" ng-true-value=true
|
||||||
ng-false-value=false> {{device.noState}}</td>
|
ng-false-value=false> {{device.noState}}</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td><label>Target</label></td>
|
<td><label>Target</label></td>
|
||||||
|
|
||||||
@@ -129,6 +154,7 @@
|
|||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Target Item</th>
|
<th>Target Item</th>
|
||||||
<th>Delay</th>
|
<th>Delay</th>
|
||||||
@@ -139,19 +165,21 @@
|
|||||||
<th>Http Headers</th>
|
<th>Http Headers</th>
|
||||||
<th>Content Type</th>
|
<th>Content Type</th>
|
||||||
<th>Manage</th>
|
<th>Manage</th>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="onItem in onDevices">
|
<tr ng-repeat="onItem in onDevices">
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="onItem.type"></select></td>
|
ng-model="onItem.type"></select></td>
|
||||||
<td><textarea rows="1" cols="20" class="form-control"
|
<td><textarea rows="1" class="form-control"
|
||||||
id="item-target" ng-model="onItem.item" placeholder="The Call"></textarea></td>
|
id="item-target" ng-model="onItem.item" placeholder="The Call"></textarea></td>
|
||||||
<td><textarea rows="1" cols="4" class="form-control"
|
<td><textarea rows="1" class="form-control"
|
||||||
id="item-delay" ng-model="onItem.delay" placeholder="millis"></textarea></td>
|
id="item-delay" ng-model="onItem.delay" placeholder="millis"></textarea></td>
|
||||||
<td><textarea rows="1" cols="2" class="form-control"
|
<td><textarea rows="1" class="form-control"
|
||||||
id="item-count" ng-model="onItem.count" placeholder="number"></textarea></td>
|
id="item-count" ng-model="onItem.count" placeholder="number"></textarea></td>
|
||||||
<td><textarea rows="1" cols="16" class="form-control"
|
<td><textarea rows="1" class="form-control"
|
||||||
id="item-filterIPs" ng-model="onItem.filterIPs"
|
id="item-filterIPs" ng-model="onItem.filterIPs"
|
||||||
placeholder="restrict IPs"></textarea></td>
|
placeholder="restrict IPs"></textarea></td>
|
||||||
<td><select name="item-http-verb" id="item-http-verb"
|
<td><select name="item-http-verb" id="item-http-verb"
|
||||||
@@ -162,7 +190,7 @@
|
|||||||
<option value="PUT">PUT</option>
|
<option value="PUT">PUT</option>
|
||||||
<option value="POST">POST</option>
|
<option value="POST">POST</option>
|
||||||
</select></td>
|
</select></td>
|
||||||
<td><textarea rows="1" cols="16" class="form-control"
|
<td><textarea rows="1" class="form-control"
|
||||||
id="item-httpBody" ng-model="onItem.httpBody"
|
id="item-httpBody" ng-model="onItem.httpBody"
|
||||||
placeholder="body args"></textarea></td>
|
placeholder="body args"></textarea></td>
|
||||||
<td><textarea rows="1" cols="16" class="form-control"
|
<td><textarea rows="1" cols="16" class="form-control"
|
||||||
@@ -188,8 +216,10 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-danger" type="submit"
|
<td><button class="btn btn-danger" type="submit"
|
||||||
ng-click="removeItemOn(onItem)">Del</button></td>
|
ng-click="removeItemOn(onItem)">Del</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="newOnItem.type"></select></td>
|
ng-model="newOnItem.type"></select></td>
|
||||||
@@ -239,6 +269,7 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-success" type="submit"
|
<td><button class="btn btn-success" type="submit"
|
||||||
ng-click="addItemOn(newOnItem)">Add</button></td>
|
ng-click="addItemOn(newOnItem)">Add</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</scrollable-table></td>
|
</scrollable-table></td>
|
||||||
@@ -250,6 +281,7 @@
|
|||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Target Item</th>
|
<th>Target Item</th>
|
||||||
<th>Delay</th>
|
<th>Delay</th>
|
||||||
@@ -260,9 +292,11 @@
|
|||||||
<th>Http Headers</th>
|
<th>Http Headers</th>
|
||||||
<th>Content Type</th>
|
<th>Content Type</th>
|
||||||
<th>Manage</th>
|
<th>Manage</th>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="dimItem in dimDevices">
|
<tr ng-repeat="dimItem in dimDevices">
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="dimItem.type"></select></td>
|
ng-model="dimItem.type"></select></td>
|
||||||
@@ -310,8 +344,10 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-danger" type="submit"
|
<td><button class="btn btn-danger" type="submit"
|
||||||
ng-click="removeItemDim(dimItem)">Del</button></td>
|
ng-click="removeItemDim(dimItem)">Del</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="newDimItem.type"></select></td>
|
ng-model="newDimItem.type"></select></td>
|
||||||
@@ -361,6 +397,7 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-success" type="submit"
|
<td><button class="btn btn-success" type="submit"
|
||||||
ng-click="addItemDim(newDimItem)">Add</button></td>
|
ng-click="addItemDim(newDimItem)">Add</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</scrollable-table></td>
|
</scrollable-table></td>
|
||||||
@@ -372,6 +409,7 @@
|
|||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Target Item</th>
|
<th>Target Item</th>
|
||||||
<th>Delay</th>
|
<th>Delay</th>
|
||||||
@@ -382,9 +420,11 @@
|
|||||||
<th>Http Headers</th>
|
<th>Http Headers</th>
|
||||||
<th>Content Type</th>
|
<th>Content Type</th>
|
||||||
<th>Manage</th>
|
<th>Manage</th>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="offItem in offDevices">
|
<tr ng-repeat="offItem in offDevices">
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="offItem.type"></select></td>
|
ng-model="offItem.type"></select></td>
|
||||||
@@ -432,8 +472,10 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-danger" type="submit"
|
<td><button class="btn btn-danger" type="submit"
|
||||||
ng-click="removeItemOff(offItem)">Del</button></td>
|
ng-click="removeItemOff(offItem)">Del</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
<td><select
|
<td><select
|
||||||
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
|
||||||
ng-model="newOffItem.type"></select></td>
|
ng-model="newOffItem.type"></select></td>
|
||||||
@@ -483,6 +525,7 @@
|
|||||||
</select></td>
|
</select></td>
|
||||||
<td><button class="btn btn-success" type="submit"
|
<td><button class="btn btn-success" type="submit"
|
||||||
ng-click="addItemOff(newOffItem)">Add</button></td>
|
ng-click="addItemOff(newOffItem)">Add</button></td>
|
||||||
|
</div>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</scrollable-table></td>
|
</scrollable-table></td>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -34,17 +36,18 @@
|
|||||||
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
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
|
setup. The 'Already Configured HAL Devices' list below will show what
|
||||||
is already setup for your HAL.</p>
|
is already setup for your HAL.</p>
|
||||||
<p>
|
<p class="text-muted">
|
||||||
Also, use this select menu for which type of dim control you would
|
Also, use this select menu for which type of dim control you would
|
||||||
like to be generated: <select name="device-dim-control"
|
like to be generated: <select name="device-dim-control"
|
||||||
id="device-dim-control" ng-model="device_dim_control">
|
id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
<option value="${intensity.byte}">Pass-thru Value</option>
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
<option value="${intensity.percent}">Percentage</option>
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
|
||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p>Use the check boxes by the names to use the bulk addition
|
<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
|
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
|
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>
|
off if selected with the name of the device from the HAL.</p>
|
||||||
@@ -88,27 +91,27 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button ng-if="haldevice.haldevicetype != 'Home' && haldevice.haldevicetype != 'HVAC' && haldevice.haldevicetype != 'IrData'" class="btn btn-success" type="submit"
|
<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)">Build Item</button>
|
ng-click="buildDeviceUrls(haldevice, device_dim_control, false)">Build Item</button>
|
||||||
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
|
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALHomeUrls(haldevice)">Build Home/Away</button>
|
ng-click="buildHALHomeUrls(haldevice, false)">Build Home/Away</button>
|
||||||
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
|
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
|
||||||
ng-click="buildButtonUrls(haldevice, button_on, button_off)">Build
|
ng-click="buildButtonUrls(haldevice, button_on, button_off, false)">Build
|
||||||
A Button</button>
|
A Button</button>
|
||||||
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
|
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<p>
|
<p>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALHeatUrls(haldevice)">Heat</button>
|
ng-click="buildHALHeatUrls(haldevice, false)">Heat</button>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALCoolUrls(haldevice)">Cool</button>
|
ng-click="buildHALCoolUrls(haldevice, false)">Cool</button>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALAutoUrls(haldevice)">Auto</button>
|
ng-click="buildHALAutoUrls(haldevice, false)">Auto</button>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALOffUrls(haldevice)">Off</button>
|
ng-click="buildHALOffUrls(haldevice, false)">Off</button>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildHALFanUrls(haldevice)">Fan</button>
|
ng-click="buildHALFanUrls(haldevice, false)">Fan</button>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,13 @@
|
|||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
|
||||||
<li ng-if="bridge.showHue" role="presentation"><a
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
href="#!/huedevices">Hue Devices</a></li>
|
href="#!/huedevices">Hue Devices</a></li>
|
||||||
<li ng-if="bridge.showHal" role="presentation" class="active"><a href="#!/haldevices">HAL
|
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL
|
||||||
Devices</a></li>
|
Devices</a></li>
|
||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
|
<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 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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -35,17 +37,18 @@
|
|||||||
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
||||||
setup. The 'Already Configured HomeAssistant Devices' list below will show what
|
setup. The 'Already Configured HomeAssistant Devices' list below will show what
|
||||||
is already setup for your HomeAssitant.</p>
|
is already setup for your HomeAssitant.</p>
|
||||||
<p>
|
<p class="text-muted">
|
||||||
Also, use this select menu for which type of dim control you would
|
Also, use this select menu for which type of dim control you would
|
||||||
like to be generated, BUT for Home Assistant, the selection should be Pass-thru: <select name="device-dim-control"
|
like to be generated, BUT for Home Assistant, the selection should be Pass-thru: <select name="device-dim-control"
|
||||||
id="device-dim-control" ng-model="device_dim_control">
|
id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
<option value="${intensity.byte}">Pass-thru Value</option>
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
<option value="${intensity.percent}">Percentage</option>
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
|
||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p>Use the check boxes by the names to use the bulk addition
|
<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
|
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
|
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 HomeAssitant.</p>
|
off if selected with the name of the device from the HomeAssitant.</p>
|
||||||
@@ -72,26 +75,8 @@
|
|||||||
{{hassdevice.deviceState.entity_id}}</td>
|
{{hassdevice.deviceState.entity_id}}</td>
|
||||||
<td>{{hassdevice.hassname}}</td>
|
<td>{{hassdevice.hassname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button ng-if="hassdevice.domain != 'climate' && hassdevice.domain != 'sensor' && hassdevice.domain != 'sun'" class="btn btn-success" type="submit"
|
<button ng-if="hassdevice.domain != 'sensor' && hassdevice.domain != 'sun'" class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(hassdevice, device_dim_control)">Build Item</button>
|
ng-click="buildDeviceUrls(hassdevice, device_dim_control, false)">Build Item</button>
|
||||||
<ul ng-if="hassdevice.domain == 'climate'" class="list-group">
|
|
||||||
<li class="list-group-item">
|
|
||||||
<p>
|
|
||||||
<button class="btn btn-success" type="submit"
|
|
||||||
ng-click="buildhassHeatUrls(hassdevice)">Heat</button>
|
|
||||||
<button class="btn btn-success" type="submit"
|
|
||||||
ng-click="buildhassCoolUrls(hassdevice)">Cool</button>
|
|
||||||
<button class="btn btn-success" type="submit"
|
|
||||||
ng-click="buildhassAutoUrls(hassdevice)">Auto</button>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<button class="btn btn-success" type="submit"
|
|
||||||
ng-click="buildhassOffUrls(hassdevice)">Off</button>
|
|
||||||
<button class="btn btn-success" type="submit"
|
|
||||||
ng-click="buildhassFanUrls(hassdevice)">Fan</button>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -35,9 +37,9 @@
|
|||||||
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
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
|
setup. The 'Already Configured Hue Devices' list below will show what
|
||||||
is already setup for your Hue.</p>
|
is already setup for your Hue.</p>
|
||||||
<p>Use the check boxes by the names to use the bulk addition
|
<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
|
feature. Select your items, then click bulk add below. Your items
|
||||||
will be added with on and off or dim and off if selected with the
|
will be added with on, off and dim with the
|
||||||
name of the device from the Hue.</p>
|
name of the device from the Hue.</p>
|
||||||
<scrollable-table watch="bridge.huedevices">
|
<scrollable-table watch="bridge.huedevices">
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
@@ -64,7 +66,7 @@
|
|||||||
<td>{{huedevice.huename}}</td>
|
<td>{{huedevice.huename}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(huedevice)">Build Item</button>
|
ng-click="buildDeviceUrls(huedevice, false)">Build Item</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
123
src/main/resources/public/views/lifxdevice.html
Normal file
123
src/main/resources/public/views/lifxdevice.html
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#!/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
|
||||||
|
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
|
||||||
|
<li 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>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">LIFX Devices</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any LIFX 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 LIFX Devices' list below will show what
|
||||||
|
is already setup for your LIFX.</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, off and dim
|
||||||
|
with the name of the device from the LIFX device.</p>
|
||||||
|
<scrollable-table watch="bridge.lifxdevices">
|
||||||
|
<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="type">Type</th>
|
||||||
|
<th>Build Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="lifxdev in bridge.lifxdevices">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td><input type="checkbox" name="bulk.devices[]"
|
||||||
|
value="{{lifxdev.name}}"
|
||||||
|
ng-checked="bulk.devices.indexOf(lifxdev.name) > -1"
|
||||||
|
ng-click="toggleSelection(lifxdev.name)">{{lifxdev.name}}</td>
|
||||||
|
<td>{{lifxdev.id}}</td>
|
||||||
|
<td>{{lifxdev.type}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildDeviceUrls(lifxdev, 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 LIFX 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.lifxdevices">
|
||||||
|
<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">Light Name</th>
|
||||||
|
<th>Map Id</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="device in bridge.devices | configuredLifxItems | 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>
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
<li role="presentation" class="active"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
143
src/main/resources/public/views/somfydevice.html
Normal file
143
src/main/resources/public/views/somfydevice.html
Normal 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>
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -141,14 +143,16 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>IP</th>
|
<th>IP</th>
|
||||||
|
<th>Webhook</th>
|
||||||
<th>Manage</th>
|
<th>Manage</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="harmony in bridge.settings.harmonyaddress.devices">
|
<tr ng-repeat="harmony in bridge.settings.harmonyaddress.devices">
|
||||||
<td>{{harmony.name}}</td>
|
<td>{{harmony.name}}</td>
|
||||||
<td>{{harmony.ip}}</td>
|
<td>{{harmony.ip}}</td>
|
||||||
|
<td>{{harmony.webhook}}</td>
|
||||||
<td><button class="btn btn-danger" type="submit"
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input id="bridge-settings-next-harmony-name"
|
<td><input id="bridge-settings-next-harmony-name"
|
||||||
@@ -157,8 +161,11 @@
|
|||||||
<td><input id="bridge-settings-next-harmony-ip"
|
<td><input id="bridge-settings-next-harmony-ip"
|
||||||
class="form-control" type="text" ng-model="newharmonyip"
|
class="form-control" type="text" ng-model="newharmonyip"
|
||||||
placeholder="192.168.1.3"></td>
|
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"
|
<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>
|
</tr>
|
||||||
</table></td>
|
</table></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -357,6 +364,46 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table></td>
|
</table></td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>Nest Username</td>
|
<td>Nest Username</td>
|
||||||
<td><input id="bridge-settings-nestuser" class="form-control"
|
<td><input id="bridge-settings-nestuser" class="form-control"
|
||||||
@@ -375,6 +422,12 @@
|
|||||||
ng-model="bridge.settings.farenheit" ng-true-value=true
|
ng-model="bridge.settings.farenheit" ng-true-value=true
|
||||||
ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>LIFX Support</td>
|
||||||
|
<td><input type="checkbox"
|
||||||
|
ng-model="bridge.settings.lifxconfigured" ng-true-value=true
|
||||||
|
ng-false-value=false> {{bridge.settings.lifxconfigured}}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Emulate Hue Hub Version</td>
|
<td>Emulate Hue Hub Version</td>
|
||||||
<td><input id="bridge-settings-hubversion" class="form-control"
|
<td><input id="bridge-settings-hubversion" class="form-control"
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -35,17 +37,18 @@
|
|||||||
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
done in the edit tab, click the 'Add Bridge Device' to finish that selection
|
||||||
setup. The 'Already Configured Vera Devices' list below will show
|
setup. The 'Already Configured Vera Devices' list below will show
|
||||||
what is already setup for your Vera.</p>
|
what is already setup for your Vera.</p>
|
||||||
<p>
|
<p class="text-muted">
|
||||||
Also, use this select menu for which type of dim control you would
|
Also, use this select menu for which type of dim control you would
|
||||||
like to be generated: <select name="device-dim-control"
|
like to be generated: <select name="device-dim-control"
|
||||||
id="device-dim-control" ng-model="device_dim_control">
|
id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
<option value="${intensity.byte}">Pass-thru Value</option>
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
<option value="${intensity.percent}">Percentage</option>
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
|
||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p>Use the check boxes by the names to use the bulk addition
|
<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
|
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
|
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>
|
off if selected with the name of the device from the Vera.</p>
|
||||||
@@ -79,7 +82,7 @@
|
|||||||
<td>{{veradevice.veraname}}</td>
|
<td>{{veradevice.veraname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Build Item</button>
|
ng-click="buildDeviceUrls(veradevice, device_dim_control, false)">Build Item</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</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.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.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>
|
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user