mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 16:41:53 +00:00
Compare commits
243 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9e9f16756 | ||
|
|
f15cc0d53a | ||
|
|
0f791c1e71 | ||
|
|
9887042f4d | ||
|
|
c840f2bc4d | ||
|
|
9a355b7906 | ||
|
|
0d568d8d68 | ||
|
|
f5e100667e | ||
|
|
c376253488 | ||
|
|
a3fd2ca722 | ||
|
|
fe4df16e10 | ||
|
|
9399af7ec7 | ||
|
|
be72f7e62c | ||
|
|
768eebfc78 | ||
|
|
79ce23b80a | ||
|
|
bddc7c1c31 | ||
|
|
51c6ffc48a | ||
|
|
ee4afc00c0 | ||
|
|
8b48f23741 | ||
|
|
87f79df8b1 | ||
|
|
1142704d22 | ||
|
|
d014240fba | ||
|
|
5c2d30e24b | ||
|
|
28d84f667a | ||
|
|
755533b30d | ||
|
|
53208ddabc | ||
|
|
ff2973e473 | ||
|
|
743656cab3 | ||
|
|
53be3ba213 | ||
|
|
a5ee0aafc8 | ||
|
|
aed8ffa8d3 | ||
|
|
369e5a25e6 | ||
|
|
3fe19f5d4e | ||
|
|
5736bb92db | ||
|
|
b61f334826 | ||
|
|
556a5fef1c | ||
|
|
4b0152060f | ||
|
|
fcb31b8f76 | ||
|
|
0205633684 | ||
|
|
7b48590807 | ||
|
|
5f7cd70710 | ||
|
|
46ad4489ad | ||
|
|
bfd1b94473 | ||
|
|
7d920d3885 | ||
|
|
2dbf4c96c4 | ||
|
|
69b510ae18 | ||
|
|
e86b700e93 | ||
|
|
a05b933e43 | ||
|
|
fe0b072b4e | ||
|
|
3e76e6298a | ||
|
|
f266945b7e | ||
|
|
2d3fac691b | ||
|
|
5f6bfae41a | ||
|
|
79d5b5da28 | ||
|
|
45e2b63f98 | ||
|
|
b6b9089ec4 | ||
|
|
063055f5c8 | ||
|
|
c1dc89704d | ||
|
|
f97c718568 | ||
|
|
d05b6bea5c | ||
|
|
2f567cd604 | ||
|
|
3971c81449 | ||
|
|
e1b5aede66 | ||
|
|
14c3614856 | ||
|
|
1311d4a68d | ||
|
|
9cbc290768 | ||
|
|
f90f39e5f1 | ||
|
|
07fa11b9ff | ||
|
|
df04d542db | ||
|
|
92ab02145e | ||
|
|
d9916b7662 | ||
|
|
f8349f12bc | ||
|
|
12823704f3 | ||
|
|
7490cf72a3 | ||
|
|
ce220d999a | ||
|
|
9a438abf79 | ||
|
|
ce97e928ad | ||
|
|
56481f3f72 | ||
|
|
55ed9ba4c2 | ||
|
|
df67980bd6 | ||
|
|
b6b78c4849 | ||
|
|
b1d1f2ac46 | ||
|
|
750056df06 | ||
|
|
3f13e957ad | ||
|
|
afc254720c | ||
|
|
943e4420e6 | ||
|
|
c9e6cd079f | ||
|
|
faae6aa31f | ||
|
|
c25f08f142 | ||
|
|
d6ad9d288e | ||
|
|
3400c4d43a | ||
|
|
ddcbea001c | ||
|
|
9a35e47c27 | ||
|
|
199fcce549 | ||
|
|
bfeb382d1f | ||
|
|
3a93d9e98f | ||
|
|
3b22e3f711 | ||
|
|
5c1f1f5b96 | ||
|
|
82788f1ecd | ||
|
|
d5920e1454 | ||
|
|
b26a63bb7a | ||
|
|
f17cea3c9d | ||
|
|
7f68285a43 | ||
|
|
cb46a13802 | ||
|
|
de07393e6e | ||
|
|
4b40b03da4 | ||
|
|
4f5d4acf56 | ||
|
|
271bd3913c | ||
|
|
869ffaaf36 | ||
|
|
5a73cc20a9 | ||
|
|
1a936c631c | ||
|
|
1a8a6f7a6f | ||
|
|
879d3b5326 | ||
|
|
3313548ec2 | ||
|
|
e6db6e11e5 | ||
|
|
dc28eb2984 | ||
|
|
b8acb4a52c | ||
|
|
c843e8d1ac | ||
|
|
21fdaf4545 | ||
|
|
db192df2c6 | ||
|
|
4a24d263c1 | ||
|
|
3394559539 | ||
|
|
47074ff60f | ||
|
|
047a7de612 | ||
|
|
7fc7f00308 | ||
|
|
14e940134c | ||
|
|
1897633e75 | ||
|
|
5a052d9374 | ||
|
|
4b048c2a7f | ||
|
|
27f77b9caa | ||
|
|
18c47ee5e4 | ||
|
|
27dd8475e9 | ||
|
|
37b381085c | ||
|
|
b2a30f5771 | ||
|
|
b88b3fa245 | ||
|
|
52aac32474 | ||
|
|
037b151729 | ||
|
|
3f3d643053 | ||
|
|
f27d905869 | ||
|
|
4c694cb285 | ||
|
|
ca2c5f7b04 | ||
|
|
0c49df1473 | ||
|
|
fe613f7688 | ||
|
|
4b247557d4 | ||
|
|
dc49de41ce | ||
|
|
9d07fac929 | ||
|
|
4ecbad6558 | ||
|
|
4c86e42776 | ||
|
|
00dbea6dac | ||
|
|
ed2bf3bd83 | ||
|
|
58fb085180 | ||
|
|
800f5ec2aa | ||
|
|
bdf5770ba0 | ||
|
|
a213672341 | ||
|
|
d337546da7 | ||
|
|
b9437d42e8 | ||
|
|
71c4447d25 | ||
|
|
a489061bac | ||
|
|
75b925992b | ||
|
|
05b9f195d7 | ||
|
|
5eca809c4a | ||
|
|
fa00b7106a | ||
|
|
df85c8a349 | ||
|
|
d8d5e8f39a | ||
|
|
690bdaa748 | ||
|
|
feee22dbac | ||
|
|
548da932ad | ||
|
|
b147f6606e | ||
|
|
31fe05fe2b | ||
|
|
924f3059fb | ||
|
|
5231eac4b0 | ||
|
|
28144312ff | ||
|
|
60e8855aa7 | ||
|
|
5ea14f9069 | ||
|
|
ce79fb4b82 | ||
|
|
98ce4e2a3a | ||
|
|
026626b5ab | ||
|
|
95c342b548 | ||
|
|
cb9312f6c3 | ||
|
|
8831fec6be | ||
|
|
0227a05970 | ||
|
|
087d66694e | ||
|
|
20ad6891e8 | ||
|
|
cd2bd072ed | ||
|
|
3a5262ff33 | ||
|
|
430eff958c | ||
|
|
86371c03b2 | ||
|
|
3207b6b76e | ||
|
|
3d4724ac57 | ||
|
|
63ac729967 | ||
|
|
0900fec60f | ||
|
|
5ccb793ddb | ||
|
|
3ebab82977 | ||
|
|
e877f410f3 | ||
|
|
220e337d08 | ||
|
|
92b7f4e260 | ||
|
|
78d39325b0 | ||
|
|
208b1cad2a | ||
|
|
ff760a488c | ||
|
|
9200c0fc5d | ||
|
|
998450af4e | ||
|
|
d78c7c536d | ||
|
|
a55c53299a | ||
|
|
fb9cc64839 | ||
|
|
409c93bfb2 | ||
|
|
543a79bb66 | ||
|
|
16d1054b96 | ||
|
|
165b6ef9bb | ||
|
|
fb94b858f6 | ||
|
|
ea80925533 | ||
|
|
62b896ee07 | ||
|
|
8657ea6704 | ||
|
|
05bd6b6d77 | ||
|
|
19256e4eaa | ||
|
|
905f6aa9ec | ||
|
|
daa0dac5b9 | ||
|
|
0478fc69f4 | ||
|
|
b99e74823c | ||
|
|
9aaab37a17 | ||
|
|
df618afeda | ||
|
|
d36769e2a0 | ||
|
|
ebeb6be7a7 | ||
|
|
d3979da2b4 | ||
|
|
f276f66991 | ||
|
|
3ac5c10f08 | ||
|
|
13c84ba174 | ||
|
|
b19fe5c86a | ||
|
|
ff9d0a5a77 | ||
|
|
50af884563 | ||
|
|
0737c54a0e | ||
|
|
a7e516925c | ||
|
|
2f1adf9d4b | ||
|
|
cd5417c2e0 | ||
|
|
ba621fcb85 | ||
|
|
7442b0d0ca | ||
|
|
c275926117 | ||
|
|
895a9ec99b | ||
|
|
6dfd70dfee | ||
|
|
0bdb321fd7 | ||
|
|
b508a8a16a | ||
|
|
ddee3a42a9 | ||
|
|
b000215b26 | ||
|
|
a2b652907f |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -12,3 +12,15 @@ data
|
|||||||
/.settings/
|
/.settings/
|
||||||
/start.bat
|
/start.bat
|
||||||
/.classpath
|
/.classpath
|
||||||
|
/.project
|
||||||
|
|
||||||
|
sftp-config\.json
|
||||||
|
/bin/
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/launch.test.json
|
||||||
|
.vscode/settings.json
|
||||||
|
.vscode/tasks.json
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
397
README.md
397
README.md
@@ -1,9 +1,9 @@
|
|||||||
# 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/Dot or other systems that support Philips Hue local network discovery. The ha-bridge is not part of meethue.philips.com so the cloud sign in does not apply to this system. The Bridge handles basic commands such as "On", "Off", "Brightness" and "Color" 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.
|
Here are some diagrams to put this software in perspective.
|
||||||
|
|
||||||
The Echo Path looks like this:
|
The Echo path looks like this:
|
||||||
```
|
```
|
||||||
+------------------------+ +------------------------+
|
+------------------------+ +------------------------+
|
||||||
+-------------+ | H A +------------------| | A +------------------+ |
|
+-------------+ | H A +------------------| | A +------------------+ |
|
||||||
@@ -11,15 +11,7 @@ The Echo Path looks like this:
|
|||||||
+-------------+ | E I +------------------| | I +------------------+ |
|
+-------------+ | E I +------------------| | I +------------------+ |
|
||||||
+------------------------+ +------------------------+
|
+------------------------+ +------------------------+
|
||||||
```
|
```
|
||||||
The Google Home Path looks like this:
|
THe Harmony Hub 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 +------------------+ |
|
+-------------+ | H A +------------------| | A +------------------+ |
|
||||||
@@ -27,26 +19,34 @@ THe Harmony Hub Path looks like this:
|
|||||||
+-------------+ | E I +------------------| | I +------------------+ |
|
+-------------+ | E I +------------------| | I +------------------+ |
|
||||||
+------------------------+ +------------------------+
|
+------------------------+ +------------------------+
|
||||||
```
|
```
|
||||||
|
A Custom implementation path looks like this:
|
||||||
|
```
|
||||||
|
+------------------------+ +------------------------+
|
||||||
|
+-------------+ | H A +------------------| | A +------------------+ |
|
||||||
|
| HA System |----->| 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, Echo Plus, Spot, Tap or Show 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!**
|
||||||
|
|
||||||
**NOTE: This software does require the user to have knowledge on how processes run on Linux or Windows with java. Also, an understanding of networking basics will help as well. This system receives upnp udp multicast packets from devices to be found, so that is something to understand. Please make sure you have all your devices use static IP addresses from your router. Most all questions have been answered already. PLEASE USE GOOGLE TO FIND YOUR ANSWERS!**
|
**NOTE: This software does require the user to have knowledge on how processes run on Linux or Windows with java. Also, an understanding of networking basics will help as well. This system receives upnp udp multicast packets from devices to be found, so that is something to understand. Please make sure you have all your devices use static IP addresses from your router. Most all questions have been answered already. PLEASE USE GOOGLE TO FIND YOUR ANSWERS!**
|
||||||
|
|
||||||
**NOTE: This software does not control Philips Hue devices directly. A physical Philips Hue Hub is required for that, by which the ha-bridge can then proxy all of your real Hue bridges behind this bridge.**
|
**NOTE: This software does not control Philips Hue devices directly. A physical Philips Hue Hub is required for that, by which the ha-bridge can then proxy all of your real Hue bridges behind this bridge.**
|
||||||
|
|
||||||
|
**ISSUE: Google Home does NOT support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work. If you have an older Google Home application, this may still work. YMMV.**
|
||||||
|
|
||||||
**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, Somfy Tahoma 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 APIs 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, Home Assistant, Domoticz, MQTT, HAL, Fibaro, HomeWizard, LIFX, OpenHAB, FHEM, Broadlink, Mozilla IOT, HomeGenie 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 and executing programs/scripts 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.
|
||||||
|
|
||||||
This bridge was built to help put the Internet of Things together.
|
This bridge was built to help put the Internet of Things together.
|
||||||
## Build
|
## Build
|
||||||
To customize and build it yourself, build a new jar with maven:
|
To customize and build it yourself, build a new jar with maven:
|
||||||
|
|
||||||
ATTENTION: This requires JDK 1.8 to build
|
|
||||||
|
|
||||||
```
|
```
|
||||||
mvn install
|
mvn install
|
||||||
```
|
```
|
||||||
@@ -54,36 +54,29 @@ Otherwise, downloads are available at https://github.com/bwssytems/ha-bridge/rel
|
|||||||
## Run
|
## Run
|
||||||
Then locate the jar and start the server with:
|
Then locate the jar and start the server with:
|
||||||
|
|
||||||
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.3.1.jar
|
java -jar ha-bridge-5.3.1RC2.jar
|
||||||
```
|
```
|
||||||
### Automation on Linux systems
|
|
||||||
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
|
|
||||||
|
|
||||||
Create the directory and make sure that ha-bridge-4.3.1.jar is in your /home/pi/habridge directory.
|
## Manual installation of ha-bridge and setup of systemd service
|
||||||
```
|
Next gen Linux systems (this includes the Raspberry Pi), use systemd to run and manage services.
|
||||||
pi@raspberrypi:~ $ mkdir habridge
|
Here is a link on how to use systemd: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
|
||||||
pi@raspberrypi:~ $ cd habridge
|
|
||||||
|
|
||||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.1/ha-bridge-4.3.1.jar
|
Create the directory and make sure that ha-bridge-5.3.1RC2.jar is in your /home/pi/ha-bridge directory.
|
||||||
```
|
|
||||||
Create the directory and make sure that ha-bridge-4.3.1.jar is in your /home/pi/habridge directory.
|
|
||||||
```
|
|
||||||
pi@raspberrypi:~ $ mkdir habridge
|
|
||||||
pi@raspberrypi:~ $ cd habridge
|
|
||||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.1/ha-bridge-4.3.1.jar
|
|
||||||
```
|
|
||||||
#### System Control Setup on a pi (preferred)
|
|
||||||
For next gen Linux systems (this includes the Raspberry Pi), here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
|
|
||||||
|
|
||||||
Start here to create the habridge.service unit file:
|
```
|
||||||
|
pi@raspberrypi:~ $ mkdir ha-bridge
|
||||||
|
pi@raspberrypi:~ $ cd ha-bridge
|
||||||
|
|
||||||
|
pi@raspberrypi:~/ha-bridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.3.1RC2/ha-bridge-5.3.1RC2.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the ha-bridge.service unit file:
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~ $ cd /etc/systemd/system
|
pi@raspberrypi:~ $ cd /etc/systemd/system
|
||||||
pi@raspberrypi:~ $ sudo nano habridge.service
|
pi@raspberrypi:~ $ sudo nano ha-bridge.service
|
||||||
```
|
```
|
||||||
Copy the text below into the editor nano.
|
Copy the text below into the editor nano.
|
||||||
```
|
```
|
||||||
@@ -95,65 +88,101 @@ 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.3.1.jar
|
WorkingDirectory=/home/pi/ha-bridge
|
||||||
|
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/ha-bridge/data/habridge.config /home/pi/ha-bridge/ha-bridge-5.3.1RC2.jar
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
```
|
```
|
||||||
|
|
||||||
Save the file in the editor by hitting CTL-X and then saying Y to update and save.
|
Save the file in the editor by hitting CTL-X and then saying Y to update and save.
|
||||||
|
|
||||||
Reload the system control config:
|
Reload the system control config:
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~ $ sudo systemctl daemon-reload
|
pi@raspberrypi:~ $ sudo systemctl daemon-reload
|
||||||
```
|
```
|
||||||
|
|
||||||
To start the bridge:
|
To start the bridge:
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~ $ sudo systemctl start habridge.service
|
pi@raspberrypi:~ $ sudo systemctl start ha-bridge.service
|
||||||
```
|
```
|
||||||
|
|
||||||
To start the service at boot, use the `enable` command:
|
To start the service at boot, use the `enable` command:
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~ $ sudo systemctl enable habridge.service
|
pi@raspberrypi:~ $ sudo systemctl enable ha-bridge.service
|
||||||
```
|
```
|
||||||
|
|
||||||
To look at the log, the output goes into the system log at `/var/log/syslog':
|
To look at the log, the output goes into the system log at `/var/log/syslog':
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~ $ tail -f /var/log/syslog
|
pi@raspberrypi:~ $ tail -f /var/log/syslog
|
||||||
```
|
```
|
||||||
#### Basic script setup to run the bridge on a pi.
|
|
||||||
|
|
||||||
*NOTE ON RC.LOCAL*: Due to the way network subsystem is brought up on the pi, it uses the new systemctl to start services. The old style runlevel setup, which rc.local is part of does not get the benefit of knowing if the network has been fully realized. Starting ha-bridge from rc.local on next gen systems will cause unexpected results and issues with discovering registered devices.
|
### ha-bridge inside Docker container
|
||||||
|
Docker start offering official support for Raspbian operating system since autumn 2016.
|
||||||
|
Running services inside containers became to be a good alternative to normal installation method described before.
|
||||||
|
|
||||||
Edit the shell script for starting:
|
Install Docker Community Edition (CE) on Raspberry Pi
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~/habridge $ nano starthabridge.sh
|
pi@raspberrypi:~ $ curl -fsSL get.docker.com -o get-docker.sh
|
||||||
|
pi@raspberrypi:~ $ sudo sh get-docker.sh
|
||||||
```
|
```
|
||||||
Then cut and past this, modify any locations that are not correct
|
|
||||||
```
|
|
||||||
cd /home/pi/habridge
|
|
||||||
rm /home/pi/habridge/habridge-log.txt
|
|
||||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.1.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
|
||||||
|
|
||||||
chmod 777 /home/pi/habridge/habridge-log.txt
|
For every architecture there is a specialized ha-bridge Docker image available.
|
||||||
|
Please use the suitable image from the following list.
|
||||||
|
|
||||||
|
* Generic x86 / x86_64 system: [aptalca/home-automation-bridge](https://hub.docker.com/r/aptalca/home-automation-bridge)
|
||||||
|
* Raspberry Pi 1 (ARM): [habridge/ha-bridge-raspberry-pi](https://hub.docker.com/r/habridge/ha-bridge-raspberry-pi)
|
||||||
|
* Raspberry Pi 2 (ARM): [habridge/ha-bridge-raspberry-pi2](https://hub.docker.com/r/habridge/ha-bridge-raspberry-pi2)
|
||||||
|
* Raspberry Pi 3 (ARM): [habridge/ha-bridge-raspberrypi3](https://hub.docker.com/r/habridge/ha-bridge-raspberrypi3)
|
||||||
|
|
||||||
|
The following example explains how to run the latest version of ha-bridge Docker container on Raspberry Pi 3.
|
||||||
```
|
```
|
||||||
Exit and save the file with ctrl-X and follow the prompts and then execute on the command line:
|
pi@raspberrypi:~ $ docker pull habridge/ha-bridge-raspberrypi3
|
||||||
|
pi@raspberrypi:~ $ docker run \
|
||||||
|
--name ha-bridge \
|
||||||
|
--rm \
|
||||||
|
--init \
|
||||||
|
--detach \
|
||||||
|
--net=host \
|
||||||
|
--volume=$PWD:/ha-bridge/data \
|
||||||
|
--volume=/etc/localtime:/etc/localtime:ro \
|
||||||
|
--volume=/etc/timezone:/etc/timezone:ro \
|
||||||
|
habridge/ha-bridge-raspberrypi3
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~/habridge $ chmod u+x starthabridge.sh
|
|
||||||
|
To set additional arguments for ha-bridge just write them as arguments for docker run command.
|
||||||
```
|
```
|
||||||
Then execute the script:
|
pi@raspberrypi:~ $ docker run \
|
||||||
|
--name ha-bridge \
|
||||||
|
--rm \
|
||||||
|
--init \
|
||||||
|
--detach \
|
||||||
|
--net=host \
|
||||||
|
--volume=$PWD:/ha-bridge/data \
|
||||||
|
--volume=/etc/localtime:/etc/localtime:ro \
|
||||||
|
--volume=/etc/timezone:/etc/timezone:ro \
|
||||||
|
habridge/ha-bridge-raspberry-pi3 \
|
||||||
|
-Dserver.port=8080 \
|
||||||
|
-Dsecurity.key=secret
|
||||||
```
|
```
|
||||||
pi@raspberrypi:~/habridge $ ./starthabridge.sh
|
|
||||||
|
To halt the ha-bridge Docker container use the `stop` command:
|
||||||
```
|
```
|
||||||
You should now be running the bridge. Check for errors:
|
pi@raspberrypi:~ $ docker stop ha-bridge
|
||||||
```
|
|
||||||
pi@raspberrypi:~/habridge $ tail -f habridge-log.txt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you like to automate the deployment just use the Ansible role on https://github.com/escalate/ansible-ha-bridge-docker.
|
||||||
|
|
||||||
## Run ha-bridge alongside web server already on port 80
|
## 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.
|
These examples will help you proxy your current webserver requests to the ha-bridge running on a different port, such as 8080.
|
||||||
|
|
||||||
### Apache Example
|
### Apache Example
|
||||||
|
|
||||||
Reverse proxy with Apache on Ubuntu linux:
|
Reverse proxy with Apache on Ubuntu linux:
|
||||||
|
|
||||||
a2enmod proxy
|
Enable the required Apache modules:
|
||||||
a2enmod proxy_http
|
|
||||||
a2enmod headers
|
`a2enmod proxy proxy_http headers`
|
||||||
|
|
||||||
Added the following lines to my Apache config file “000-default”
|
Added the following lines to my Apache config file “000-default”
|
||||||
|
|
||||||
@@ -175,7 +204,10 @@ Added the following lines to my Apache config file “000-default”
|
|||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
service apache2 restart
|
Restart apache for the changes to take effect.
|
||||||
|
|
||||||
|
`service apache2 restart`
|
||||||
|
|
||||||
### lighthttpd Example
|
### lighthttpd Example
|
||||||
```
|
```
|
||||||
server.modules += ( "mod_proxy" )
|
server.modules += ( "mod_proxy" )
|
||||||
@@ -190,12 +222,17 @@ proxy.server = (
|
|||||||
```
|
```
|
||||||
### nginx Example
|
### nginx Example
|
||||||
```
|
```
|
||||||
location /api/ {
|
location /api {
|
||||||
proxy_pass http://127.0.0.1:8080/api;
|
proxy_pass http://127.0.0.1:8080/api;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Available Arguments
|
## Available Arguments
|
||||||
Arguments are now deprecated. The ha-bridge will use the old -D arguments and populate the configuration screen, Bridge Control Tab, which can now be saved to a file and will not be needed. There is only one optional argument that overrides and that is the location of the configuration file. The default is the relative path "data/habridge.config".
|
Arguments are now deprecated. The ha-bridge will use the old -D arguments and populate the configuration screen, Bridge Control Tab, which can now be saved to a file and will not be needed. There is only one optional argument that overrides and that is the location of the configuration file. The default is the relative path "data/habridge.config".
|
||||||
|
### -Djava.net.preferIPv4Stack=true
|
||||||
|
This will guarantee that the ha-bridge will not use an IPV6 address. This cannot be automatically set inside the code.
|
||||||
|
```
|
||||||
|
java -jar -Djava.net.preferIPv4Stack=true ha-bridge-W.X.Y.jar
|
||||||
|
```
|
||||||
### -Dconfig.file=`<filepath>`
|
### -Dconfig.file=`<filepath>`
|
||||||
The default location for the configuration file to contain the settings for the bridge is the relative path from where the bridge is started in "data/habridge.config". If you would like a different filename or directory, specify -Dconfig.file=`<directory>/<filename>` explicitly. The command line example:
|
The default location for the configuration file to contain the settings for the bridge is the relative path from where the bridge is started in "data/habridge.config". If you would like a different filename or directory, specify -Dconfig.file=`<directory>/<filename>` explicitly. The command line example:
|
||||||
```
|
```
|
||||||
@@ -213,25 +250,81 @@ The default ip address for the bridge to listen on is all interfaces (0.0.0.0).
|
|||||||
```
|
```
|
||||||
java -jar -Dserver.ip=192.168.1.1 ha-bridge-W.X.Y.jar
|
java -jar -Dserver.ip=192.168.1.1 ha-bridge-W.X.Y.jar
|
||||||
```
|
```
|
||||||
|
### -Dsecurity.key=`<Your Key To Encrypt Security Data>`
|
||||||
|
This option is very important to set if you will be using username/passwords to secure the ha-bridge. The ha-bridge needs to encrypt the settings in the config file and to make sure they are secured specifically to you is to provide this key. Otherwise a default key is used and it is available in the code on github for the ha-bridge here, so not very secure in that sense. **It is very important provide this if you are using username/password.** To override the default, specify -Dsecurity.key=`<Your Key To Encrypt Security Data>` explicitly on the command line. This is will prevent any issues if your config file gets hacked. The command line example:
|
||||||
|
```
|
||||||
|
java -jar -Dsecurity.key=Xfawer354WertSdf321234asd ha-bridge-W.X.Y.jar
|
||||||
|
```
|
||||||
|
### -Dexec.garden=`<The path to your scripts and program directory>`
|
||||||
|
This sets a directory of your choosing to have a walled area for what can be executed by the Exec Command type. This is a good feature to use if you use the capabilities of executing a script or program from the ha-bridge. The default is not set which allows any program or script to be called and anyone with access to the your system could create an exec command call and execute it from the API. This is will prevent any issues if your system gets hacked. To override the default, specify -Dexec.garden=`<The path to your scripts and program directory>` explicitly on the command line. The command line example:
|
||||||
|
```
|
||||||
|
java -jar -Dexec.garden=C:\Users\John\bin
|
||||||
|
```
|
||||||
## HA Bridge Usage and Configuration
|
## HA Bridge Usage and Configuration
|
||||||
This section will cover the basics of configuration and where this configuration can be done. This requires that you have started your bridge process and then have pointed your
|
This section will cover the basics of configuration and where this configuration can be done. This requires that you have started your bridge process and then have pointed your
|
||||||
favorite web interface by going to the http://<my ip address>:<port> or http://localhost:<port> with port you have assigned. The default quick link is http://localhost for your reference.
|
favorite web interface by going to the `http://<my ip address>:<port>` or `http://localhost:<port>` with port you have assigned. The default quick link is http://localhost for your reference.
|
||||||
### The Bridge Devices Tab
|
### The Bridge Devices Tab
|
||||||
This screen allows you to see your devices you have configured for the ha-bridge to present to a controller, such as an Amazon Echo/Dot. It gives you a count of devices as there have been reports that the Echo only supports a limited number, but has been growing as of late, YMMV. You can test each device from this page as this calls the ha-bridge just as a controller would, i.e. the Echo. This is useful to make sure your configuration for each device is correct and for trouble shooting. You can also manages your devices as well by editing and making a new device copy as well as deleting it.
|
This screen allows you to see your devices you have configured for the ha-bridge to present to a controller, such as an Amazon Echo/Dot. You can test each device from this page as this calls the ha-bridge just as a controller would, i.e. the Echo. This is useful to make sure your configuration for each device is correct and for trouble shooting. You can also manage your devices as well by editing and making a new device copy as well as deleting it.
|
||||||
|
|
||||||
At the bottom of the screen is the "Bridge Device DB Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Device DB' button will create a backup and name it for you. You can manage these backups by restoring them or deleting them.
|
Each of the columns are sortable by the use of the little arrow in the upper left corner of the heading.
|
||||||
|
|
||||||
|
If you click on the ID number on a Device, this will toggle the ID number to lock/unlock that is used during renumbering. When the ID is '<b>Bolded</b>', it is locked. You can also hover your mouse to see the state. This allows you to renumber a part of your devices and keep the ID for others. All IDs will be unique.
|
||||||
|
|
||||||
|
There is a new feature for the Devices that can be selected on the 'Startup' column. If you choose to have certain devices executed when the bridge is started or restarted. You can can click this field to bring up the dialog which will allow you to enter what you want the device to do on startup. The default is to do nothing.
|
||||||
|
|
||||||
|
At the bottom of the screen is the "Bridge Device DB Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Device DB' button will create a backup and name it for you. You can manage these backups by restoring them, deleting them, downloading them by clicking on the file name and uploading a saved device DB backup on your local machine.
|
||||||
|
#### Renumber Devices
|
||||||
|
This changes the numbering of the added devices to start at the nmuber given in the 'Bridge Control' tab field 'ID Seed' and the default is 100 and goes up from there. It was originally intended for a conversion from the previous system version that used large numbers and was not necessary. This also allows the system to try and number sequentially. If you use this button, you will need to re-discover your devices as their ID's will have changed.
|
||||||
|
#### Link
|
||||||
|
If this is present, you have enabled the Hue link button feature for the ha-bridge. If you want a new system to recognize the ha-bridge, you will need to press this button when you are doing a discovery.
|
||||||
|
#### Manage Links
|
||||||
|
If this is present, you have enabled the Hue link button feature for the ha-bridge. This button will bring up a dialog which contains all of the registered users created by linking the ha-bridge with a device. This allows you to revoke control for a created user so that it cannot access the ha-bridge by deleting that link user.
|
||||||
|
#### Show devices visible to
|
||||||
|
This filter is to sort devices that have an IP filter set. Type in the IP that is used in your device filter field.
|
||||||
|
#### Filter device type
|
||||||
|
This filter is for a quick method to find specific devices by their type listed in the dropdown.
|
||||||
### The Bridge Control Tab
|
### The Bridge Control Tab
|
||||||
This is where all of the configuration occurs for what ports and IP's the bridge runs on. It also contains the configurations for target devices so that Helper Tabs for configuration can be added as well as the connection information to control those devices.
|
This is where all of the configuration occurs for what ports and IP's the bridge runs on. It also contains the configurations for target devices so that Helper Tabs for configuration can be added as well as the connection information to control those devices.
|
||||||
#### Bridge server
|
#### Bridge server
|
||||||
This field is used to test the bridge server with the UPNP IP Address and to make sure that the bridge is responding.
|
This field is used to test the bridge server with the UPNP IP Address and to make sure that the bridge is responding.
|
||||||
#### Bridge Control Buttons
|
#### Bridge Control Buttons
|
||||||
These buttons are for managing the bridge. The Save button is enabled when there is a change to the configuration. The Bridge Reinitialize button will recycle the internal running of the bridge in the java process. The Stop button will stop the java process. The Refresh button will refresh the page and settings.
|
These buttons are for managing the bridge. The Save button is enabled when there is a change to the configuration. The Bridge Reinitialize button will recycle the internal running of the bridge in the java process. The Stop button will stop the java process. The Refresh button will refresh the page and settings.
|
||||||
|
#### The Security Dialog
|
||||||
|
This is where you can set the different security settings for the ha-bridge. The settings are the https enablement with the Keyfile path and password and described below, enabling Hue like operation to secure the Hue API with the internally generated user for the calls that are done after the link button. Another is to secure the hue API with a username/password that is created as well. The last one is the path to the exec garden if used for only allowing scripts and programs to be executed from this location only. The other fields are to add and delete users and to set and change passwords for those users. If there are no users in the system, the system will not require a username/password to operate.
|
||||||
|
|
||||||
|
The use https selection will require you to generate a java keytool keystore file for the ha-bridge to use. This will require the path to the keyfile and the password that was used to secure the keyfile. There are mulitple ways to add the key file. The basic way is to generate a self signed keystore using keytool as follows:
|
||||||
|
|
||||||
|
Step 1. Open the command console
|
||||||
|
|
||||||
|
Step 2. Run this command (Where indicate the number of days for which the certificate will be valid)
|
||||||
|
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass ```<password>``` -validity 365 -keysize 2048
|
||||||
|
|
||||||
|
Step 3. Enter a password for the keystore. Note this ```<password>``` as you require this for configuring the server
|
||||||
|
|
||||||
|
Step 4. When prompted for first name and last name, enter the domain name of the server. For example, myserver or myserver.mycompany.com.
|
||||||
|
|
||||||
|
Step 5. Enter the other details, such as Organizational Unit, Organization, City, State, and Country.
|
||||||
|
|
||||||
|
Step 6. When prompted with Enter key ```<password>``` for , press Enter to use the same ```<password>``` as the keystore ```<password>```
|
||||||
|
|
||||||
|
Step 7. Run this command to verify the contents of the keystore
|
||||||
|
keytool -list -v -keystore selfsigned.jks
|
||||||
|
|
||||||
|
Step 8. When prompted, enter the keystore password note in Step 3. The basic information about the generated certificate is displayed. Verify that the Owner and Issuer are the same. Also, you should see the information you provided in Step 4 and 5.
|
||||||
|
|
||||||
|
The second way is to acquire a certified certificate to use in the keyfile. Such way to get one is use letsencrypt. Once you have the certifcate files you can follow this to create the keystore: https://community.letsencrypt.org/t/tutorial-java-keystores-jks-with-lets-encrypt/34754.
|
||||||
|
|
||||||
|
The easiest place to keep the keystore files is in your ha bridge data directory.
|
||||||
#### Configuration Path and File
|
#### Configuration Path and File
|
||||||
The default location for the configuration file to contain the settings for the bridge is the relative path from where the bridge is started in "data/habridge.config". If you would like a different filename or directory, specify `<directory>/<filename>` explicitly.
|
The default location for the configuration file to contain the settings for the bridge is the relative path from where the bridge is started in "data/habridge.config". If you would like a different filename or directory, specify `<directory>/<filename>` explicitly.
|
||||||
#### Device DB Path and File
|
#### Device DB Path and File
|
||||||
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify `<directory>/<filename> explicitly.
|
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify `<directory>/<filename>` explicitly.
|
||||||
#### UPNP IP Address
|
#### UPNP IP Address
|
||||||
The server defaults to the first available address on the host if this is not given. This default may NOT be the correct IP that is your public IP for your host on the network. It is best to set this parameter to not have discovery issues. Replace this value with the server ipv4 address you would like to use as the address that any upnp device will call after discovery.
|
The server defaults to the first available address on the host if this is not given. This default may NOT be the correct IP that is your public IP for your host on the network. It is best to set this parameter to not have discovery issues. Replace this value with the server ipv4 address you would like to use as the address that any upnp device will call after discovery.
|
||||||
|
#### Use UPNP Address Interface
|
||||||
|
The server tries to bind to all interfaces to respond to UPNP request. Setting this to `true` will make the binding to the interface that has the `UPNP IP Address`. The default is to be all interfaces which is set as false.
|
||||||
|
#### Use Rooms for Alexa
|
||||||
|
This setting controls rooms for Alexa. If it is set to true, any device ID abaove 10000 is treated as a special group. The default is set as false.
|
||||||
#### Web Server IP Address
|
#### Web Server IP Address
|
||||||
The server defaults to all interfaces on the machine (0.0.0.0). Replace this value with the server ipv4 address you would like to use as the address that will bind to a specific ip address on an interface if you would like. This is only necessary if you want to isolate how access is handled to the web UI.
|
The server defaults to all interfaces on the machine (0.0.0.0). Replace this value with the server ipv4 address you would like to use as the address that will bind to a specific ip address on an interface if you would like. This is only necessary if you want to isolate how access is handled to the web UI.
|
||||||
#### Web Server Port
|
#### Web Server Port
|
||||||
@@ -239,7 +332,9 @@ The server defaults to running on port 80. To override what the default is, spec
|
|||||||
#### UPNP Response Port
|
#### UPNP Response Port
|
||||||
The upnp response port that will be used. The default is 50000.
|
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 device/scene you configure.
|
||||||
|
#### Fibaro Names and IP Addresses
|
||||||
|
Provide IP Addresses of your Fibaros 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 Fibaro device/scene you configure. There are filter switches available to limit some of the returns for devices and scenes such as use save logs, use user description, use only Lili command and a switch that cleans up format Trash Chars. The default filters are false for everything but Trash Chars.
|
||||||
#### 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. 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}
|
Provide IP Addresses of your Harmony Hubs that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the activity or buttons by the call it receives and send it to the target Harmony Hub and activity/button you configure. Also, an option of webhook can be called when the activity changes on the harmony hub that will send an HTTP GET call to the the address of your choosing. This can contain the replacement variables of ${activity.id} and/or ${activity.label}. Example : http://192.168.0.1/activity/${activity.id}/${activity.label} OR http://hook?a=${activity.label}
|
||||||
#### Hue Names and IP Addresses
|
#### Hue Names and IP Addresses
|
||||||
@@ -247,31 +342,51 @@ Provide IP Addresses of your Hue Bridges that you want to proxy through the brid
|
|||||||
|
|
||||||
Don't forget - You will need to push the link button when you got to the Hue Tab the first time after the process comes up. (The user name is not persistent when the process comes up.)
|
Don't forget - You will need to push the link button when you got to the Hue Tab the first time after the process comes up. (The user name is not persistent when the process comes up.)
|
||||||
#### HAL Names and IP Addresses
|
#### HAL Names and IP Addresses
|
||||||
Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure.
|
Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL device you configure.
|
||||||
#### HAL Token
|
|
||||||
The token you generate or give to a HAL and must be the same for all HAL's you have identified. This needs to be given if you are using the HAL features.
|
|
||||||
#### MQTT Client IDs and IP Addresses
|
#### MQTT Client IDs and IP Addresses
|
||||||
Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured your MQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish MQTT messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages.
|
Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured your MQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish MQTT messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages.
|
||||||
|
#### Home Assistant Names and IP Addresses
|
||||||
|
<Provide IP Addresses and ports of your Home Assistant 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 Home Assistant device you configure.
|
||||||
|
#### HomeWizard Gateways Names and IP Addresses
|
||||||
|
Provide IP Addresses of your HomeWizard Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HomeWizard device you configure.
|
||||||
|
#### Domoticz Names and IP Addresses
|
||||||
|
Provide IP Addresses of your Domoticz Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Domoticz device you configure.
|
||||||
|
#### Somfy Tahoma Names and IP Addresses
|
||||||
|
Provide user name and password 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.
|
||||||
|
#### OpenHAB Names and IP Addresses
|
||||||
|
Provide IP Addresses of your OpenHAB Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target OpenHAB device you configure.
|
||||||
|
#### FHEM Names and IP Addresses
|
||||||
|
Provide IP Addresses of your FHEM Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target FHEM device you configure.
|
||||||
|
#### Mozilla IOT Names and IP Addresses
|
||||||
|
Provide IP Addresses of your Mozilla IOT Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices by the call it receives and send it to the target Mozilla IOT device you configure.
|
||||||
|
#### HomeGenie Names and IP Addresses
|
||||||
|
Provide IP Addresses of your HomeGenie Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices by the call it receives and send it to the target HomeGenie device you configure. There is an extra Other Types field that you can add types that are not within the defualt of "light", "Switch" and "Dimmer" that you may want to control.
|
||||||
#### Nest Username
|
#### Nest Username
|
||||||
The user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account.
|
Provide the username and password of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account. Also, you can set Nest Temp Fahrenheit that allows the value being sent into the bridge to be interpreted as Fahrenheit or Celsius. The default is to have Fahrenheit.
|
||||||
#### Nest Password
|
#### LIFX Support
|
||||||
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.
|
This setting will have the ha-bridge look for LIFX devices on your network. Since this is broadcast based, there is no other info needed.
|
||||||
#### Nest Temp Fahrenheit
|
#### Broadlink Support
|
||||||
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 will have the ha-bridge look for Broadlink devices on your network (i.e. RM2 IRcontrollers, Smart Power Strips and Smart Plugs). Since this is broadcast based, there is no other info needed.
|
||||||
#### Somfy Tahoma Username
|
#### Emulate Hue Hub Version
|
||||||
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.
|
This setting is used to set the version that the ha-bridge will return in the hub version field. The default is 9999999999 which should work to be higher than the versions that are being used.
|
||||||
#### Somfy Tahoma Password
|
#### Emulate MAC
|
||||||
The password associated with the Somfy Tahoma username above
|
This setting is in bridge-id, uuid, etc. in ha-bridge hue config replies. Leave blank unless needed as it is mainly a tool to keep a config to a specific set of devices whtn the ha-bridge is moved to another machine
|
||||||
#### 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
|
||||||
This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process.
|
This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process.
|
||||||
#### UPNP Strict Handling
|
|
||||||
Upnp has been set to be very specific as to respond as a Hue. There may be a need to make this response a little more open for other devices that may want to find the ha-bridge. The default is to be strict which is set as true.
|
|
||||||
#### Trace UPNP Calls
|
#### Trace UPNP Calls
|
||||||
Turn on tracing for upnp discovery messages to the log. The default is false.
|
Turn on tracing for upnp discovery messages to the log. The default is false.
|
||||||
|
#### Trace State Changes
|
||||||
|
Turn on tracing for calls to the ha-bridge and send these information messages to the log for debugging. This a quick way to watch the state changes without turning the HueMulator debugging. The default is false.
|
||||||
|
#### UPNP Send Delay
|
||||||
|
This setting is for the upnp spec to delay a certain amount between upnp response messages sent back to a client. This is defaulted to 650ms and can be tuned to any value up to 1500ms.
|
||||||
|
#### ID Seed
|
||||||
|
The seed that starts numbering from this value and is used in the 'Renumbering' button on the 'Bridge Devices' tab. The defaul for this value is 100.
|
||||||
|
#### My Echo URL
|
||||||
|
This sets the URL that is used in the menu bar to ge to your echo. For certain countries, this needs to be set to a different URL.
|
||||||
|
|
||||||
At the bottom of the screen is the "Bridge Settings Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Settings' button will create a backup and name it for you. You can manage these backups by restoring them or deleting them.
|
At the bottom of the screen is the "Bridge Settings Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Settings' button will create a backup and name it for you. You can manage these backups by restoring them, deleting them, downloading them by clicking on the file name and uploading a saved configuration backup on your local machine.
|
||||||
### The Logs Tab
|
### The Logs Tab
|
||||||
This screen displays the last 512 or number of rows defined in the config screen of the log so you don't have to go to the output of your process. The `Update Log` button refreshes the log as this screen does not auto refresh. FYI, when the trace upnp setting is turned on in the configuration, the messages will show here.
|
This screen displays the last 512 or number of rows defined in the config screen of the log so you don't have to go to the output of your process. The `Update Log` button refreshes the log as this screen does not auto refresh. FYI, when the trace upnp setting is turned on in the configuration, the messages will show here.
|
||||||
|
|
||||||
@@ -279,17 +394,28 @@ The bottom part of the Logs Screen has configuration to change the logging level
|
|||||||
### Bridge Device Additions
|
### Bridge Device Additions
|
||||||
You must configure devices before you will have anything for the Echo or other controller that is connected to the ha-bridge to receive.
|
You must configure devices before you will have anything for the Echo or other controller that is connected to the ha-bridge to receive.
|
||||||
#### Helpers
|
#### Helpers
|
||||||
The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest and Hue to create devices that the bridge will present.
|
The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest, Hue and others to create devices that the bridge will present.
|
||||||
|
|
||||||
For the Helpers, each item being presented from the target system has a button such as `Build Item`, `Build A Button` or specific tasks such as `Temp` for thermostats that is used to create the specific device parameters. The build action buttons will put you into the edit screen. The next thing to check is the name for the bridge device that it is something that makes sense especially if you using the ha-bridge with an Echo or Google Home as this is what the Echo or Google Home will interpret as the device you want. 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.
|
For the Helpers, each item being presented from the target system has a button such as `Build Item`, `Build A Button` or specific tasks such as `Temp` for thermostats that is used to create the specific device parameters. The build action buttons will put you into the edit screen. The next thing to check is the name for the bridge device that it is something that makes sense especially if you using the ha-bridge with an Echo or Google Home as this is what the Echo or Google Home will interpret as the device you want. 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. OR you can go back to any helper and use `Build Item` or as such to add another item into the current device being shown in the `Add/Edit` tab. This allows you to create custom devices that execute many devices at once.
|
||||||
|
|
||||||
The helper tabs will also show you what you have already configured for that target type. Click on the `+` and you will see them and be able to delete them.
|
The helper tabs will also show you what you have already configured for that target type. Click on the `+` and you will see them and be able to delete them.
|
||||||
#### The Add/Edit Tab
|
#### The Add/Edit Tab
|
||||||
Another way to add a device is through the Manual Add Tab. This allows you to manually enter the name, the on and off URLs and select if there are custom handling with the type of call that can be made. This allows for control of anything that has a distinct request that can be executed so you are not limited to the Vera, Harmony, Nest or other Hue.
|
This is the main device editing page to modify details or you can add a device through this tab. This allows you to manually enter the name, the on/dim/off/color items and select if there are custom handling with the type of call that can be made. This allows for control of anything that has a distinct request that can be executed so you are not limited to the Vera, Harmony, Nest or other Hue.
|
||||||
|
|
||||||
There is a new format for the on/dim/off URL areas. The new editor handles the intricacies of the components, but is broken down here for explanation.
|
There is a new format for the on/dim/off/color URL areas. The new editor handles the intricacies of the components, but is broken down here for explanation.
|
||||||
|
|
||||||
|
It is imperative when adding a line by hand that you hit the ```Add``` button at the end of the line before adding or updating the whole entry.
|
||||||
|
|
||||||
|
```Update Bridge Device``` Button is for editing a current bridge device entry.
|
||||||
|
|
||||||
|
```Add Bridge Device``` Button is to ccreate a new bridge device entry.
|
||||||
|
|
||||||
|
```Clear``` Button is used to clear the contents of the entry on the screen.
|
||||||
|
|
||||||
|
```Change Edit Mode``` Button is used to swithc back to a pure editor for the on/off/dim/color lines within the device entry.
|
||||||
|
|
||||||
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
|
||||||
@@ -307,12 +433,14 @@ Example from device.db:
|
|||||||
[{"item":<a String that is quoted or another JSON object>,"type":"<atype>"."count":X."delay":X."filterIPs":"<comma separated list of IP addresses that are valid>"."httpVerb":"<GET,PUT,POST>","httpBody":"<body info>","httpHeaders":[{"name":"header name","value":"header value"},{"name":"another header","value":"another value"}],"contentType":"<http content type i.e application/json>"},{"item":<another item>,"type":"<aType>"}]
|
[{"item":<a String that is quoted or another JSON object>,"type":"<atype>"."count":X."delay":X."filterIPs":"<comma separated list of IP addresses that are valid>"."httpVerb":"<GET,PUT,POST>","httpBody":"<body info>","httpHeaders":[{"name":"header name","value":"header value"},{"name":"another header","value":"another value"}],"contentType":"<http content type i.e application/json>"},{"item":<another item>,"type":"<aType>"}]
|
||||||
```
|
```
|
||||||
|
|
||||||
The Add/Edit tab will show you the fields to fill in for the above in a form, when you hcae completed putting in the things you want, make sure to hit the `Add` button at the right.
|
The format of the example is in JSON where the JSON tags equate to the UI labels of the On Items/Dim Items/Off Items. i.e.: JSON item = UI Target Item, JSON type = UI Type, etc...
|
||||||
|
|
||||||
|
The Add/Edit tab will show you the fields to fill in for the above in a form, when you have completed putting in the things you want, make sure to hit the `Add` button at the right.
|
||||||
|
|
||||||
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", "somfyDevice"
|
"halButton", "halHome", "halThermoSet", "mqttMessage", "cmdDevice", "hassDevice", "homewizardDevice", "tcpDevice", "udpDevice", "httpDevice", "domoticzDevice", "somfyDevice"
|
||||||
|
|
||||||
Filter Ip example:
|
Filter Ip example:
|
||||||
```
|
```
|
||||||
@@ -332,7 +460,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} 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.
|
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, "${time.millis}" for inserting a pure timestamp (milliseconds from 1.1.1970), ${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:
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -353,42 +481,30 @@ Examples:
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Multiple Call Construct
|
#### Multiple Call Construct
|
||||||
Also available is the ability to specify multiple commands in the On URL, Dim URL and Off URL areas by adding Json constructs listed here. This is only for the types of tcp, udp, http, https or a new exec type. Also within the item format you can specify delay in milliseconds and count per item. These new parameters work on device buttons for the Harmony as well.
|
Also available is the ability to specify multiple commands in the On Items, Dim Items, Off Items and Color Items by adding a new line to the item. When doing this manually, make sure to hit the `Add` button to the right of the row. If you do not hit the add button, it will not save when the add or update device buttons are selected. You can also add by going to a helper tab after you have entered the `Add/Edit` tab and using the helpers 'Build' buttons to add a new item line in the respected On/Dim/Off/Color items areas.
|
||||||
Format Example in the URL areas:
|
|
||||||
```
|
|
||||||
[{"item":"http://192.168.1.1:8180/do/this/thing","type":"httpDevice"},
|
|
||||||
{"item":"http://192.168.1.1:8180/do/the/next/thing","delay":1000,"count":2,"type":"httpDevice"},
|
|
||||||
{"item":"http://192.168.1.1:8180/do/another/thing","type":"httpDevice"}]
|
|
||||||
|
|
||||||
|
|
||||||
[{"item":"udp://192.168.1.1:5000/0x450555","type":"udpDevice"},
|
|
||||||
{"item":"udp://192.168.1.1:5000/0x45${intensity.percent}55","type":"udpDevice"}]
|
|
||||||
|
|
||||||
[{"item":"udp://192.168.1.1:5000/0x450555","type":"udpDevice"},
|
|
||||||
{"item":"http://192.168.1.1:8180/do/this/thing","type":"httpDevice"},
|
|
||||||
{"item":"tcp://192.168.2.1/sendthisdata","type":"tcpDevice"},
|
|
||||||
{"item":"https://192.168.12.1/do/this/secure/thing","type":"httpDevice"},
|
|
||||||
{"item":"exec://notepad.exe","type":"cmdDevice"}]
|
|
||||||
```
|
|
||||||
#### Script or Command Execution
|
#### Script or Command Execution
|
||||||
The release as of v2.0.0 will now support the execution of a local script or program. This will blindly fire off a process to run and is bound by the privileges of the java process.
|
The release as of v2.0.0 will now support the execution of a local script or program. This will blindly fire off a process to run and is bound by the privileges of the java process.
|
||||||
|
|
||||||
To configure this type of manual add, you will need to select the Device type of "Execute Script/Program".
|
To configure this type of manual add, you will need to select the Device type of "Execute Script/Program".
|
||||||
|
|
||||||
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":"exec://C:\\Users\\John\\Documents\\Applications\\putty.exe 192.168.1.1","type":"cmdDevice"},{"item":"exec://notepad.exe","type":"cmdDevice"}]
|
|
||||||
|
|
||||||
[{"item":"/home/pi/scripts/dothisscript.sh","type":"cmdDevice"}]
|
If you are running a script on a system, you will need to provide the shell interface it will use before the script such as `sh` or `cmd.exe`.
|
||||||
```
|
|
||||||
#### 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.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}".
|
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, there is a ${time.millis} which will put the millis timestamp where this replacement control is located.
|
||||||
|
|
||||||
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.
|
Color has been added as a replacement control and the available values are ${color.r}, ${color.g}, ${color.b} which are representations of each color as 0 - 255. There are hex equivalents as well as ${color.rx}, ${color.gx}, ${color.bx} and ${color.rgbx} as 2 place hex representations except for rgbx which is a six place hex representation.
|
||||||
|
|
||||||
|
Color can also be replaced with ${color.hsl} which will output a string in the Hue/Saturation/Brightness comma-delineated format, useful for many devices under OpenHAB. The format will be a 0-360 hue value, a 0-100 saturation value, and a 0-100 brightness value, separated by commas. (Such devices usually accept either a full HSB value in that format, or a single ${intensity.percent} value for the dimming value, sent as raw text in a POST request.)
|
||||||
|
|
||||||
|
Special handling for milights is included and is handled by ${color.milight:x}. The usage for that is as follows: udp://ip:port/0x${color.milight:x} where x is a number between 0 and 4 (0 all groups, 1-4 specific group). The group is necessary in case the color turns out to be white. The correct group on must of course be sent before that udp packet.
|
||||||
|
Note that milight can only use 255 colors and white is handled completely separate for the rgbw strips, so setting temperature via ct with milight does something but not really the desired result
|
||||||
|
|
||||||
|
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}", "${device.deviceType}", "${device.requesterAddress}", "${device.description}" and "${device.comments}". 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"}]
|
||||||
@@ -401,7 +517,7 @@ e.g.
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Also, you may want to use the REST API's listed below to configure your devices.
|
Also, you may want to use the REST APIs listed below to configure your devices.
|
||||||
## Ask Alexa
|
## Ask Alexa
|
||||||
After this Tell Alexa: "Alexa, discover my devices". If there is an issue you can go to the `Menu / Settings / Connected Home` for the echo on the mobile app or your browser and have Alexa forget all devices and then do the discovery again.
|
After this Tell Alexa: "Alexa, discover my devices". If there is an issue you can go to the `Menu / Settings / Connected Home` for the echo on the mobile app or your browser and have Alexa forget all devices and then do the discovery again.
|
||||||
|
|
||||||
@@ -411,16 +527,13 @@ Here is the table of items to use to tell Alexa what you want to do, this has ch
|
|||||||
|
|
||||||
To do this... | Say this...
|
To do this... | Say this...
|
||||||
--------------|------------
|
--------------|------------
|
||||||
ON Commands |
|
ON Commands | Alexa, turn on `<Device Name>`
|
||||||
| Alexa, turn on `<Device Name>`
|
OFF Commands | Alexa, turn off `<Device Name>`
|
||||||
OFF Commands |
|
DIM Commands | Alexa, brighten `<Device Name>` to `<Position>`
|
||||||
| Alexa, turn off `<Device Name>`
|
DIM Commands| Alexa, dim `<Device Name>` to `<Position>`
|
||||||
DIM Commands |
|
DIM Commands| Alexa, brighten `<Device Name>`
|
||||||
| Alexa, brighten `<Device Name>` to `<Position>`
|
DIM Commands| Alexa, dim `<Device Name>`
|
||||||
| Alexa, dim `<Device Name>` to `<Position>`
|
DIM Commands| Alexa, set `<Device Name>` to `<Position>`
|
||||||
| Alexa, brighten `<Device Name>`
|
|
||||||
| Alexa, dim `<Device Name>`
|
|
||||||
| Alexa, set `<Device Name>` to `<Position>`
|
|
||||||
|
|
||||||
To see what Alexa thinks you said, you can check in the home page for your Alexa.
|
To see what Alexa thinks you said, you can check in the home page for your Alexa.
|
||||||
|
|
||||||
@@ -429,6 +542,8 @@ To view or remove devices that Alexa knows about, you can use the mobile app `Me
|
|||||||
## Google Assistant
|
## Google Assistant
|
||||||
Google Home is supported as of v3.2.0 and forward, but only if the bridge is running on port 80.
|
Google Home is supported as of v3.2.0 and forward, but only if the bridge is running on port 80.
|
||||||
|
|
||||||
|
**ISSUE: Google Home does NOT support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work. If you have an older Google Home application, this may still work. YMMV.**
|
||||||
|
|
||||||
Use the Google Home app on a phone to add new "home control" devices by going into `Settings / Home Control / +`
|
Use the Google Home app on a phone to add new "home control" devices by going into `Settings / Home Control / +`
|
||||||
as described [here](https://support.google.com/googlehome/answer/7124115?hl=en&ref_topic=7125624#homecontrol).
|
as described [here](https://support.google.com/googlehome/answer/7124115?hl=en&ref_topic=7125624#homecontrol).
|
||||||
Click on `Philips Hue` under the `Add new` section. If ha-bridge is on the same network as the
|
Click on `Philips Hue` under the `Add new` section. If ha-bridge is on the same network as the
|
||||||
@@ -459,7 +574,7 @@ New or removed devices are picked up automatically as soon as they are added/rem
|
|||||||
No re-discovery step is necessary.
|
No re-discovery step is necessary.
|
||||||
|
|
||||||
## Configuration REST API Usage
|
## Configuration REST API Usage
|
||||||
This section will describe the REST api available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
This section will describe the REST API available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
||||||
```
|
```
|
||||||
{"var1":"value1","var2":"value2","var3:"value3"}
|
{"var1":"value1","var2":"value2","var3:"value3"}
|
||||||
```
|
```
|
||||||
@@ -491,8 +606,8 @@ contentBodyOff | string | This is the content body that you would like to send w
|
|||||||
{
|
{
|
||||||
"name" : "bedroom light",
|
"name" : "bedroom light",
|
||||||
"deviceType" : "switch",
|
"deviceType" : "switch",
|
||||||
"onUrl" : [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=41","type":"veraDevice"}],
|
"onUrl" : "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=41\",\"type\":\"veraDevice\"}]",
|
||||||
"offUrl" : [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41","type":"veraDevice"}]
|
"offUrl" : "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41\",\"type\":\"veraDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Dimming Control Example
|
#### Dimming Control Example
|
||||||
@@ -502,8 +617,8 @@ e.g.
|
|||||||
{
|
{
|
||||||
"name": "entry light",
|
"name": "entry light",
|
||||||
"deviceType": "switch",
|
"deviceType": "switch",
|
||||||
"offUrl": [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=31","type":"veraDevice"}],
|
"offUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=31\",\"type\":\"veraDevice\"}]",
|
||||||
"onUrl": [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}","type":"veraDevice"}]
|
"onUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}\",\"type\":\"veraDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
See the echo's documentation for the dimming phrase.
|
See the echo's documentation for the dimming phrase.
|
||||||
@@ -515,8 +630,8 @@ e.g.
|
|||||||
{
|
{
|
||||||
"name": "Thermostat,
|
"name": "Thermostat,
|
||||||
"deviceType": "custom",
|
"deviceType": "custom",
|
||||||
"offUrl": [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=10","type":"veraDevice"}],
|
"offUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=10\",\"type\":\"veraDevice\"}]",
|
||||||
"onUrl": [{"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":"veraDevice"}]
|
"onUrl": "[{\"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\":\"veraDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
See the echo's documentation for the dimming phrase.
|
See the echo's documentation for the dimming phrase.
|
||||||
@@ -528,8 +643,8 @@ e.g:
|
|||||||
{
|
{
|
||||||
"name": "test device",
|
"name": "test device",
|
||||||
"deviceType": "custom",
|
"deviceType": "custom",
|
||||||
"offUrl": [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=31","httpVerb":"POST","contentType" : "application/json","httpBody" : "{\"fooBar\":\"baz_off\"}],
|
"offUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=31\",\"httpVerb\":\"POST\",\"contentType\" : \"application/json\",\"httpBody\" : \"{\"fooBar\":\"baz_off\"}]",
|
||||||
"onUrl": [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}","type":"httpDevice","httpVerb":"POST","contentType" : "application/json","httpBody" : "{\"fooBar\":\"baz_on\"}]
|
"onUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&DeviceNum=31&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=${intensity.percent}\",\"type\":\"httpDevice\",\"httpVerb\":\"POST\",\"contentType\" : \"application/json\",\"httpBody\" : \"{\"fooBar\":\"baz_on\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Custom Usage URLs Example
|
#### Custom Usage URLs Example
|
||||||
@@ -538,8 +653,8 @@ Anything that takes an action as a result of an HTTP request will probably work
|
|||||||
{
|
{
|
||||||
"name": "night mode",
|
"name": "night mode",
|
||||||
"deviceType": ""custom",
|
"deviceType": ""custom",
|
||||||
"offUrl": [{"item":"http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=1","type":"httpDevice"}],
|
"offUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=1\",\"type\":\"httpDevice\"}]",
|
||||||
"onUrl": [{"item":"http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=3","type":"httpDevice"}]
|
"onUrl": "[{\"item\":\"http://192.168.1.201:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode=3\",\"type\":\"httpDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Here is a UDP example that can send binary data.
|
Here is a UDP example that can send binary data.
|
||||||
@@ -547,8 +662,8 @@ Here is a UDP example that can send binary data.
|
|||||||
{
|
{
|
||||||
"name": "UDPPacket",
|
"name": "UDPPacket",
|
||||||
"deviceType": "custom",
|
"deviceType": "custom",
|
||||||
"offUrl": [{"item":"udp://192.168.1.1:8899/0x460055","type":"udpDevice"}],
|
"offUrl": "[{\"item\":\"udp://192.168.1.1:8899/0x460055\",\"type\":\"udpDevice\"}]",
|
||||||
"onUrl": [{"item":"udp://192.168.1.1:8899/0x450055","type":"udpDevice"}]
|
"onUrl": "[{\"item\":\"udp://192.168.1.1:8899/0x450055\",\"type\":\"udpDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Response
|
#### Response
|
||||||
@@ -607,8 +722,8 @@ contentBodyOff | string | This is the content body that you would like to send w
|
|||||||
"id" : "6789",
|
"id" : "6789",
|
||||||
"name" : "table light",
|
"name" : "table light",
|
||||||
"deviceType" : "switch",
|
"deviceType" : "switch",
|
||||||
"onUrl" : [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=41","type":"veraDevice"}],
|
"onUrl" : "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=41\",\"type\":\"veraDevice\"}]",
|
||||||
"offUrl" : [{"item":"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41","type":"veraDevice"}]
|
"offUrl" : "[{\"item\":\"http://192.168.1.201:3480/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=41\",\"type\":\"veraDevice\"}]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Response
|
#### Response
|
||||||
@@ -861,7 +976,7 @@ The example below is representative of some HUE device responses.
|
|||||||
|
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
-----|-------|-------------
|
-----|-------|-------------
|
||||||
device | HUE lights object | The HUE light detail descriptor, see api for lights response below.
|
device | HUE lights object | The HUE light detail descriptor, see API for lights response below.
|
||||||
huedeviceid | string | The id of the actual passthru HUE light id.
|
huedeviceid | string | The id of the actual passthru HUE light id.
|
||||||
hueaddress | string | The address of the target HUE bridge.
|
hueaddress | string | The address of the target HUE bridge.
|
||||||
huename | string | A name given to the target HUE bridge.
|
huename | string | A name given to the target HUE bridge.
|
||||||
@@ -870,7 +985,7 @@ huename | string | A name given to the target HUE bridge.
|
|||||||
[{"device":{"state":{"on":true,"bri":254,"hue":4444,"sat":254,"effect":"none","ct":0,"alert":"none","colormode":"hs","reachable":true,"xy":[0.0,0.0]},"type":"Extended color light","name":"Hue Lamp 1","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0a","swversion":"65003148"},"huedeviceid":"1","hueaddress":"192.168.0.118:8000","huename":"HueEmul"},{"device":{"state":{"on":true,"bri":254,"hue":23536,"sat":144,"effect":"none","ct":201,"alert":"none","colormode":"hs","reachable":true,"xy":[0.346,0.3568]},"type":"Extended color light","name":"Hue Lamp 2","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0b","swversion":"65003148"},"huedeviceid":"2","hueaddress":"192.168.0.118:8000","huename":"HueEmul"},{"device":{"state":{"on":true,"bri":254,"hue":65136,"sat":254,"effect":"none","ct":201,"alert":"none","colormode":"hs","reachable":true,"xy":[0.346,0.3568]},"type":"Extended color light","name":"Hue Lamp 3","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0c","swversion":"65003148"},"huedeviceid":"3","hueaddress":"192.168.0.118:8000","huename":"HueEmul"}]
|
[{"device":{"state":{"on":true,"bri":254,"hue":4444,"sat":254,"effect":"none","ct":0,"alert":"none","colormode":"hs","reachable":true,"xy":[0.0,0.0]},"type":"Extended color light","name":"Hue Lamp 1","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0a","swversion":"65003148"},"huedeviceid":"1","hueaddress":"192.168.0.118:8000","huename":"HueEmul"},{"device":{"state":{"on":true,"bri":254,"hue":23536,"sat":144,"effect":"none","ct":201,"alert":"none","colormode":"hs","reachable":true,"xy":[0.346,0.3568]},"type":"Extended color light","name":"Hue Lamp 2","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0b","swversion":"65003148"},"huedeviceid":"2","hueaddress":"192.168.0.118:8000","huename":"HueEmul"},{"device":{"state":{"on":true,"bri":254,"hue":65136,"sat":254,"effect":"none","ct":201,"alert":"none","colormode":"hs","reachable":true,"xy":[0.346,0.3568]},"type":"Extended color light","name":"Hue Lamp 3","modelid":"LCT001","uniqueid":"00:17:88:01:00:d4:12:08-0c","swversion":"65003148"},"huedeviceid":"3","hueaddress":"192.168.0.118:8000","huename":"HueEmul"}]
|
||||||
```
|
```
|
||||||
## HUE REST API usage
|
## HUE REST API usage
|
||||||
This section will describe the REST api available for controlling the bridge based off of the HUE API. This Bridge does not support the full HUE API, only the calls that are supported with the HA Bridge are shown. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
This section will describe the REST API available for controlling the bridge based off of the HUE API. This Bridge does not support the full HUE API, only the calls that are supported with the HA Bridge are shown. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
||||||
```
|
```
|
||||||
{"var1":"value1","var2":"value2","var3:"value3"}
|
{"var1":"value1","var2":"value2","var3:"value3"}
|
||||||
```
|
```
|
||||||
@@ -979,7 +1094,7 @@ A response to a successful PUT request contains confirmation of the arguments pa
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
### Update bridge internal light state
|
### Update bridge internal light state
|
||||||
Allows the user to set the internal state of the light on and off, modify the brightness. This is not a HUE API call and is special to the bridge as it keeps track of the state changes to the light from the api. It is intended to allow you to sync the bridge state with your HA system state.
|
Allows the user to set the internal state of the light on and off, modify the brightness. This is not a HUE API call and is special to the bridge as it keeps track of the state changes to the light from the API. It is intended to allow you to sync the bridge state with your HA system state.
|
||||||
```
|
```
|
||||||
PUT http://host:port/api/<username>/lights/<id>/bridgeupdatestate
|
PUT http://host:port/api/<username>/lights/<id>/bridgeupdatestate
|
||||||
```
|
```
|
||||||
|
|||||||
263
pom.xml
263
pom.xml
@@ -1,160 +1,208 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>4.3.1</version>
|
<version>5.3.1RC1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub or Nest, using lightweight frameworks</description>
|
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub or Nest, using lightweight frameworks</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>jitpack.io</id>
|
<id>jitpack.io</id>
|
||||||
<url>https://jitpack.io</url>
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>Eclipse Paho Repo</id>
|
||||||
|
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
|
||||||
<id>Eclipse Paho Repo</id>
|
|
||||||
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.bwssytems</groupId>
|
<groupId>com.github.bwssytems</groupId>
|
||||||
<artifactId>harmony-java-client</artifactId>
|
<artifactId>harmony-java-client</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>master-SNAPSHOT</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>log4j-over-slf4j</artifactId>
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.bwssytems</groupId>
|
|
||||||
<artifactId>nest-controller</artifactId>
|
|
||||||
<version>1.0.14</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-simple</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>log4j-over-slf4j</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sparkjava</groupId>
|
<groupId>com.github.bwssytems</groupId>
|
||||||
<artifactId>spark-core</artifactId>
|
<artifactId>nest-controller</artifactId>
|
||||||
<version>2.3</version>
|
<version>1.0.14</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<groupId>org.slf4j</groupId>
|
||||||
<groupId>org.slf4j</groupId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sparkjava</groupId>
|
||||||
|
<artifactId>spark-core</artifactId>
|
||||||
|
<version>2.7.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
<version>4.5.1</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpcore</artifactId>
|
<artifactId>httpcore</artifactId>
|
||||||
<version>4.4.4</version>
|
<version>4.4.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>1.7.5</version>
|
<version>1.7.24</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.1.5</version>
|
<version>1.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<version>2.6.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.eval</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>eval</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>0.5</version>
|
<version>2.6.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.java.dev.eval</groupId>
|
||||||
|
<artifactId>eval</artifactId>
|
||||||
|
<version>0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.inject</groupId>
|
<groupId>com.google.inject</groupId>
|
||||||
<artifactId>guice</artifactId>
|
<artifactId>guice</artifactId>
|
||||||
<version>4.0-beta4</version>
|
<version>4.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.igniterealtime.smack</groupId>
|
<groupId>org.igniterealtime.smack</groupId>
|
||||||
<artifactId>smack-core</artifactId>
|
<artifactId>smack-core</artifactId>
|
||||||
<version>4.0.7</version>
|
<version>4.2.0</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.paho</groupId>
|
|
||||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
|
||||||
<version>1.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.11</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.bwssytems</groupId>
|
<groupId>org.eclipse.paho</groupId>
|
||||||
<artifactId>lifx-sdk-java</artifactId>
|
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||||
<version>2.1.6</version>
|
<version>1.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>3.5</version>
|
<version>4.13.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.bwssytems</groupId>
|
||||||
|
<artifactId>lifx-sdk-java</artifactId>
|
||||||
|
<version>2.1.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.mob41</groupId>
|
||||||
|
<artifactId>broadlink-java-api</artifactId>
|
||||||
|
<version>master-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jmdns</groupId>
|
||||||
|
<artifactId>jmdns</artifactId>
|
||||||
|
<version>3.5.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>version.properties</include>
|
<include>version.properties</include>
|
||||||
</includes>
|
</includes>
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>version.properties</exclude>
|
<exclude>version.properties</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
<filtering>false</filtering>
|
<filtering>false</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
|
<version>3.0.0-M2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>enforce-maven</id>
|
||||||
|
<goals>
|
||||||
|
<goal>enforce</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<rules>
|
||||||
|
<requireMavenVersion>
|
||||||
|
<!-- Change this to Version 3.3 for Java 1.8 and Raspberry PI compilation -->
|
||||||
|
<version>3.6</version>
|
||||||
|
</requireMavenVersion>
|
||||||
|
</rules>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin> <plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<!-- Comment this release line out for Java 1.8 and Raspberry PI compilation -->
|
||||||
|
<release>11</release>
|
||||||
|
<!-- Uncomment the next two lines for Java 1.8 and Raspberry PI compilation -->
|
||||||
|
<!-- <source>1.8</source> -->
|
||||||
|
<!-- <target>1.8</target> -->
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M3</version>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>false</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4.3</version>
|
<version>3.2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@@ -216,8 +264,7 @@
|
|||||||
</filter>
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
|
||||||
<mainClass>com.bwssystems.HABridge.HABridge</mainClass>
|
<mainClass>com.bwssystems.HABridge.HABridge</mainClass>
|
||||||
</transformer>
|
</transformer>
|
||||||
</transformers>
|
</transformers>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.bwssystems.HABridge;
|
|||||||
public class BridgeControlDescriptor {
|
public class BridgeControlDescriptor {
|
||||||
private boolean reinit;
|
private boolean reinit;
|
||||||
private boolean stop;
|
private boolean stop;
|
||||||
|
private boolean linkButton;
|
||||||
|
|
||||||
public BridgeControlDescriptor() {
|
public BridgeControlDescriptor() {
|
||||||
super();
|
super();
|
||||||
@@ -22,4 +23,12 @@ public class BridgeControlDescriptor {
|
|||||||
public void setStop(boolean stop) {
|
public void setStop(boolean stop) {
|
||||||
this.stop = stop;
|
this.stop = stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLinkButton() {
|
||||||
|
return linkButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkButton(boolean linkButton) {
|
||||||
|
this.linkButton = linkButton;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
470
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
470
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueError;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
|
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
import spark.Request;
|
||||||
|
|
||||||
|
public class BridgeSecurity {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BridgeSecurity.class);
|
||||||
|
private static final String USER_SESSION_ID = "user";
|
||||||
|
private static final String DEPRACATED_INTERNAL_USER = "thehabridgeuser";
|
||||||
|
private static final String TEST_USER_TYPE = "test_ha_bridge";
|
||||||
|
private static final byte[] SALT = {
|
||||||
|
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||||
|
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||||
|
};
|
||||||
|
private static char[] habridgeKey;
|
||||||
|
private String execGarden;
|
||||||
|
private BridgeSecurityDescriptor securityDescriptor;
|
||||||
|
private boolean settingsChanged;
|
||||||
|
|
||||||
|
public BridgeSecurity(char[] theKey, String theExecGarden) {
|
||||||
|
habridgeKey = theKey;
|
||||||
|
execGarden = theExecGarden;
|
||||||
|
securityDescriptor = null;
|
||||||
|
settingsChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurityData(String theData) {
|
||||||
|
String anError = null;
|
||||||
|
if(theData != null && !theData.isEmpty()) {
|
||||||
|
try {
|
||||||
|
securityDescriptor = new Gson().fromJson(decrypt(theData), BridgeSecurityDescriptor.class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
anError = e.getMessage();
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
anError = e.getMessage();
|
||||||
|
} catch (IOException e) {
|
||||||
|
anError = e.getMessage();
|
||||||
|
}
|
||||||
|
if(anError != null)
|
||||||
|
log.warn("Cound not get security data, using default security (none): " + anError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(theData == null || anError != null) {
|
||||||
|
securityDescriptor = new BridgeSecurityDescriptor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecurityDescriptorData() throws UnsupportedEncodingException, GeneralSecurityException {
|
||||||
|
return encrypt(new Gson().toJson(securityDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseLinkButton() {
|
||||||
|
return securityDescriptor.isUseLinkButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String setPassword(User aUser) throws IOException {
|
||||||
|
String error = null;
|
||||||
|
if(aUser != null) {
|
||||||
|
error = aUser.validate();
|
||||||
|
if(error == null) {
|
||||||
|
if(securityDescriptor.getUsers() != null) {
|
||||||
|
User theUser = securityDescriptor.getUsers().get(aUser.getUsername());
|
||||||
|
if(theUser != null) {
|
||||||
|
theUser.setPassword(aUser.getPassword());
|
||||||
|
theUser.setPassword2(null);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "User not found";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "User not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "invalid user object given";
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String addUser(User aUser) throws IOException {
|
||||||
|
String error = null;
|
||||||
|
if(aUser != null) {
|
||||||
|
error = aUser.validate();
|
||||||
|
if(error == null) {
|
||||||
|
if(securityDescriptor.getUsers() == null)
|
||||||
|
securityDescriptor.setUsers(new HashMap<String, User>());
|
||||||
|
if(securityDescriptor.getUsers().get(aUser.getUsername()) == null) {
|
||||||
|
securityDescriptor.getUsers().put(aUser.getUsername(), aUser);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "Invalid request";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "invalid user object given";
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String delUser(User aUser) throws IOException {
|
||||||
|
String error = null;
|
||||||
|
if(aUser != null) {
|
||||||
|
if(securityDescriptor.getUsers() != null) {
|
||||||
|
if(securityDescriptor.getUsers().get(aUser.getUsername()) != null) {
|
||||||
|
securityDescriptor.getUsers().remove(aUser.getUsername());
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "User not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = "invalid user object given";
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecGarden() {
|
||||||
|
return execGarden;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getKeyfilePath() {
|
||||||
|
return securityDescriptor.getKeyfilePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getKeyfilePassword() {
|
||||||
|
return securityDescriptor.getKeyfilePassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUseLinkButton(boolean useThis) {
|
||||||
|
securityDescriptor.setUseLinkButton(useThis);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecureHueApi() {
|
||||||
|
return securityDescriptor.isSecureHueApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseHttps() {
|
||||||
|
return securityDescriptor.isUseHttps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKeyfilePW() {
|
||||||
|
if(securityDescriptor.getKeyfilePassword() != null && !securityDescriptor.getKeyfilePassword().trim().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSecureHueApi(boolean theState) {
|
||||||
|
securityDescriptor.setSecureHueApi(theState);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUseHttps(boolean usehttps, String keyfilepath, String keyfilepassword) {
|
||||||
|
if(usehttps) {
|
||||||
|
if(!isUseHttps()) {
|
||||||
|
securityDescriptor.setKeyfilePath(keyfilepath);
|
||||||
|
securityDescriptor.setKeyfilePassword(keyfilepassword);
|
||||||
|
securityDescriptor.setUseHttps(usehttps);
|
||||||
|
settingsChanged = true;
|
||||||
|
} else {
|
||||||
|
if(!keyfilepassword.equals("########")) {
|
||||||
|
securityDescriptor.setKeyfilePassword(keyfilepassword);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!securityDescriptor.getKeyfilePath().equals(keyfilepath)) {
|
||||||
|
securityDescriptor.setKeyfilePath(keyfilepath);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(isUseHttps()) {
|
||||||
|
securityDescriptor.setKeyfilePassword("");
|
||||||
|
securityDescriptor.setKeyfilePath("");
|
||||||
|
securityDescriptor.setUseHttps(usehttps);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityInfo getSecurityInfo() {
|
||||||
|
SecurityInfo theInfo = new SecurityInfo();
|
||||||
|
theInfo.setUseLinkButton(isUseLinkButton());
|
||||||
|
theInfo.setSecureHueApi(isSecureHueApi());
|
||||||
|
theInfo.setSecure(isSecure());
|
||||||
|
theInfo.setUseHttps(isUseHttps());
|
||||||
|
theInfo.setKeyfilePath(securityDescriptor.getKeyfilePath());
|
||||||
|
|
||||||
|
if(isKeyfilePW()) {
|
||||||
|
theInfo.setKeyfilePassword("########");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theInfo.setKeyfilePassword("");
|
||||||
|
}
|
||||||
|
if(isSecure()) {
|
||||||
|
theInfo.setExecGarden(execGarden);
|
||||||
|
}
|
||||||
|
return theInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurityDataByInfo(SecurityInfo theInfo) {
|
||||||
|
setUseLinkButton(theInfo.isUseLinkButton());
|
||||||
|
setSecureHueApi(theInfo.isSecureHueApi());
|
||||||
|
setUseHttps(theInfo.isUseHttps(), theInfo.getKeyfilePath(), theInfo.getKeyfilePassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginResult validatePassword(User targetUser) throws IOException {
|
||||||
|
LoginResult result = new LoginResult();
|
||||||
|
if(targetUser != null && targetUser.getUsername() != null) {
|
||||||
|
if(securityDescriptor.getUsers() != null && securityDescriptor.getUsers().get(targetUser.getUsername()) != null) {
|
||||||
|
User theUser = securityDescriptor.getUsers().get(targetUser.getUsername());
|
||||||
|
if(theUser.getPassword() != null) {
|
||||||
|
theUser.setPassword2(targetUser.getPassword());
|
||||||
|
if(theUser.validatePassword()) {
|
||||||
|
theUser.setPassword2(null);
|
||||||
|
result.setUser(targetUser);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.setError("user or password not correct");
|
||||||
|
} else {
|
||||||
|
result.setError("input password is not set....");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.setError("user or password not correct");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.setError("input user not given");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecure() {
|
||||||
|
return securityDescriptor.isSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSettingsChanged() {
|
||||||
|
return settingsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSettingsChanged(boolean settingsChanged) {
|
||||||
|
this.settingsChanged = settingsChanged;
|
||||||
|
}
|
||||||
|
public Map<String, WhitelistEntry> getWhitelist() {
|
||||||
|
return securityDescriptor.getWhitelist();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhitelist(Map<String, WhitelistEntry> aWhitelist) {
|
||||||
|
securityDescriptor.setWhitelist(aWhitelist);
|
||||||
|
settingsChanged = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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("") && !aUser.equals(DEPRACATED_INTERNAL_USER)) {
|
||||||
|
if (securityDescriptor.getWhitelist() != null) {
|
||||||
|
Set<String> theUserIds = securityDescriptor.getWhitelist().keySet();
|
||||||
|
Iterator<String> userIterator = theUserIds.iterator();
|
||||||
|
while (userIterator.hasNext()) {
|
||||||
|
validUser = userIterator.next();
|
||||||
|
if (validUser.equals(aUser)) {
|
||||||
|
found = true;
|
||||||
|
log.debug("validateWhitelistUser: found a user <" + aUser + ">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found && !strict) {
|
||||||
|
log.debug("validateWhitelistUser: a user was not found and it is not strict rules <" + aUser + "> being created");
|
||||||
|
newWhitelistUser(aUser, userDescription);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
log.debug("validateWhitelistUser: a user was not found and strict rules is set to: " + strict + "for user <" + aUser + ">");
|
||||||
|
return HueErrorResponse.createResponse("1", "/api/" + aUser == null ? "" : aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findWhitelistUserByDeviceType(String aDeviceType) {
|
||||||
|
String validUser = null;
|
||||||
|
boolean found = false;
|
||||||
|
WhitelistEntry anEntry = null;
|
||||||
|
if (aDeviceType != null) {
|
||||||
|
if (securityDescriptor.getWhitelist() != null) {
|
||||||
|
Set<String> theUserIds = securityDescriptor.getWhitelist().keySet();
|
||||||
|
Iterator<String> userIterator = theUserIds.iterator();
|
||||||
|
while (!found && userIterator.hasNext()) {
|
||||||
|
validUser = userIterator.next();
|
||||||
|
anEntry = securityDescriptor.getWhitelist().get(validUser);
|
||||||
|
if (anEntry.getName().equals(aDeviceType)) {
|
||||||
|
found = true;
|
||||||
|
log.debug("findWhitelistUserByDeviceType: found a user <" + validUser + "> for device type <" + aDeviceType + ">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found)
|
||||||
|
validUser = null;
|
||||||
|
|
||||||
|
return validUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newWhitelistUser(String aUser, String userDescription) {
|
||||||
|
if (securityDescriptor.getWhitelist() == null) {
|
||||||
|
securityDescriptor.setWhitelist(new HashMap<>());
|
||||||
|
}
|
||||||
|
if(userDescription == null)
|
||||||
|
userDescription = "auto insert user";
|
||||||
|
|
||||||
|
securityDescriptor.getWhitelist().put(aUser, WhitelistEntry.createEntry(userDescription));
|
||||||
|
setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createWhitelistUser(String userDescription) {
|
||||||
|
String aUser = null;
|
||||||
|
String theEntry = findWhitelistUserByDeviceType(userDescription);
|
||||||
|
if(theEntry == null) {
|
||||||
|
aUser = getNewUserID();
|
||||||
|
newWhitelistUser(aUser, userDescription);
|
||||||
|
} else {
|
||||||
|
aUser = theEntry;
|
||||||
|
}
|
||||||
|
return aUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||||
|
securityDescriptor.setWhitelist(whitelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void removeHttpsSettings() {
|
||||||
|
securityDescriptor.setUseHttps(false);
|
||||||
|
securityDescriptor.setKeyfilePassword(null);
|
||||||
|
securityDescriptor.setKeyfilePath(null);
|
||||||
|
setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTestUsers() {
|
||||||
|
if (securityDescriptor.getWhitelist() != null) {
|
||||||
|
Object anUser = securityDescriptor.getWhitelist().remove(DEPRACATED_INTERNAL_USER);
|
||||||
|
if(anUser != null)
|
||||||
|
setSettingsChanged(true);
|
||||||
|
|
||||||
|
Iterator<Entry<String, WhitelistEntry>> it = securityDescriptor.getWhitelist().entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Map.Entry<String, WhitelistEntry> pair = it.next();
|
||||||
|
if(pair.getValue().getName().equals(TEST_USER_TYPE)) {
|
||||||
|
it.remove(); // avoids a ConcurrentModificationException
|
||||||
|
setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||||
|
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||||
|
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||||
|
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
|
||||||
|
return base64Encode(pbeCipher.doFinal(property.getBytes("UTF-8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String base64Encode(byte[] bytes) {
|
||||||
|
return Base64.getEncoder().encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String decrypt(String property) throws GeneralSecurityException, IOException {
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||||
|
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||||
|
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||||
|
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
|
||||||
|
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] base64Decode(String property) throws IOException {
|
||||||
|
return Base64.getDecoder().decode(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAuthenticatedUser(Request request, User u) {
|
||||||
|
request.session().attribute(USER_SESSION_ID, u);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAuthenticatedUser(Request request) {
|
||||||
|
request.session().removeAttribute(USER_SESSION_ID);
|
||||||
|
request.session().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getAuthenticatedUser(Request request) {
|
||||||
|
User theUser = request.session().attribute(USER_SESSION_ID);
|
||||||
|
if(theUser == null) {
|
||||||
|
String authHeader = request.headers("Authorization");
|
||||||
|
if(authHeader != null) {
|
||||||
|
byte[] authData;
|
||||||
|
try {
|
||||||
|
authData = base64Decode(authHeader.substring(6));
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
return theUser;
|
||||||
|
}
|
||||||
|
String[] credentials = new String(authData).split(":");
|
||||||
|
String username = credentials[0];
|
||||||
|
String password = credentials[1];
|
||||||
|
theUser = new User();
|
||||||
|
theUser.setUsername(username);
|
||||||
|
theUser.setPassword(password);
|
||||||
|
LoginResult theResult = null;
|
||||||
|
try {
|
||||||
|
theResult = validatePassword(theUser);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(theResult != null && theResult.getError() == null) {
|
||||||
|
addAuthenticatedUser(request, theUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||||
|
|
||||||
|
public class BridgeSecurityDescriptor {
|
||||||
|
private Map<String, User> users;
|
||||||
|
private boolean useLinkButton;
|
||||||
|
private String execGarden;
|
||||||
|
private boolean secureHueApi;
|
||||||
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
|
private boolean useHttps;
|
||||||
|
private String keyfilePassword;
|
||||||
|
private String keyfilePath;
|
||||||
|
|
||||||
|
public BridgeSecurityDescriptor() {
|
||||||
|
super();
|
||||||
|
this.setUseLinkButton(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, User> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsers(Map<String, User> users) {
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseLinkButton() {
|
||||||
|
return useLinkButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseLinkButton(boolean useLinkButton) {
|
||||||
|
this.useLinkButton = useLinkButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecGarden() {
|
||||||
|
return execGarden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecGarden(String execGarden) {
|
||||||
|
this.execGarden = execGarden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecureHueApi() {
|
||||||
|
return secureHueApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecureHueApi(boolean secureHueApi) {
|
||||||
|
this.secureHueApi = secureHueApi;
|
||||||
|
}
|
||||||
|
public Map<String, WhitelistEntry> getWhitelist() {
|
||||||
|
return whitelist;
|
||||||
|
}
|
||||||
|
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecure() {
|
||||||
|
boolean secureFlag = false;
|
||||||
|
if(users != null && !users.isEmpty()) {
|
||||||
|
for (Map.Entry<String, User> entry : users.entrySet())
|
||||||
|
{
|
||||||
|
if(entry.getValue().getPassword() != null && !entry.getValue().getPassword().isEmpty()) {
|
||||||
|
secureFlag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return secureFlag;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseHttps() {
|
||||||
|
return useHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseHttps(boolean useHttps) {
|
||||||
|
this.useHttps = useHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyfilePassword() {
|
||||||
|
return keyfilePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyfilePassword(String keyfilePassword) {
|
||||||
|
this.keyfilePassword = keyfilePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyfilePath() {
|
||||||
|
return keyfilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyfilePath(String keyfilePath) {
|
||||||
|
this.keyfilePath = keyfilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
@@ -10,6 +11,9 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.nio.file.attribute.PosixFilePermission;
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -20,18 +24,27 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.bwssystems.HABridge.util.BackupHandler;
|
import com.bwssystems.HABridge.util.BackupHandler;
|
||||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
|
import com.bwssystems.HABridge.util.ParseRoute;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class BridgeSettings extends BackupHandler {
|
public class BridgeSettings extends BackupHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||||
private BridgeSettingsDescriptor theBridgeSettings;
|
private BridgeSettingsDescriptor theBridgeSettings;
|
||||||
private BridgeControlDescriptor bridgeControl;
|
private BridgeControlDescriptor bridgeControl;
|
||||||
|
private BridgeSecurity bridgeSecurity;
|
||||||
|
private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss");
|
||||||
|
|
||||||
public BridgeSettings() {
|
public BridgeSettings() {
|
||||||
super();
|
super();
|
||||||
bridgeControl = new BridgeControlDescriptor();
|
bridgeControl = new BridgeControlDescriptor();
|
||||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
bridgeSecurity = null;
|
||||||
|
String theKey = System.getProperty("security.key");
|
||||||
|
if(theKey == null)
|
||||||
|
theKey = "IWantMyPasswordsToBeAbleToBeDecodedPleaseSeeTheReadme";
|
||||||
|
String execGarden = System.getProperty("exec.garden");
|
||||||
|
bridgeSecurity = new BridgeSecurity(theKey.toCharArray(), execGarden);
|
||||||
|
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||||
}
|
}
|
||||||
@@ -43,9 +56,17 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
||||||
return theBridgeSettings;
|
return theBridgeSettings;
|
||||||
}
|
}
|
||||||
|
public BridgeSecurity getBridgeSecurity() {
|
||||||
|
return bridgeSecurity;
|
||||||
|
}
|
||||||
|
public String getCurrentDate() {
|
||||||
|
return LocalDateTime.now().format(dateTimeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
public void buildSettings() {
|
public void buildSettings() {
|
||||||
String addressString = null;
|
String addressString = null;
|
||||||
String theVeraAddress = null;
|
String theVeraAddress = null;
|
||||||
|
String theFibaroAddress = null;
|
||||||
String theSomfyAddress = null;
|
String theSomfyAddress = null;
|
||||||
String theHarmonyAddress = null;
|
String theHarmonyAddress = null;
|
||||||
String configFileProperty = System.getProperty("config.file");
|
String configFileProperty = System.getProperty("config.file");
|
||||||
@@ -71,6 +92,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
|
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
|
||||||
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
|
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
|
||||||
theBridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db"));
|
theBridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db"));
|
||||||
|
theBridgeSettings.setUpnpGroupDb(System.getProperty("upnp.group.db"));
|
||||||
theBridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
theBridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||||
|
|
||||||
theVeraAddress = System.getProperty("vera.address");
|
theVeraAddress = System.getProperty("vera.address");
|
||||||
@@ -89,6 +111,22 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
theBridgeSettings.setVeraAddress(theVeraList);
|
theBridgeSettings.setVeraAddress(theVeraList);
|
||||||
|
|
||||||
|
theFibaroAddress = System.getProperty("fibaro.address");
|
||||||
|
IpList theFibaroList = null;
|
||||||
|
if(theFibaroAddress != null) {
|
||||||
|
try {
|
||||||
|
theFibaroList = new Gson().fromJson(theFibaroAddress, IpList.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
theFibaroList = new Gson().fromJson("{devices:[{name:default,ip:" + theFibaroAddress + "}]}", IpList.class);
|
||||||
|
} catch (Exception et) {
|
||||||
|
log.error("Cannot parse fibaro.address, not set with message: " + e.getMessage(), e);
|
||||||
|
theFibaroList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theBridgeSettings.setFibaroAddress(theFibaroList);
|
||||||
|
|
||||||
theHarmonyAddress = System.getProperty("harmony.address");
|
theHarmonyAddress = System.getProperty("harmony.address");
|
||||||
IpList theHarmonyList = null;
|
IpList theHarmonyList = null;
|
||||||
if(theHarmonyAddress != null) {
|
if(theHarmonyAddress != null) {
|
||||||
@@ -121,15 +159,16 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
theBridgeSettings.setSomfyAddress(theSomfyList);
|
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)));
|
||||||
theBridgeSettings.setNestuser(System.getProperty("nest.user"));
|
theBridgeSettings.setNestuser(System.getProperty("nest.user"));
|
||||||
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
|
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().equals("")) {
|
ParseRoute aDefaultRoute = ParseRoute.getInstance();
|
||||||
addressString = checkIpAddress(null, true);
|
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().trim().equals("") || theBridgeSettings.getUpnpConfigAddress().trim().equals("0.0.0.0")) {
|
||||||
|
addressString = aDefaultRoute.getLocalIPAddress();
|
||||||
if(addressString != null) {
|
if(addressString != null) {
|
||||||
theBridgeSettings.setUpnpConfigAddress(addressString);
|
theBridgeSettings.setUpnpConfigAddress(addressString);
|
||||||
log.info("Adding " + addressString + " as our default upnp config address.");
|
log.info("Adding " + addressString + " as our default upnp config address.");
|
||||||
@@ -139,8 +178,10 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addressString = checkIpAddress(theBridgeSettings.getUpnpConfigAddress(), false);
|
addressString = checkIpAddress(theBridgeSettings.getUpnpConfigAddress(), false);
|
||||||
if(addressString == null)
|
if(addressString == null) {
|
||||||
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host.");
|
addressString = aDefaultRoute.getLocalIPAddress();
|
||||||
|
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host. Using default address: " + addressString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(theBridgeSettings.getUpnpResponsePort() == null)
|
if(theBridgeSettings.getUpnpResponsePort() == null)
|
||||||
@@ -152,13 +193,17 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
if(theBridgeSettings.getUpnpDeviceDb() == null)
|
if(theBridgeSettings.getUpnpDeviceDb() == null)
|
||||||
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
||||||
|
|
||||||
|
if(theBridgeSettings.getUpnpGroupDb() == null)
|
||||||
|
theBridgeSettings.setUpnpGroupDb(Configuration.GROUP_DB_DIRECTORY);
|
||||||
|
|
||||||
if(theBridgeSettings.getNumberoflogmessages() == null || theBridgeSettings.getNumberoflogmessages() <= 0)
|
if(theBridgeSettings.getNumberoflogmessages() == null || theBridgeSettings.getNumberoflogmessages() <= 0)
|
||||||
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
theBridgeSettings.setNumberoflogmessages(Integer.valueOf(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||||
|
|
||||||
if(theBridgeSettings.getButtonsleep() == null || theBridgeSettings.getButtonsleep() < 0)
|
if(theBridgeSettings.getButtonsleep() == null || theBridgeSettings.getButtonsleep() < 0)
|
||||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||||
|
|
||||||
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
||||||
|
theBridgeSettings.setFibaroconfigured(theBridgeSettings.isValidFibaro());
|
||||||
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
||||||
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||||
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
||||||
@@ -167,14 +212,27 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
|
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
|
||||||
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
|
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
|
||||||
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
|
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
|
||||||
|
theBridgeSettings.setHomeWizardConfigured(theBridgeSettings.isValidHomeWizard());
|
||||||
|
theBridgeSettings.setOpenhabconfigured(theBridgeSettings.isValidOpenhab());
|
||||||
|
theBridgeSettings.setFhemconfigured(theBridgeSettings.isValidFhem());
|
||||||
|
theBridgeSettings.setMoziotconfigured(theBridgeSettings.isValidMozIot());
|
||||||
|
theBridgeSettings.setHomegenieconfigured(theBridgeSettings.isValidHomeGenie());
|
||||||
// Lifx is either configured or not, so it does not need an update.
|
// 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);
|
||||||
|
theBridgeSettings.setUpnpConfigAddress(serverIpOverride);
|
||||||
|
}
|
||||||
|
|
||||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||||
|
|
||||||
setupInternalTestUser();
|
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());
|
||||||
|
if(theBridgeSettings.getWhitelist() != null) {
|
||||||
|
bridgeSecurity.convertWhitelist(theBridgeSettings.getWhitelist());
|
||||||
|
theBridgeSettings.removeWhitelist();
|
||||||
|
updateConfigFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadConfig() {
|
public void loadConfig() {
|
||||||
@@ -203,6 +261,18 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
log.debug("Save HA Bridge settings.");
|
log.debug("Save HA Bridge settings.");
|
||||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
|
if(bridgeSecurity.isSettingsChanged()) {
|
||||||
|
try {
|
||||||
|
newBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.warn("could not get encoded security data: " + e.getMessage());
|
||||||
|
return;
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
log.warn("could not get encoded security data: " + e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bridgeSecurity.setSettingsChanged(false);
|
||||||
|
}
|
||||||
String jsonValue = aRenderer.render(newBridgeSettings);
|
String jsonValue = aRenderer.render(newBridgeSettings);
|
||||||
configWriter(jsonValue, configPath);
|
configWriter(jsonValue, configPath);
|
||||||
_loadConfig(configPath);
|
_loadConfig(configPath);
|
||||||
@@ -213,13 +283,25 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
log.debug("Save HA Bridge settings.");
|
log.debug("Save HA Bridge settings.");
|
||||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
|
if(bridgeSecurity.isSettingsChanged()) {
|
||||||
|
try {
|
||||||
|
theBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.warn("could not get encoded security data: " + e.getMessage());
|
||||||
|
return;
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
log.warn("could not get encoded security data: " + e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bridgeSecurity.setSettingsChanged(false);
|
||||||
|
}
|
||||||
String jsonValue = aRenderer.render(theBridgeSettings);
|
String jsonValue = aRenderer.render(theBridgeSettings);
|
||||||
configWriter(jsonValue, configPath);
|
configWriter(jsonValue, configPath);
|
||||||
_loadConfig(configPath);
|
_loadConfig(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void configWriter(String content, Path filePath) {
|
private synchronized 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);
|
||||||
return;
|
return;
|
||||||
@@ -236,7 +318,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
try {
|
try {
|
||||||
Path target = null;
|
Path target = null;
|
||||||
if(Files.exists(filePath)) {
|
if(Files.exists(filePath)) {
|
||||||
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old");
|
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old." + getCurrentDate());
|
||||||
Files.move(filePath, target);
|
Files.move(filePath, target);
|
||||||
}
|
}
|
||||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
@@ -249,7 +331,9 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
perms.add(PosixFilePermission.OWNER_WRITE);
|
perms.add(PosixFilePermission.OWNER_WRITE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.setPosixFilePermissions(filePath, perms);
|
String osName = System.getProperty("os.name");
|
||||||
|
if(osName.toLowerCase().indexOf("win") < 0)
|
||||||
|
Files.setPosixFilePermissions(filePath, perms);
|
||||||
} catch(UnsupportedOperationException e) {
|
} catch(UnsupportedOperationException e) {
|
||||||
log.info("Cannot set permissions for config file on this system as it is not supported. Continuing");
|
log.info("Cannot set permissions for config file on this system as it is not supported. Continuing");
|
||||||
}
|
}
|
||||||
@@ -284,6 +368,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
log.error("checkIpAddress cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
log.error("checkIpAddress cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String addressString = null;
|
String addressString = null;
|
||||||
InetAddress address = null;
|
InetAddress address = null;
|
||||||
while (ifs.hasMoreElements() && addressString == null) {
|
while (ifs.hasMoreElements() && addressString == null) {
|
||||||
@@ -310,9 +395,4 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
}
|
}
|
||||||
return addressString;
|
return addressString;
|
||||||
}
|
}
|
||||||
private void setupInternalTestUser() {
|
|
||||||
theBridgeSettings.setupInternalTestUser();
|
|
||||||
if(theBridgeSettings.isSettingsChanged())
|
|
||||||
this.updateConfigFile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,450 +1,850 @@
|
|||||||
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 com.google.gson.annotations.Expose;
|
||||||
import java.util.StringTokenizer;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import java.util.UUID;
|
//import com.bwssystems.HABridge.api.NameValue;
|
||||||
|
|
||||||
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";
|
@SerializedName("upnpconfigaddress")
|
||||||
private static final String DEFAULT_USER_DESCRIPTION = "default_test_user";
|
@Expose
|
||||||
private String upnpconfigaddress;
|
private String upnpconfigaddress;
|
||||||
|
@SerializedName("useupnpiface")
|
||||||
|
@Expose
|
||||||
|
private boolean useupnpiface;
|
||||||
|
@SerializedName("userooms")
|
||||||
|
@Expose
|
||||||
|
private boolean userooms;
|
||||||
|
@SerializedName("serverport")
|
||||||
|
@Expose
|
||||||
private Integer serverport;
|
private Integer serverport;
|
||||||
|
@SerializedName("upnpresponseport")
|
||||||
|
@Expose
|
||||||
private Integer upnpresponseport;
|
private Integer upnpresponseport;
|
||||||
|
@SerializedName("upnpdevicedb")
|
||||||
|
@Expose
|
||||||
private String upnpdevicedb;
|
private String upnpdevicedb;
|
||||||
|
@SerializedName("upnpgroupdb")
|
||||||
|
@Expose
|
||||||
|
private String upnpgroupdb;
|
||||||
|
@SerializedName("veraaddress")
|
||||||
|
@Expose
|
||||||
private IpList veraaddress;
|
private IpList veraaddress;
|
||||||
|
@SerializedName("fibaroaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList fibaroaddress;
|
||||||
|
@SerializedName("harmonyaddress")
|
||||||
|
@Expose
|
||||||
private IpList harmonyaddress;
|
private IpList harmonyaddress;
|
||||||
|
@SerializedName("buttonsleep")
|
||||||
|
@Expose
|
||||||
private Integer buttonsleep;
|
private Integer buttonsleep;
|
||||||
private boolean upnpstrict;
|
@SerializedName("traceupnp")
|
||||||
|
@Expose
|
||||||
private boolean traceupnp;
|
private boolean traceupnp;
|
||||||
|
@SerializedName("nestuser")
|
||||||
|
@Expose
|
||||||
private String nestuser;
|
private String nestuser;
|
||||||
|
@SerializedName("nestpwd")
|
||||||
|
@Expose
|
||||||
private String nestpwd;
|
private String nestpwd;
|
||||||
private boolean veraconfigured;
|
@SerializedName("farenheit")
|
||||||
private boolean harmonyconfigured;
|
@Expose
|
||||||
private boolean nestconfigured;
|
|
||||||
private boolean farenheit;
|
private boolean farenheit;
|
||||||
|
@SerializedName("configfile")
|
||||||
|
@Expose
|
||||||
private String configfile;
|
private String configfile;
|
||||||
|
@SerializedName("numberoflogmessages")
|
||||||
|
@Expose
|
||||||
private Integer numberoflogmessages;
|
private Integer numberoflogmessages;
|
||||||
|
@SerializedName("hueaddress")
|
||||||
|
@Expose
|
||||||
private IpList hueaddress;
|
private IpList hueaddress;
|
||||||
private boolean hueconfigured;
|
@SerializedName("haladdress")
|
||||||
|
@Expose
|
||||||
private IpList haladdress;
|
private IpList haladdress;
|
||||||
private String haltoken;
|
@SerializedName("whitelist")
|
||||||
private boolean halconfigured;
|
@Expose
|
||||||
private Map<String, WhitelistEntry> whitelist;
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
private boolean settingsChanged;
|
@SerializedName("myechourl")
|
||||||
|
@Expose
|
||||||
private String myechourl;
|
private String myechourl;
|
||||||
|
@SerializedName("webaddress")
|
||||||
|
@Expose
|
||||||
private String webaddress;
|
private String webaddress;
|
||||||
|
@SerializedName("mqttaddress")
|
||||||
|
@Expose
|
||||||
private IpList mqttaddress;
|
private IpList mqttaddress;
|
||||||
private boolean mqttconfigured;
|
@SerializedName("hassaddress")
|
||||||
|
@Expose
|
||||||
private IpList hassaddress;
|
private IpList hassaddress;
|
||||||
private boolean hassconfigured;
|
@SerializedName("domoticzaddress")
|
||||||
private String hubversion;
|
@Expose
|
||||||
private IpList domoticzaddress;
|
private IpList domoticzaddress;
|
||||||
private boolean domoticzconfigured;
|
@SerializedName("somfyaddress")
|
||||||
|
@Expose
|
||||||
private IpList somfyaddress;
|
private IpList somfyaddress;
|
||||||
private boolean somfyconfigured;
|
@SerializedName("openhabaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList openhabaddress;
|
||||||
|
@SerializedName("moziotaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList moziotaddress;
|
||||||
|
@SerializedName("hubversion")
|
||||||
|
@Expose
|
||||||
|
private String hubversion;
|
||||||
|
@SerializedName("hubmac")
|
||||||
|
@Expose
|
||||||
|
private String hubmac;
|
||||||
|
@SerializedName("securityData")
|
||||||
|
@Expose
|
||||||
|
private String securityData;
|
||||||
|
@SerializedName("homewizardaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList homewizardaddress;
|
||||||
|
@SerializedName("upnpsenddelay")
|
||||||
|
@Expose
|
||||||
|
private Integer upnpsenddelay;
|
||||||
|
@SerializedName("fhemaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList fhemaddress;
|
||||||
|
@SerializedName("homegenieaddress")
|
||||||
|
@Expose
|
||||||
|
private IpList homegenieaddress;
|
||||||
|
@SerializedName("lifxconfigured")
|
||||||
|
@Expose
|
||||||
private boolean lifxconfigured;
|
private boolean lifxconfigured;
|
||||||
|
@SerializedName("broadlinkconfigured")
|
||||||
|
@Expose
|
||||||
|
private boolean broadlinkconfigured;
|
||||||
|
@SerializedName("tracestate")
|
||||||
|
@Expose
|
||||||
|
private boolean tracestate;
|
||||||
|
@SerializedName("upnporiginal")
|
||||||
|
@Expose
|
||||||
|
private boolean upnporiginal;
|
||||||
|
@SerializedName("seedid")
|
||||||
|
@Expose
|
||||||
|
private Integer seedid;
|
||||||
|
@SerializedName("haaddressessecured")
|
||||||
|
@Expose
|
||||||
|
private boolean haaddressessecured;
|
||||||
|
// @SerializedName("activeloggers")
|
||||||
|
// @Expose
|
||||||
|
// private List<NameValue> activeloggers;
|
||||||
|
|
||||||
|
private boolean settingsChanged;
|
||||||
|
private boolean veraconfigured;
|
||||||
|
private boolean fibaroconfigured;
|
||||||
|
private boolean harmonyconfigured;
|
||||||
|
private boolean hueconfigured;
|
||||||
|
private boolean nestconfigured;
|
||||||
|
private boolean halconfigured;
|
||||||
|
private boolean mqttconfigured;
|
||||||
|
private boolean hassconfigured;
|
||||||
|
private boolean domoticzconfigured;
|
||||||
|
private boolean somfyconfigured;
|
||||||
|
private boolean homewizardconfigured;
|
||||||
|
private boolean openhabconfigured;
|
||||||
|
private boolean fhemconfigured;
|
||||||
|
private boolean moziotconfigured;
|
||||||
|
private boolean homegenieconfigured;
|
||||||
|
|
||||||
|
// Deprecated settings
|
||||||
|
private String haltoken;
|
||||||
|
// private boolean upnpstrict;
|
||||||
|
|
||||||
public BridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor() {
|
||||||
super();
|
super();
|
||||||
this.upnpstrict = true;
|
// this.upnpstrict = true;
|
||||||
|
this.useupnpiface = false;
|
||||||
|
this.userooms = false;
|
||||||
this.traceupnp = false;
|
this.traceupnp = false;
|
||||||
this.nestconfigured = false;
|
this.nestconfigured = false;
|
||||||
this.veraconfigured = false;
|
this.veraconfigured = false;
|
||||||
|
this.fibaroconfigured = false;
|
||||||
this.somfyconfigured = false;
|
this.somfyconfigured = false;
|
||||||
this.harmonyconfigured = false;
|
this.harmonyconfigured = false;
|
||||||
this.hueconfigured = false;
|
this.hueconfigured = false;
|
||||||
this.halconfigured = false;
|
this.halconfigured = false;
|
||||||
this.mqttconfigured = false;
|
this.mqttconfigured = false;
|
||||||
this.hassconfigured = false;
|
this.hassconfigured = false;
|
||||||
|
this.domoticzconfigured = false;
|
||||||
|
this.homewizardconfigured = false;
|
||||||
|
this.lifxconfigured = false;
|
||||||
|
this.openhabconfigured = false;
|
||||||
|
this.moziotconfigured = false;
|
||||||
|
this.homegenieconfigured = false;
|
||||||
this.farenheit = true;
|
this.farenheit = true;
|
||||||
this.whitelist = null;
|
this.securityData = null;
|
||||||
this.settingsChanged = false;
|
this.settingsChanged = false;
|
||||||
this.myechourl = "echo.amazon.com/#cards";
|
this.myechourl = "alexa.amazon.com/spa/index.html#cards";
|
||||||
this.webaddress = "0.0.0.0";
|
this.webaddress = "0.0.0.0";
|
||||||
this.hubversion = HueConstants.HUB_VERSION;
|
this.hubversion = HueConstants.HUB_VERSION;
|
||||||
|
this.hubmac = null;
|
||||||
|
// this.activeloggers = null;
|
||||||
|
this.upnpsenddelay = Configuration.UPNP_SEND_DELAY;
|
||||||
|
this.broadlinkconfigured = false;
|
||||||
|
this.tracestate = false;
|
||||||
|
this.upnporiginal = false;
|
||||||
|
this.seedid = 100;
|
||||||
|
this.haaddressessecured = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
return upnpconfigaddress;
|
return upnpconfigaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
||||||
this.upnpconfigaddress = upnpConfigAddress;
|
this.upnpconfigaddress = upnpConfigAddress;
|
||||||
}
|
}
|
||||||
public Integer getServerPort() {
|
|
||||||
|
public boolean isUseupnpiface() {
|
||||||
|
return useupnpiface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseupnpiface(boolean useupnpiface) {
|
||||||
|
this.useupnpiface = useupnpiface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUserooms() {
|
||||||
|
return userooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserooms(boolean userooms) {
|
||||||
|
this.userooms = userooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getServerPort() {
|
||||||
return serverport;
|
return serverport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerPort(Integer serverPort) {
|
public void setServerPort(Integer serverPort) {
|
||||||
this.serverport = serverPort;
|
this.serverport = serverPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerPort(String serverPort) {
|
public void setServerPort(String serverPort) {
|
||||||
this.serverport = Integer.valueOf(serverPort);
|
this.serverport = Integer.valueOf(serverPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getUpnpResponsePort() {
|
public Integer getUpnpResponsePort() {
|
||||||
return upnpresponseport;
|
return upnpresponseport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpnpResponsePort(Integer upnpResponsePort) {
|
public void setUpnpResponsePort(Integer upnpResponsePort) {
|
||||||
this.upnpresponseport = upnpResponsePort;
|
this.upnpresponseport = upnpResponsePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpnpResponsePort(String upnpResponsePort) {
|
public void setUpnpResponsePort(String upnpResponsePort) {
|
||||||
this.upnpresponseport = Integer.valueOf(upnpResponsePort);
|
this.upnpresponseport = Integer.valueOf(upnpResponsePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUpnpDeviceDb() {
|
public String getUpnpDeviceDb() {
|
||||||
return upnpdevicedb;
|
return upnpdevicedb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
||||||
this.upnpdevicedb = upnpDeviceDb;
|
this.upnpdevicedb = upnpDeviceDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUpnpGroupDb() {
|
||||||
|
return upnpgroupdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpnpGroupDb(String upnpGroupDb) {
|
||||||
|
this.upnpgroupdb = upnpGroupDb;
|
||||||
|
}
|
||||||
|
|
||||||
public IpList getVeraAddress() {
|
public IpList getVeraAddress() {
|
||||||
|
|
||||||
return veraaddress;
|
return veraaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IpList getFibaroAddress() {
|
||||||
|
return fibaroaddress;
|
||||||
|
}
|
||||||
|
|
||||||
public IpList getSomfyAddress() {
|
public IpList getSomfyAddress() {
|
||||||
return somfyaddress;
|
return somfyaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IpList getHomeWizardAddress() {
|
||||||
|
return homewizardaddress;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVeraAddress(IpList veraAddress) {
|
public void setVeraAddress(IpList veraAddress) {
|
||||||
this.veraaddress = veraAddress;
|
this.veraaddress = veraAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFibaroAddress(IpList fibaroAddress) {
|
||||||
|
this.fibaroaddress = fibaroAddress;
|
||||||
|
}
|
||||||
|
|
||||||
public void setSomfyAddress(IpList somfyAddress) {
|
public void setSomfyAddress(IpList somfyAddress) {
|
||||||
this.somfyaddress = somfyAddress;
|
this.somfyaddress = somfyAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHomeWizardAddress(IpList homewizardaddress) {
|
||||||
|
this.homewizardaddress = homewizardaddress;
|
||||||
|
}
|
||||||
|
|
||||||
public IpList getHarmonyAddress() {
|
public IpList getHarmonyAddress() {
|
||||||
return harmonyaddress;
|
return harmonyaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHarmonyAddress(IpList harmonyaddress) {
|
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||||
this.harmonyaddress = harmonyaddress;
|
this.harmonyaddress = harmonyaddress;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
public boolean isUpnpStrict() {
|
public boolean isUpnpStrict() {
|
||||||
return upnpstrict;
|
return upnpstrict;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpnpStrict(boolean upnpStrict) {
|
public void setUpnpStrict(boolean upnpStrict) {
|
||||||
this.upnpstrict = upnpStrict;
|
this.upnpstrict = upnpStrict;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
public boolean isTraceupnp() {
|
public boolean isTraceupnp() {
|
||||||
return traceupnp;
|
return traceupnp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTraceupnp(boolean traceupnp) {
|
public void setTraceupnp(boolean traceupnp) {
|
||||||
this.traceupnp = traceupnp;
|
this.traceupnp = traceupnp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNestuser() {
|
public String getNestuser() {
|
||||||
return nestuser;
|
return nestuser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNestuser(String nestuser) {
|
public void setNestuser(String nestuser) {
|
||||||
this.nestuser = nestuser;
|
this.nestuser = nestuser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNestpwd() {
|
public String getNestpwd() {
|
||||||
return nestpwd;
|
return nestpwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNestpwd(String nestpwd) {
|
public void setNestpwd(String nestpwd) {
|
||||||
this.nestpwd = nestpwd;
|
this.nestpwd = nestpwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVeraconfigured() {
|
public boolean isVeraconfigured() {
|
||||||
return veraconfigured;
|
return veraconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFibaroconfigured() {
|
||||||
|
return fibaroconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSomfyconfigured() {
|
public boolean isSomfyconfigured() {
|
||||||
return somfyconfigured;
|
return somfyconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isHomeWizardConfigured() {
|
||||||
|
return homewizardconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVeraconfigured(boolean veraconfigured) {
|
public void setVeraconfigured(boolean veraconfigured) {
|
||||||
this.veraconfigured = veraconfigured;
|
this.veraconfigured = veraconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFibaroconfigured(boolean fibaroconfigured) {
|
||||||
|
this.fibaroconfigured = fibaroconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
public void setSomfyconfigured(boolean somfyconfigured) {
|
public void setSomfyconfigured(boolean somfyconfigured) {
|
||||||
this.somfyconfigured = somfyconfigured;
|
this.somfyconfigured = somfyconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHomeWizardConfigured(boolean homewizardconfigured) {
|
||||||
|
this.homewizardconfigured = homewizardconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isHarmonyconfigured() {
|
public boolean isHarmonyconfigured() {
|
||||||
return harmonyconfigured;
|
return harmonyconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHarmonyconfigured(boolean harmonyconfigured) {
|
public void setHarmonyconfigured(boolean harmonyconfigured) {
|
||||||
this.harmonyconfigured = harmonyconfigured;
|
this.harmonyconfigured = harmonyconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNestConfigured() {
|
public boolean isNestConfigured() {
|
||||||
return nestconfigured;
|
return nestconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNestConfigured(boolean isNestConfigured) {
|
public void setNestConfigured(boolean isNestConfigured) {
|
||||||
this.nestconfigured = isNestConfigured;
|
this.nestconfigured = isNestConfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getButtonsleep() {
|
public Integer getButtonsleep() {
|
||||||
return buttonsleep;
|
return buttonsleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setButtonsleep(Integer buttonsleep) {
|
public void setButtonsleep(Integer buttonsleep) {
|
||||||
this.buttonsleep = buttonsleep;
|
this.buttonsleep = buttonsleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getConfigfile() {
|
public String getConfigfile() {
|
||||||
return configfile;
|
return configfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfigfile(String configfile) {
|
public void setConfigfile(String configfile) {
|
||||||
this.configfile = configfile;
|
this.configfile = configfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getNumberoflogmessages() {
|
public Integer getNumberoflogmessages() {
|
||||||
return numberoflogmessages;
|
return numberoflogmessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNumberoflogmessages(Integer numberoflogmessages) {
|
public void setNumberoflogmessages(Integer numberoflogmessages) {
|
||||||
this.numberoflogmessages = numberoflogmessages;
|
this.numberoflogmessages = numberoflogmessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFarenheit() {
|
public boolean isFarenheit() {
|
||||||
return farenheit;
|
return farenheit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFarenheit(boolean farenheit) {
|
public void setFarenheit(boolean farenheit) {
|
||||||
this.farenheit = farenheit;
|
this.farenheit = farenheit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpList getHueaddress() {
|
public IpList getHueaddress() {
|
||||||
return hueaddress;
|
return hueaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHueaddress(IpList hueaddress) {
|
public void setHueaddress(IpList hueaddress) {
|
||||||
this.hueaddress = hueaddress;
|
this.hueaddress = hueaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHueconfigured() {
|
public boolean isHueconfigured() {
|
||||||
return hueconfigured;
|
return hueconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHueconfigured(boolean hueconfigured) {
|
public void setHueconfigured(boolean hueconfigured) {
|
||||||
this.hueconfigured = hueconfigured;
|
this.hueconfigured = hueconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpList getHaladdress() {
|
public IpList getHaladdress() {
|
||||||
return haladdress;
|
return haladdress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHaladdress(IpList haladdress) {
|
public void setHaladdress(IpList haladdress) {
|
||||||
this.haladdress = haladdress;
|
this.haladdress = haladdress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHaltoken() {
|
public String getHaltoken() {
|
||||||
return haltoken;
|
return haltoken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHaltoken(String haltoken) {
|
public void setHaltoken(String haltoken) {
|
||||||
this.haltoken = haltoken;
|
this.haltoken = haltoken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHalconfigured() {
|
public boolean isHalconfigured() {
|
||||||
return halconfigured;
|
return halconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHalconfigured(boolean halconfigured) {
|
public void setHalconfigured(boolean halconfigured) {
|
||||||
this.halconfigured = halconfigured;
|
this.halconfigured = halconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, WhitelistEntry> getWhitelist() {
|
public Map<String, WhitelistEntry> getWhitelist() {
|
||||||
return whitelist;
|
return whitelist;
|
||||||
}
|
}
|
||||||
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
|
||||||
this.whitelist = whitelist;
|
protected void removeWhitelist() {
|
||||||
|
whitelist = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSettingsChanged() {
|
public boolean isSettingsChanged() {
|
||||||
return settingsChanged;
|
return settingsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSettingsChanged(boolean settingsChanged) {
|
public void setSettingsChanged(boolean settingsChanged) {
|
||||||
this.settingsChanged = settingsChanged;
|
this.settingsChanged = settingsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMyechourl() {
|
public String getMyechourl() {
|
||||||
return myechourl;
|
return myechourl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMyechourl(String myechourl) {
|
public void setMyechourl(String myechourl) {
|
||||||
this.myechourl = myechourl;
|
this.myechourl = myechourl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebaddress() {
|
public String getWebaddress() {
|
||||||
return webaddress;
|
return webaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWebaddress(String webaddress) {
|
public void setWebaddress(String webaddress) {
|
||||||
this.webaddress = webaddress;
|
this.webaddress = webaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpList getMqttaddress() {
|
public IpList getMqttaddress() {
|
||||||
return mqttaddress;
|
return mqttaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMqttaddress(IpList mqttaddress) {
|
public void setMqttaddress(IpList mqttaddress) {
|
||||||
this.mqttaddress = mqttaddress;
|
this.mqttaddress = mqttaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMqttconfigured() {
|
public boolean isMqttconfigured() {
|
||||||
return mqttconfigured;
|
return mqttconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMqttconfigured(boolean mqttconfigured) {
|
public void setMqttconfigured(boolean mqttconfigured) {
|
||||||
this.mqttconfigured = mqttconfigured;
|
this.mqttconfigured = mqttconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpList getHassaddress() {
|
public IpList getHassaddress() {
|
||||||
return hassaddress;
|
return hassaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHassaddress(IpList hassaddress) {
|
public void setHassaddress(IpList hassaddress) {
|
||||||
this.hassaddress = hassaddress;
|
this.hassaddress = hassaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHassconfigured() {
|
public boolean isHassconfigured() {
|
||||||
return hassconfigured;
|
return hassconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHassconfigured(boolean hassconfigured) {
|
public void setHassconfigured(boolean hassconfigured) {
|
||||||
this.hassconfigured = hassconfigured;
|
this.hassconfigured = hassconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IpList getOpenhabaddress() {
|
||||||
|
return openhabaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpenhabaddress(IpList openhabaddress) {
|
||||||
|
this.openhabaddress = openhabaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpenhabconfigured() {
|
||||||
|
return openhabconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpenhabconfigured(boolean openhabconfigured) {
|
||||||
|
this.openhabconfigured = openhabconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHubversion() {
|
public String getHubversion() {
|
||||||
return hubversion;
|
return hubversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHubversion(String hubversion) {
|
public void setHubversion(String hubversion) {
|
||||||
this.hubversion = hubversion;
|
this.hubversion = hubversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHubmac() {
|
||||||
|
return hubmac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHubmac(String hubmac) {
|
||||||
|
this.hubmac = hubmac;
|
||||||
|
}
|
||||||
|
|
||||||
public IpList getDomoticzaddress() {
|
public IpList getDomoticzaddress() {
|
||||||
return domoticzaddress;
|
return domoticzaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDomoticzaddress(IpList domoticzaddress) {
|
public void setDomoticzaddress(IpList domoticzaddress) {
|
||||||
this.domoticzaddress = domoticzaddress;
|
this.domoticzaddress = domoticzaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDomoticzconfigured() {
|
public boolean isDomoticzconfigured() {
|
||||||
return domoticzconfigured;
|
return domoticzconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDomoticzconfigured(boolean domoticzconfigured) {
|
public void setDomoticzconfigured(boolean domoticzconfigured) {
|
||||||
this.domoticzconfigured = domoticzconfigured;
|
this.domoticzconfigured = domoticzconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLifxconfigured() {
|
public boolean isLifxconfigured() {
|
||||||
return lifxconfigured;
|
return lifxconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLifxconfigured(boolean lifxconfigured) {
|
public void setLifxconfigured(boolean lifxconfigured) {
|
||||||
this.lifxconfigured = lifxconfigured;
|
this.lifxconfigured = lifxconfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSecurityData() {
|
||||||
|
return securityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurityData(String securityData) {
|
||||||
|
this.securityData = securityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUpnpsenddelay() {
|
||||||
|
return upnpsenddelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpnpsenddelay(Integer upnpsenddelay) {
|
||||||
|
this.upnpsenddelay = upnpsenddelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IpList getFhemaddress() {
|
||||||
|
return fhemaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFhemaddress(IpList fhemaddress) {
|
||||||
|
this.fhemaddress = fhemaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFhemconfigured() {
|
||||||
|
return fhemconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFhemconfigured(boolean fhemconfigured) {
|
||||||
|
this.fhemconfigured = fhemconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public List<NameValue> getActiveloggers() {
|
||||||
|
// return activeloggers;
|
||||||
|
// }
|
||||||
|
// public void setActiveloggers(List<NameValue> activeloggers) {
|
||||||
|
// this.activeloggers = activeloggers;
|
||||||
|
// }
|
||||||
|
public boolean isBroadlinkconfigured() {
|
||||||
|
return broadlinkconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBroadlinkconfigured(boolean broadlinkconfigured) {
|
||||||
|
this.broadlinkconfigured = broadlinkconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
List<NamedIP> devicesList = this.getVeraAddress().getDevices();
|
List<NamedIP> devicesList = this.getVeraAddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isValidFibaro() {
|
||||||
|
if (this.getFibaroAddress() == null || this.getFibaroAddress().getDevices().size() <= 0)
|
||||||
|
return false;
|
||||||
|
List<NamedIP> devicesList = this.getFibaroAddress().getDevices();
|
||||||
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean isValidHarmony() {
|
public Boolean isValidHarmony() {
|
||||||
if(this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
|
if (this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getHarmonyAddress().getDevices();
|
List<NamedIP> devicesList = this.getHarmonyAddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidNest() {
|
public Boolean isValidNest() {
|
||||||
if(this.getNestpwd() == null || this.getNestpwd().equals(""))
|
if (this.getNestpwd() == null || this.getNestpwd().equals(""))
|
||||||
return false;
|
return false;
|
||||||
if(this.getNestuser() == null || this.getNestuser().equals(""))
|
if (this.getNestuser() == null || this.getNestuser().equals(""))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidHue() {
|
public Boolean isValidHue() {
|
||||||
if(this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
|
if (this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getHueaddress().getDevices();
|
List<NamedIP> devicesList = this.getHueaddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidHal() {
|
public Boolean isValidHal() {
|
||||||
if(this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
|
if (this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getHaladdress().getDevices();
|
List<NamedIP> devicesList = this.getHaladdress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
|
||||||
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
|
|
||||||
return false;
|
return false;
|
||||||
|
if (devicesList.get(0).getPassword() == null || devicesList.get(0).getPassword().trim().isEmpty()) {
|
||||||
|
if (this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidMQTT() {
|
public Boolean isValidMQTT() {
|
||||||
if(this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
|
if (this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getMqttaddress().getDevices();
|
List<NamedIP> devicesList = this.getMqttaddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidHass() {
|
public Boolean isValidHass() {
|
||||||
if(this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
|
if (this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getHassaddress().getDevices();
|
List<NamedIP> devicesList = this.getHassaddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidDomoticz() {
|
public Boolean isValidDomoticz() {
|
||||||
if(this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
|
if (this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getDomoticzaddress().getDevices();
|
List<NamedIP> devicesList = this.getDomoticzaddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidSomfy() {
|
public Boolean isValidSomfy() {
|
||||||
if(this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
|
if (this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
List<NamedIP> devicesList = this.getSomfyAddress().getDevices();
|
List<NamedIP> devicesList = this.getSomfyAddress().getDevices();
|
||||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isValidLifx() {
|
public Boolean isValidLifx() {
|
||||||
return this.isLifxconfigured();
|
return this.isLifxconfigured();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
public void updateHue(NamedIP aHue) {
|
||||||
String validUser = null;
|
int indexHue = -1;
|
||||||
boolean found = false;
|
for (int i = 0; i < hueaddress.getDevices().size(); i++) {
|
||||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
if (hueaddress.getDevices().get(i).getName().equals(aHue.getName()))
|
||||||
&& !aUser.equalsIgnoreCase("")) {
|
indexHue = i;
|
||||||
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 (indexHue >= 0) {
|
||||||
if(!found && !strict) {
|
hueaddress.getDevices().set(indexHue, aHue);
|
||||||
newWhitelistUser(aUser, userDescription);
|
this.setSettingsChanged(true);
|
||||||
|
|
||||||
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) {
|
public Boolean isValidHomeWizard() {
|
||||||
if (whitelist == null) {
|
if (this.getHomeWizardAddress() == null || this.getHomeWizardAddress().getDevices().size() <= 0)
|
||||||
whitelist = new HashMap<>();
|
return false;
|
||||||
}
|
|
||||||
if(userDescription == null)
|
|
||||||
userDescription = "auto insert user";
|
|
||||||
|
|
||||||
whitelist.put(aUser, WhitelistEntry.createEntry(userDescription));
|
List<NamedIP> devicesList = this.getHomeWizardAddress().getDevices();
|
||||||
setSettingsChanged(true);
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String createWhitelistUser(String userDescription) {
|
public Boolean isValidOpenhab() {
|
||||||
String aUser = getNewUserID();
|
if (this.getOpenhabaddress() == null || this.getOpenhabaddress().getDevices().size() <= 0)
|
||||||
newWhitelistUser(aUser, userDescription);
|
return false;
|
||||||
return aUser;
|
|
||||||
|
List<NamedIP> devicesList = this.getOpenhabaddress().getDevices();
|
||||||
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNewUserID() {
|
public Boolean isValidFhem() {
|
||||||
UUID uid = UUID.randomUUID();
|
if (this.getFhemaddress() == null || this.getFhemaddress().getDevices().size() <= 0)
|
||||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
return false;
|
||||||
String newUser = "";
|
|
||||||
while (st.hasMoreTokens()) {
|
|
||||||
newUser = newUser + st.nextToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
return newUser;
|
List<NamedIP> devicesList = this.getFhemaddress().getDevices();
|
||||||
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInternalTestUser() {
|
public Boolean isValidBroadlink() {
|
||||||
return DEFAULT_INTERNAL_USER;
|
return this.isBroadlinkconfigured();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupInternalTestUser() {
|
public boolean isTracestate() {
|
||||||
boolean found = false;
|
return tracestate;
|
||||||
if(whitelist != null) {
|
}
|
||||||
for (String key : whitelist.keySet()) {
|
|
||||||
if(key.equals(DEFAULT_INTERNAL_USER)) {
|
public void setTracestate(boolean tracestate) {
|
||||||
found = true;
|
this.tracestate = tracestate;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
public IpList getMoziotaddress() {
|
||||||
}
|
return moziotaddress;
|
||||||
if(!found) {
|
}
|
||||||
newWhitelistUser(DEFAULT_INTERNAL_USER, DEFAULT_USER_DESCRIPTION);
|
|
||||||
}
|
public void setMoziotgaddress(IpList moziotgateway) {
|
||||||
|
this.moziotaddress = moziotgateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isValidMozIot() {
|
||||||
|
if (this.getMoziotaddress() == null || this.getMoziotaddress().getDevices().size() <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List<NamedIP> devicesList = this.getMoziotaddress().getDevices();
|
||||||
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMoziotconfigured() {
|
||||||
|
return moziotconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMoziotconfigured(boolean moziotconfigured) {
|
||||||
|
this.moziotconfigured = moziotconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpnporiginal() {
|
||||||
|
return upnporiginal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpnporiginal(boolean upnporiginal) {
|
||||||
|
this.upnporiginal = upnporiginal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSeedid() {
|
||||||
|
return seedid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeedid(Integer seedid) {
|
||||||
|
this.seedid = seedid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IpList getHomegenieaddress() {
|
||||||
|
return homegenieaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHomegenieaddress(IpList homegenieaddress) {
|
||||||
|
this.homegenieaddress = homegenieaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHomegenieconfigured() {
|
||||||
|
return homegenieconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHomegenieconfigured(boolean homegenieconfigured) {
|
||||||
|
this.homegenieconfigured = homegenieconfigured;
|
||||||
|
}
|
||||||
|
public Boolean isValidHomeGenie() {
|
||||||
|
if (this.getHomegenieaddress() == null || this.getHomegenieaddress().getDevices().size() <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List<NamedIP> devicesList = this.getHomegenieaddress().getDevices();
|
||||||
|
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHaaddressessecured() {
|
||||||
|
return haaddressessecured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHaaddressessecured(boolean haaddressessecured) {
|
||||||
|
this.haaddressessecured = haaddressessecured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge;
|
|||||||
|
|
||||||
public class Configuration {
|
public class Configuration {
|
||||||
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||||
|
public final static String GROUP_DB_DIRECTORY = "data/group.db";
|
||||||
public final static String UPNP_RESPONSE_PORT = "50000";
|
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||||
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
||||||
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
||||||
@@ -13,4 +14,7 @@ public class Configuration {
|
|||||||
public static final String CONFIG_FILE = "data/habridge.config";
|
public static final String CONFIG_FILE = "data/habridge.config";
|
||||||
public static final int NUMBER_OF_LOG_MESSAGES = 512;
|
public static final int NUMBER_OF_LOG_MESSAGES = 512;
|
||||||
public static final long UPNP_NOTIFY_TIMEOUT = 20000;
|
public static final long UPNP_NOTIFY_TIMEOUT = 20000;
|
||||||
|
public static final int UPNP_SEND_DELAY = 650;
|
||||||
|
public static final int BROADLINK_DISCOVER_PORT = 40000;
|
||||||
|
public static final int BROADLINK_DISCONVER_TIMEOUT = 5000;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public class DeviceMapTypes {
|
|||||||
public final static String[] CUSTOM_DEVICE = { "custom", "Custom"};
|
public final static String[] CUSTOM_DEVICE = { "custom", "Custom"};
|
||||||
public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"};
|
public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"};
|
||||||
public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"};
|
public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"};
|
||||||
|
public final static String[] FIBARO_DEVICE = { "fibaroDevice", "Fibaro Device"};
|
||||||
|
public final static String[] FIBARO_SCENE = { "fibaroScene", "Fibaro Scene"};
|
||||||
public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"};
|
public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"};
|
||||||
public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"};
|
public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"};
|
||||||
public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"};
|
public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"};
|
||||||
@@ -20,6 +22,7 @@ public class DeviceMapTypes {
|
|||||||
public final static String[] EXEC_DEVICE_COMPAT = { "exec", "Execute Script/Program"};
|
public final static String[] EXEC_DEVICE_COMPAT = { "exec", "Execute Script/Program"};
|
||||||
public final static String[] CMD_DEVICE = { "cmdDevice", "Execute Command/Script/Program"};
|
public final static String[] CMD_DEVICE = { "cmdDevice", "Execute Command/Script/Program"};
|
||||||
public final static String[] HASS_DEVICE = { "hassDevice", "HomeAssistant Device"};
|
public final static String[] HASS_DEVICE = { "hassDevice", "HomeAssistant Device"};
|
||||||
|
public final static String[] HOMEWIZARD_DEVICE = { "homewizardDevice", "HomeWizard Device"};
|
||||||
public final static String[] TCP_DEVICE = { "tcpDevice", "TCP Device"};
|
public final static String[] TCP_DEVICE = { "tcpDevice", "TCP Device"};
|
||||||
public final static String[] TCP_DEVICE_COMPAT = { "TCP", "TCP Device"};
|
public final static String[] TCP_DEVICE_COMPAT = { "TCP", "TCP Device"};
|
||||||
public final static String[] UDP_DEVICE = { "udpDevice", "UDP Device"};
|
public final static String[] UDP_DEVICE = { "udpDevice", "UDP Device"};
|
||||||
@@ -28,6 +31,11 @@ public class DeviceMapTypes {
|
|||||||
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[] SOMFY_DEVICE = { "somfyDevice", "Somfy Device"};
|
||||||
public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
|
public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
|
||||||
|
public final static String[] OPENHAB_DEVICE = { "openhabDevice", "OpenHAB Device"};
|
||||||
|
public final static String[] FHEM_DEVICE = { "fhemDevice", "FHEM Device"};
|
||||||
|
public final static String[] BROADLINK_DEVICE = { "broadlinkDevice", "Broadlink Device"};
|
||||||
|
public final static String[] MOZIOT_DEVICE = { "moziotDevice", "Mozilla IOT Device"};
|
||||||
|
public final static String[] HOMEGENIE_DEVICE = { "homegenieDevice", "HomeGenie 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,18 +54,25 @@ public class DeviceMapTypes {
|
|||||||
deviceMapTypes.add(HARMONY_ACTIVITY);
|
deviceMapTypes.add(HARMONY_ACTIVITY);
|
||||||
deviceMapTypes.add(HARMONY_BUTTON);
|
deviceMapTypes.add(HARMONY_BUTTON);
|
||||||
deviceMapTypes.add(HASS_DEVICE);
|
deviceMapTypes.add(HASS_DEVICE);
|
||||||
|
deviceMapTypes.add(HOMEWIZARD_DEVICE);
|
||||||
deviceMapTypes.add(HTTP_DEVICE);
|
deviceMapTypes.add(HTTP_DEVICE);
|
||||||
deviceMapTypes.add(HUE_DEVICE);
|
deviceMapTypes.add(HUE_DEVICE);
|
||||||
deviceMapTypes.add(LIFX_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(FIBARO_DEVICE);
|
||||||
|
deviceMapTypes.add(FIBARO_SCENE);
|
||||||
deviceMapTypes.add(SOMFY_DEVICE);
|
deviceMapTypes.add(SOMFY_DEVICE);
|
||||||
|
deviceMapTypes.add(OPENHAB_DEVICE);
|
||||||
|
deviceMapTypes.add(FHEM_DEVICE);
|
||||||
|
deviceMapTypes.add(BROADLINK_DEVICE);
|
||||||
|
deviceMapTypes.add(MOZIOT_DEVICE);
|
||||||
|
deviceMapTypes.add(HOMEGENIE_DEVICE);
|
||||||
}
|
}
|
||||||
public static int getTypeIndex() {
|
public static int getTypeIndex() {
|
||||||
return typeIndex;
|
return typeIndex;
|
||||||
|
|||||||
@@ -2,16 +2,20 @@ package com.bwssystems.HABridge;
|
|||||||
|
|
||||||
import static spark.Spark.*;
|
import static spark.Spark.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.devicemanagmeent.*;
|
import com.bwssystems.HABridge.devicemanagmeent.*;
|
||||||
import com.bwssystems.HABridge.hue.HueMulator;
|
import com.bwssystems.HABridge.hue.HueMulator;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HttpClientPool;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
private static SystemControl theSystem;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This program is based on the work of armzilla from this github repository:
|
* This program is based on the work of armzilla from this github repository:
|
||||||
@@ -36,27 +40,47 @@ public class HABridge {
|
|||||||
UDPDatagramSender udpSender;
|
UDPDatagramSender udpSender;
|
||||||
UpnpSettingsResource theSettingResponder;
|
UpnpSettingsResource theSettingResponder;
|
||||||
UpnpListener theUpnpListener;
|
UpnpListener theUpnpListener;
|
||||||
SystemControl theSystem;
|
|
||||||
BridgeSettings bridgeSettings;
|
BridgeSettings bridgeSettings;
|
||||||
Version theVersion;
|
Version theVersion;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
HttpClientPool thePool;
|
||||||
|
ShutdownHook shutdownHook = null;
|
||||||
|
|
||||||
|
log.info("HA Bridge startup sequence...");
|
||||||
theVersion = new Version();
|
theVersion = new Version();
|
||||||
|
// Singleton initialization
|
||||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
|
thePool = new HttpClientPool();
|
||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings = new BridgeSettings();
|
||||||
|
// sparkjava config directive to set html static file location for Jetty
|
||||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||||
bridgeSettings.buildSettings();
|
log.info("HA Bridge (v{}) initializing....", theVersion.getVersion() );
|
||||||
log.info("HA Bridge initializing....");
|
bridgeSettings.buildSettings();
|
||||||
|
if(bridgeSettings.getBridgeSecurity().isUseHttps()) {
|
||||||
|
secure(bridgeSettings.getBridgeSecurity().getKeyfilePath(), bridgeSettings.getBridgeSecurity().getKeyfilePassword(), null, null);
|
||||||
|
log.info("Using https for web and api calls");
|
||||||
|
}
|
||||||
|
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||||
// sparkjava config directive to set ip address for the web server to listen on
|
// sparkjava config directive to set ip address for the web server to listen on
|
||||||
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
||||||
// sparkjava config directive to set port for the web server to listen on
|
// sparkjava config directive to set port for the web server to listen on
|
||||||
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||||
// sparkjava config directive to set html static file location for Jetty
|
staticFileLocation("/public");
|
||||||
staticFileLocation("/public");
|
initExceptionHandler((e) -> HABridge.theExceptionHandler(e, bridgeSettings.getBridgeSettingsDescriptor().getServerPort()));
|
||||||
|
if(!bridgeSettings.getBridgeControl().isReinit())
|
||||||
|
init();
|
||||||
|
bridgeSettings.getBridgeControl().setReinit(false);
|
||||||
// setup system control api first
|
// setup system control api first
|
||||||
theSystem = new SystemControl(bridgeSettings, theVersion);
|
theSystem = new SystemControl(bridgeSettings, theVersion);
|
||||||
theSystem.setupServer();
|
theSystem.setupServer();
|
||||||
|
|
||||||
|
// Add shutdown hook to be able to properly stop server
|
||||||
|
if (shutdownHook != null) {
|
||||||
|
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||||
|
}
|
||||||
|
shutdownHook = new ShutdownHook(bridgeSettings, theSystem);
|
||||||
|
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||||
|
|
||||||
// setup the UDP Datagram socket to be used by the HueMulator and the upnpListener
|
// setup the UDP Datagram socket to be used by the HueMulator and the upnpListener
|
||||||
udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort());
|
udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort());
|
||||||
if(udpSender == null) {
|
if(udpSender == null) {
|
||||||
@@ -65,34 +89,78 @@ public class HABridge {
|
|||||||
else {
|
else {
|
||||||
//Setup the device connection homes through the manager
|
//Setup the device connection homes through the manager
|
||||||
homeManager = new HomeManager();
|
homeManager = new HomeManager();
|
||||||
homeManager.buildHomes(bridgeSettings.getBridgeSettingsDescriptor(), udpSender);
|
homeManager.buildHomes(bridgeSettings, udpSender);
|
||||||
// setup the class to handle the resource setup rest api
|
// setup the class to handle the resource setup rest api
|
||||||
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), homeManager);
|
theResources = new DeviceResource(bridgeSettings, homeManager);
|
||||||
// setup the class to handle the upnp response rest api
|
|
||||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
|
||||||
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, theResources.getDeviceRepository(), homeManager);
|
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), theResources.getGroupRepository(), 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();
|
||||||
|
|
||||||
|
if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp()) {
|
||||||
|
log.info("Traceupnp: upnp config address: {} -useIface: {} on web server: {}:{}",
|
||||||
|
bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress(),
|
||||||
|
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface(),
|
||||||
|
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress(),
|
||||||
|
bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||||
|
}
|
||||||
|
// setup the class to handle the upnp response rest api
|
||||||
|
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||||
|
theSettingResponder.setupServer();
|
||||||
|
|
||||||
// start the upnp ssdp discovery listener
|
// start the upnp ssdp discovery listener
|
||||||
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender);
|
theUpnpListener = null;
|
||||||
if(theUpnpListener.startListening())
|
try {
|
||||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
theUpnpListener = new UpnpListener(bridgeSettings, bridgeSettings.getBridgeControl(), udpSender);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not initialize UpnpListener, exiting....", e);
|
||||||
|
theUpnpListener = null;
|
||||||
|
}
|
||||||
|
if(theUpnpListener != null && theUpnpListener.startListening())
|
||||||
|
log.info("HA Bridge (v{}) reinitialization requessted....", theVersion.getVersion());
|
||||||
else
|
else
|
||||||
bridgeSettings.getBridgeControl().setStop(true);
|
bridgeSettings.getBridgeControl().setStop(true);
|
||||||
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
||||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
log.info("Going to close all homes");
|
||||||
homeManager.closeHomes();
|
homeManager.closeHomes();
|
||||||
udpSender.closeResponseSocket();
|
udpSender.closeResponseSocket();
|
||||||
udpSender = null;
|
udpSender = null;
|
||||||
}
|
}
|
||||||
bridgeSettings.getBridgeControl().setReinit(false);
|
|
||||||
stop();
|
stop();
|
||||||
|
if(!bridgeSettings.getBridgeControl().isStop()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Sleep error: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||||
|
if(bridgeSettings.getBridgeSecurity().isSettingsChanged())
|
||||||
|
bridgeSettings.updateConfigFile();
|
||||||
|
try {
|
||||||
|
HttpClientPool.shutdown();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||||
|
}
|
||||||
|
thePool = null;
|
||||||
|
log.info("HA Bridge (v{}) exiting....", theVersion.getVersion());
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void theExceptionHandler(Exception e, Integer thePort) {
|
||||||
|
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||||
|
if(e.getMessage().equals("no valid keystore") || e.getMessage().equals("keystore password was incorrect")) {
|
||||||
|
log.error("Https settings have been removed as {}. Restart system manually after this process exits....", e.getMessage());
|
||||||
|
log.warn(theSystem.removeHttpsSettings());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.error("Could not start ha-bridge webservice on port [{}] due to: {}", thePort, e.getMessage());
|
||||||
|
log.warn(theSystem.stop());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
|
|||||||
import com.bwssystems.HABridge.hue.HueMulatorHandler;
|
import com.bwssystems.HABridge.hue.HueMulatorHandler;
|
||||||
|
|
||||||
public interface Home extends HueMulatorHandler, ResourceHandler {
|
public interface Home extends HueMulatorHandler, ResourceHandler {
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings);
|
public Home createHome(BridgeSettings bridgeSettings);
|
||||||
public void closeHome();
|
public void closeHome();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,35 @@ import java.util.Collection;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
|
import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
|
||||||
import com.bwssystems.HABridge.plugins.NestBridge.NestHome;
|
import com.bwssystems.HABridge.plugins.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.broadlink.BroadlinkHome;
|
||||||
import com.bwssystems.HABridge.plugins.domoticz.DomoticzHome;
|
import com.bwssystems.HABridge.plugins.domoticz.DomoticzHome;
|
||||||
import com.bwssystems.HABridge.plugins.exec.CommandHome;
|
import com.bwssystems.HABridge.plugins.exec.CommandHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.fhem.FHEMHome;
|
||||||
import com.bwssystems.HABridge.plugins.hal.HalHome;
|
import com.bwssystems.HABridge.plugins.hal.HalHome;
|
||||||
import com.bwssystems.HABridge.plugins.harmony.HarmonyHome;
|
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.homewizard.HomeWizardHome;
|
||||||
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.lifx.LifxHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.moziot.MozIotHome;
|
||||||
import com.bwssystems.HABridge.plugins.mqtt.MQTTHome;
|
import com.bwssystems.HABridge.plugins.mqtt.MQTTHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.openhab.OpenHABHome;
|
||||||
import com.bwssystems.HABridge.plugins.somfy.SomfyHome;
|
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;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.FibaroHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.homegenie.HomeGenieHome;
|
||||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||||
|
|
||||||
public class HomeManager {
|
public class HomeManager {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeManager.class);
|
||||||
Map<String, Home> homeList;
|
Map<String, Home> homeList;
|
||||||
Map<String, Home> resourceList;
|
Map<String, Home> resourceList;
|
||||||
|
|
||||||
@@ -31,8 +42,16 @@ public class HomeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// factory method
|
// factory method
|
||||||
public void buildHomes(BridgeSettingsDescriptor bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
|
public void buildHomes(BridgeSettings bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
|
||||||
Home aHome = null;
|
Home aHome = null;
|
||||||
|
//setup the http handler Home - This must be the first home created for devMode
|
||||||
|
aHome = new HTTPHome(bridgeSettings);
|
||||||
|
homeList.put(DeviceMapTypes.HTTP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||||
//setup the harmony connection if available
|
//setup the harmony connection if available
|
||||||
aHome = new HarmonyHome(bridgeSettings);
|
aHome = new HarmonyHome(bridgeSettings);
|
||||||
resourceList.put(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex], aHome);
|
||||||
@@ -63,16 +82,14 @@ public class HomeManager {
|
|||||||
aHome = new HassHome(bridgeSettings);
|
aHome = new HassHome(bridgeSettings);
|
||||||
resourceList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
// Setup the HomeWizard configuration if available
|
||||||
|
aHome = new HomeWizardHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
//setup the command execution Home
|
//setup the command execution Home
|
||||||
aHome = new CommandHome(bridgeSettings);
|
aHome = new CommandHome(bridgeSettings);
|
||||||
homeList.put(DeviceMapTypes.EXEC_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.EXEC_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.CMD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.CMD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
//setup the http handler Home
|
|
||||||
aHome = new HTTPHome(bridgeSettings);
|
|
||||||
homeList.put(DeviceMapTypes.HTTP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
|
||||||
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
|
||||||
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
|
||||||
homeList.put(DeviceMapTypes.VERA_SCENE[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);
|
||||||
@@ -85,11 +102,15 @@ public class HomeManager {
|
|||||||
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 Fibaro Home if available
|
||||||
|
aHome = new FibaroHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
resourceList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||||
//setup the Domoticz 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);
|
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
|
//setup the Somfy configuration if availableOPENHAB
|
||||||
aHome = new SomfyHome(bridgeSettings);
|
aHome = new SomfyHome(bridgeSettings);
|
||||||
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
@@ -97,6 +118,26 @@ public class HomeManager {
|
|||||||
aHome = new LifxHome(bridgeSettings);
|
aHome = new LifxHome(bridgeSettings);
|
||||||
resourceList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
resourceList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
homeList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
homeList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
//setup the OpenHAB configuration if available
|
||||||
|
aHome = new OpenHABHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
//setup the FHEM configuration if available
|
||||||
|
aHome = new FHEMHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
//setup the Broadlink configuration if available
|
||||||
|
aHome = new BroadlinkHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
//setup the Mozilla IOT configuration if available
|
||||||
|
aHome = new MozIotHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.MOZIOT_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.MOZIOT_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
//setup the HomeGenie configuration if available
|
||||||
|
aHome = new HomeGenieHome(bridgeSettings);
|
||||||
|
resourceList.put(DeviceMapTypes.HOMEGENIE_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
|
homeList.put(DeviceMapTypes.HOMEGENIE_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Home findHome(String type) {
|
public Home findHome(String type) {
|
||||||
@@ -107,8 +148,10 @@ public class HomeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void closeHomes() {
|
public void closeHomes() {
|
||||||
|
log.info("Manager close homes called....");
|
||||||
Collection<Home> theHomes = homeList.values();
|
Collection<Home> theHomes = homeList.values();
|
||||||
for(Home aHome : theHomes) {
|
for(Home aHome : theHomes) {
|
||||||
|
log.info("Closing home: " + aHome.getClass().getCanonicalName());
|
||||||
aHome.closeHome();
|
aHome.closeHome();
|
||||||
}
|
}
|
||||||
homeList.clear();
|
homeList.clear();
|
||||||
|
|||||||
29
src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java
Normal file
29
src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class LinkButtonPressed extends TimerTask {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LinkButtonPressed.class);
|
||||||
|
private BridgeControlDescriptor linkDescriptor;
|
||||||
|
private Timer myTimer;
|
||||||
|
private boolean isSilent;
|
||||||
|
|
||||||
|
public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer, boolean keepSilent) {
|
||||||
|
linkDescriptor = theDescriptor;
|
||||||
|
myTimer = aTimer;
|
||||||
|
isSilent = keepSilent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if(!isSilent)
|
||||||
|
log.info("Link button time ended....");
|
||||||
|
linkDescriptor.setLinkButton(false);
|
||||||
|
myTimer.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/com/bwssystems/HABridge/LinkParams.java
Normal file
20
src/main/java/com/bwssystems/HABridge/LinkParams.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class LinkParams {
|
||||||
|
private Integer seconds;
|
||||||
|
private boolean silent;
|
||||||
|
|
||||||
|
public Integer getSeconds() {
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
public void setSeconds(Integer seconds) {
|
||||||
|
this.seconds = seconds;
|
||||||
|
}
|
||||||
|
public boolean isSilent() {
|
||||||
|
return silent;
|
||||||
|
}
|
||||||
|
public void setSilent(boolean silent) {
|
||||||
|
this.silent = silent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/java/com/bwssystems/HABridge/LoginResult.java
Normal file
22
src/main/java/com/bwssystems/HABridge/LoginResult.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class LoginResult {
|
||||||
|
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
public void setError(String error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,54 +1,113 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
public class NamedIP {
|
public class NamedIP {
|
||||||
private String name;
|
private String name;
|
||||||
private String ip;
|
private String ip;
|
||||||
private String webhook;
|
private String webhook;
|
||||||
private String port;
|
private String port;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private JsonObject extensions;
|
||||||
private Boolean secure;
|
private Boolean secure;
|
||||||
|
private String httpPreamble;
|
||||||
|
private String encodedLogin;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIp() {
|
public String getIp() {
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIp(String ip) {
|
public void setIp(String ip) {
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
}
|
}
|
||||||
public String getWebhook() {
|
|
||||||
return webhook;
|
public String getWebhook() {
|
||||||
}
|
return webhook;
|
||||||
public void setWebhook(final String webhook) {
|
}
|
||||||
this.webhook = webhook;
|
|
||||||
}
|
public void setWebhook(final String webhook) {
|
||||||
public String getPort() {
|
this.webhook = webhook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPort() {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPort(String port) {
|
public void setPort(String port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getSecure() {
|
public Boolean getSecure() {
|
||||||
return secure;
|
return secure;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecure(Boolean secure) {
|
public void setSecure(Boolean secure) {
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonObject getExtensions() {
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtensions(JsonObject extensions) {
|
||||||
|
this.extensions = extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHttpPreamble() {
|
||||||
|
if (httpPreamble == null || !httpPreamble.trim().isEmpty()) {
|
||||||
|
if (getSecure() != null && getSecure())
|
||||||
|
httpPreamble = "https://";
|
||||||
|
else
|
||||||
|
httpPreamble = "http://";
|
||||||
|
|
||||||
|
httpPreamble = httpPreamble + getIp();
|
||||||
|
if (getPort() != null && !getPort().trim().isEmpty()) {
|
||||||
|
httpPreamble = httpPreamble + ":" + getPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHttpPreamble(String httpPreamble) {
|
||||||
|
this.httpPreamble = httpPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserPass64() {
|
||||||
|
if (encodedLogin == null || !encodedLogin.trim().isEmpty()) {
|
||||||
|
if (getUsername() != null && !getUsername().isEmpty() && getPassword() != null
|
||||||
|
&& !getPassword().isEmpty()) {
|
||||||
|
String userPass = getUsername() + ":" + getPassword();
|
||||||
|
encodedLogin = new String(Base64.encodeBase64(userPass.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encodedLogin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
62
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class SecurityInfo {
|
||||||
|
private boolean useLinkButton;
|
||||||
|
private boolean secureHueApi;
|
||||||
|
private boolean isSecure;
|
||||||
|
private String execGarden;
|
||||||
|
private boolean useHttps;
|
||||||
|
private String keyfilePath;
|
||||||
|
private String keyfilePassword;
|
||||||
|
|
||||||
|
public boolean isUseLinkButton() {
|
||||||
|
return useLinkButton;
|
||||||
|
}
|
||||||
|
public void setUseLinkButton(boolean useLinkButton) {
|
||||||
|
this.useLinkButton = useLinkButton;
|
||||||
|
}
|
||||||
|
public boolean isSecureHueApi() {
|
||||||
|
return secureHueApi;
|
||||||
|
}
|
||||||
|
public void setSecureHueApi(boolean secureHueApi) {
|
||||||
|
this.secureHueApi = secureHueApi;
|
||||||
|
}
|
||||||
|
public boolean isSecure() {
|
||||||
|
return isSecure;
|
||||||
|
}
|
||||||
|
public void setSecure(boolean isSecure) {
|
||||||
|
this.isSecure = isSecure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseHttps() {
|
||||||
|
return useHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseHttps(boolean useHttps) {
|
||||||
|
this.useHttps = useHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyfilePath() {
|
||||||
|
return keyfilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyfilePath(String keyfilePath) {
|
||||||
|
this.keyfilePath = keyfilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecGarden() {
|
||||||
|
return execGarden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecGarden(String execGarden) {
|
||||||
|
this.execGarden = execGarden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyfilePassword() {
|
||||||
|
return keyfilePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyfilePassword(String keyfilePassword) {
|
||||||
|
this.keyfilePassword = keyfilePassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/com/bwssystems/HABridge/ShutdownHook.java
Normal file
48
src/main/java/com/bwssystems/HABridge/ShutdownHook.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements the shutdown hook used to properly stop server from the
|
||||||
|
* command line (sending SIGTERM), or while shutting down the host machine.
|
||||||
|
*
|
||||||
|
* @author gaudryc
|
||||||
|
*/
|
||||||
|
public class ShutdownHook extends Thread {
|
||||||
|
|
||||||
|
private final BridgeSettings bridgeSettings;
|
||||||
|
private final SystemControl theSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param bridgeSettings
|
||||||
|
* bridge settings
|
||||||
|
* @param theSystem
|
||||||
|
*/
|
||||||
|
public ShutdownHook(final BridgeSettings bridgeSettings, final SystemControl theSystem) {
|
||||||
|
this.bridgeSettings = bridgeSettings;
|
||||||
|
this.theSystem = theSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Logger log = LoggerFactory.getLogger(ShutdownHook.class);
|
||||||
|
log.info("Shutdown requested...");
|
||||||
|
if (bridgeSettings != null) {
|
||||||
|
if (!bridgeSettings.getBridgeControl().isStop() && (theSystem != null)) {
|
||||||
|
log.info("Forcing system stop...");
|
||||||
|
theSystem.stop();
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Sleep error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("Already stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,19 +4,30 @@ import static spark.Spark.get;
|
|||||||
import static spark.Spark.options;
|
import static spark.Spark.options;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
|
import static spark.Spark.before;
|
||||||
|
import static spark.Spark.halt;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.MulticastSocket;
|
import java.net.MulticastSocket;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
//import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.Base64;
|
||||||
|
//import java.util.Iterator;
|
||||||
|
//import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
//import com.bwssystems.HABridge.api.NameValue;
|
||||||
|
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||||
import com.bwssystems.HABridge.dao.BackupFilename;
|
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
import com.bwssystems.HABridge.util.TextStringFormatter;
|
import com.bwssystems.HABridge.util.TextStringFormatter;
|
||||||
@@ -24,10 +35,12 @@ import com.bwssystems.logservices.LoggerInfo;
|
|||||||
import com.bwssystems.logservices.LoggingForm;
|
import com.bwssystems.logservices.LoggingForm;
|
||||||
import com.bwssystems.logservices.LoggingManager;
|
import com.bwssystems.logservices.LoggingManager;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.classic.spi.LoggingEvent;
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
|
//import ch.qos.logback.core.Appender;
|
||||||
import ch.qos.logback.core.read.CyclicBufferAppender;
|
import ch.qos.logback.core.read.CyclicBufferAppender;
|
||||||
|
|
||||||
public class SystemControl {
|
public class SystemControl {
|
||||||
@@ -47,7 +60,7 @@ public class SystemControl {
|
|||||||
this.version = theVersion;
|
this.version = theVersion;
|
||||||
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
|
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
|
||||||
reacquireCBA();
|
setupLoggerSettings();
|
||||||
theLogServiceMgr = new LoggingManager();
|
theLogServiceMgr = new LoggingManager();
|
||||||
theLogServiceMgr.init();
|
theLogServiceMgr.init();
|
||||||
}
|
}
|
||||||
@@ -55,28 +68,32 @@ public class SystemControl {
|
|||||||
// This function sets up the sparkjava rest calls for the hue api
|
// This function sets up the sparkjava rest calls for the hue api
|
||||||
public void setupServer() {
|
public void setupServer() {
|
||||||
log.info("System control service started....");
|
log.info("System control service started....");
|
||||||
|
before(SYSTEM_CONTEXT + "/*", (request, response) -> {
|
||||||
|
if(bridgeSettings.getBridgeSecurity().isSecure()) {
|
||||||
|
String pathInfo = request.pathInfo();
|
||||||
|
if(pathInfo == null || (!pathInfo.equals(SYSTEM_CONTEXT + "/login") && !pathInfo.equals(SYSTEM_CONTEXT + "/habridge/version"))) {
|
||||||
|
User authUser = bridgeSettings.getBridgeSecurity().getAuthenticatedUser(request);
|
||||||
|
if(authUser == null) {
|
||||||
|
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
// http://ip_address:port/system/habridge/version gets the version of this bridge instance
|
// http://ip_address:port/system/habridge/version gets the version of this bridge instance
|
||||||
get (SYSTEM_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
|
get (SYSTEM_CONTEXT + "/habridge/version", (request, response) -> {
|
||||||
log.debug("Get HA Bridge version: v" + version.getVersion());
|
log.debug("Get HA Bridge version: v" + version.getVersion());
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return "{\"version\":\"" + version.getVersion() + "\"}";
|
response.type("application/json");
|
||||||
});
|
return "{\"version\":\"" + version.getVersion() + "\",\"isSecure\":" + bridgeSettings.getBridgeSecurity().isSecure() + "}";
|
||||||
|
|
||||||
// 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", (request, response) -> {
|
||||||
log.debug("Get logmsgs.");
|
log.debug("Get logmsgs.");
|
||||||
response.status(HttpStatus.SC_OK);
|
|
||||||
String logMsgs;
|
String logMsgs;
|
||||||
int count = -1;
|
int count = -1;
|
||||||
if(cyclicBufferAppender == null)
|
if(cyclicBufferAppender == null)
|
||||||
reacquireCBA();
|
setupLoggerSettings();
|
||||||
if (cyclicBufferAppender != null) {
|
if (cyclicBufferAppender != null) {
|
||||||
count = cyclicBufferAppender.getLength();
|
count = cyclicBufferAppender.getLength();
|
||||||
}
|
}
|
||||||
@@ -93,24 +110,249 @@ public class SystemControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logMsgs = logMsgs + "]";
|
logMsgs = logMsgs + "]";
|
||||||
response.status(200);
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return logMsgs;
|
return logMsgs;
|
||||||
});
|
});
|
||||||
|
|
||||||
// http://ip_address:port/system/logmgmt/loggers gets the logger info for the bridge
|
// http://ip_address:port/system/logmgmt/loggers gets the logger info for the bridge
|
||||||
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", "application/json", (request, response) -> {
|
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", (request, response) -> {
|
||||||
log.debug("Get loggers info with showAll argument: " + request.params(":all"));
|
log.debug("Get loggers info with showAll argument: " + request.params(":all"));
|
||||||
Boolean showAll = false;
|
Boolean showAll = false;
|
||||||
if(request.params(":all").equals("true"))
|
if(request.params(":all").equals("true"))
|
||||||
showAll = true;
|
showAll = true;
|
||||||
theLogServiceMgr.setShowAll(showAll);
|
theLogServiceMgr.setShowAll(showAll);
|
||||||
theLogServiceMgr.init();
|
theLogServiceMgr.init();
|
||||||
response.status(200);
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return theLogServiceMgr.getConfiguredLoggers();
|
return theLogServiceMgr.getConfiguredLoggers();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/setpassword CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/setpassword", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/setpassword which sets a password for a given user
|
||||||
|
post(SYSTEM_CONTEXT + "/setpassword", (request, response) -> {
|
||||||
|
log.debug("setpassword....");
|
||||||
|
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||||
|
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||||
|
String errorMessage = bridgeSettings.getBridgeSecurity().setPassword(theUser);
|
||||||
|
if(errorMessage != null) {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||||
|
} else {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errorMessage == null)
|
||||||
|
errorMessage = "{}";
|
||||||
|
response.type("application/json");
|
||||||
|
return errorMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/adduser CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/adduser", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/adduser which adds a new user
|
||||||
|
put(SYSTEM_CONTEXT + "/adduser", (request, response) -> {
|
||||||
|
log.debug("adduser....");
|
||||||
|
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||||
|
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||||
|
String errorMessage = theUser.validate();
|
||||||
|
if(errorMessage != null) {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||||
|
} else {
|
||||||
|
errorMessage = bridgeSettings.getBridgeSecurity().addUser(theUser);
|
||||||
|
if(errorMessage == null) {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
} else {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errorMessage == null)
|
||||||
|
errorMessage = "{}";
|
||||||
|
response.type("application/json");
|
||||||
|
return errorMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/deluser CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/deluser", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/deluser which dels a user
|
||||||
|
put(SYSTEM_CONTEXT + "/deluser", (request, response) -> {
|
||||||
|
log.debug("deluser....");
|
||||||
|
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||||
|
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||||
|
String errorMessage = bridgeSettings.getBridgeSecurity().delUser(theUser);
|
||||||
|
if(errorMessage != null) {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||||
|
} else {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errorMessage == null)
|
||||||
|
errorMessage = "{}";
|
||||||
|
response.type("application/json");
|
||||||
|
return errorMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/login CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/login", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/login validates the login
|
||||||
|
post(SYSTEM_CONTEXT + "/login", (request, response) -> {
|
||||||
|
log.debug("login....");
|
||||||
|
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||||
|
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||||
|
LoginResult result = bridgeSettings.getBridgeSecurity().validatePassword(theUser);
|
||||||
|
if(result.getUser() != null)
|
||||||
|
bridgeSettings.getBridgeSecurity().addAuthenticatedUser(request, theUser);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return result;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/logout CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/logout", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/logout invalidates user session
|
||||||
|
put(SYSTEM_CONTEXT + "/logout", (request, response) -> {
|
||||||
|
log.debug("logout....");
|
||||||
|
bridgeSettings.getBridgeSecurity().removeAuthenticatedUser(request);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/presslinkbutton CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/presslinkbutton which sets the link button for device registration
|
||||||
|
put(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> {
|
||||||
|
LinkParams linkParams = null;
|
||||||
|
if(!request.body().isEmpty()) {
|
||||||
|
linkParams = new Gson().fromJson(request.body(), LinkParams.class);
|
||||||
|
if(linkParams.getSeconds() <= 0)
|
||||||
|
linkParams.setSeconds(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
linkParams = new LinkParams();
|
||||||
|
linkParams.setSilent(false);
|
||||||
|
linkParams.setSeconds(30);
|
||||||
|
}
|
||||||
|
if(!linkParams.isSilent())
|
||||||
|
log.info("Link button pressed....");
|
||||||
|
bridgeSettings.getBridgeControl().setLinkButton(true);
|
||||||
|
Timer theTimer = new Timer();
|
||||||
|
theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer, linkParams.isSilent()), (linkParams.getSeconds() * 1000));
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return "";
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/securityinfo gets the security info for the bridge
|
||||||
|
get (SYSTEM_CONTEXT + "/securityinfo", (request, response) -> {
|
||||||
|
log.debug("Get security info");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/changesecurityinfo CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/changesecurityinfo which sets the security settings other than passwords and users
|
||||||
|
post(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||||
|
log.debug("changesecurityinfo....");
|
||||||
|
SecurityInfo theInfo = new Gson().fromJson(request.body(), SecurityInfo.class);
|
||||||
|
bridgeSettings.getBridgeSecurity().setSecurityDataByInfo(theInfo);
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/whitelist gets the whitelist for the bridge
|
||||||
|
get (SYSTEM_CONTEXT + "/whitelist", (request, response) -> {
|
||||||
|
log.debug("Get whitelist");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return bridgeSettings.getBridgeSecurity().getWhitelist();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/setwhitelist CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/setwhitelist", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
// http://ip_address:port/system/setwhitelist which sets the whitelist after being managed
|
||||||
|
post(SYSTEM_CONTEXT + "/setwhitelist", (request, response) -> {
|
||||||
|
log.debug("setwhitelist....");
|
||||||
|
Type listType = new TypeToken<Map<String, WhitelistEntry>>() {
|
||||||
|
}.getType();
|
||||||
|
Map<String, WhitelistEntry> aWhitelist = new Gson().fromJson(request.body(), listType);
|
||||||
|
bridgeSettings.getBridgeSecurity().setWhitelist(aWhitelist);
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return bridgeSettings.getBridgeSecurity().getWhitelist();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/logmgmt/update CORS request
|
// http://ip_address:port/system/logmgmt/update CORS request
|
||||||
options(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/logmgmt/update", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
@@ -119,28 +361,30 @@ public class SystemControl {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
// http://ip_address:port/system/logmgmt/update which changes logging parameters for the process
|
// http://ip_address:port/system/logmgmt/update which changes logging parameters for the process
|
||||||
put(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
put(SYSTEM_CONTEXT + "/logmgmt/update", (request, response) -> {
|
||||||
log.debug("update loggers: " + request.body());
|
log.debug("update loggers: " + request.body());
|
||||||
response.status(200);
|
|
||||||
LoggerInfo updateLoggers[];
|
LoggerInfo updateLoggers[];
|
||||||
updateLoggers = new Gson().fromJson(request.body(), LoggerInfo[].class);
|
updateLoggers = new Gson().fromJson(request.body(), LoggerInfo[].class);
|
||||||
LoggingForm theModel = theLogServiceMgr.getModel();
|
LoggingForm theModel = theLogServiceMgr.getModel();
|
||||||
theModel.setUpdatedLoggers(Arrays.asList(updateLoggers));
|
theModel.setUpdatedLoggers(Arrays.asList(updateLoggers));
|
||||||
theLogServiceMgr.updateLogLevels();
|
theLogServiceMgr.updateLogLevels();
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return theLogServiceMgr.getConfiguredLoggers();
|
return theLogServiceMgr.getConfiguredLoggers();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
||||||
get(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
get(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||||
log.debug("bridge settings requested from " + request.ip());
|
log.debug("bridge settings requested from " + request.ip());
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
response.status(200);
|
response.type("application/json");
|
||||||
|
// if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() == null)
|
||||||
|
// bridgeSettings.getBridgeSettingsDescriptor().setActiveloggers(getLogAppenders());
|
||||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/settings CORS request
|
// http://ip_address:port/system/settings CORS request
|
||||||
options(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
@@ -149,17 +393,19 @@ public class SystemControl {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
||||||
put(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
put(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||||
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
|
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
|
||||||
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
|
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
|
||||||
|
if(newBridgeSettings.getUpnpsenddelay() > 15000)
|
||||||
|
newBridgeSettings.setUpnpsenddelay(15000);
|
||||||
bridgeSettings.save(newBridgeSettings);
|
bridgeSettings.save(newBridgeSettings);
|
||||||
response.status(200);
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/control/reinit CORS request
|
// http://ip_address:port/system/control/reinit CORS request
|
||||||
options(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/control/reinit", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
@@ -168,12 +414,14 @@ public class SystemControl {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
// http://ip_address:port/system/control/reinit sets the parameter reinit the server
|
// http://ip_address:port/system/control/reinit sets the parameter reinit the server
|
||||||
put(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
|
put(SYSTEM_CONTEXT + "/control/reinit", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return reinit();
|
return reinit();
|
||||||
});
|
});
|
||||||
|
|
||||||
// http://ip_address:port/system/control/stop CORS request
|
// http://ip_address:port/system/control/stop CORS request
|
||||||
options(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/control/stop", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
@@ -182,19 +430,14 @@ public class SystemControl {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
// http://ip_address:port/system/control/stop sets the parameter stop the server
|
// http://ip_address:port/system/control/stop sets the parameter stop the server
|
||||||
put(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
|
put(SYSTEM_CONTEXT + "/control/stop", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return stop();
|
return stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
// http://ip_address:port/system/backup/available returns a list of config backup filenames
|
// http://ip_address:port/system/devices/backup/download CORS request
|
||||||
get (SYSTEM_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/backup/download", "application/json", (request, response) -> {
|
||||||
log.debug("Get backup filenames");
|
|
||||||
response.status(HttpStatus.SC_OK);
|
|
||||||
return bridgeSettings.getBackups();
|
|
||||||
}, new JsonTransformer());
|
|
||||||
|
|
||||||
// http://ip_address:port/system/backup/create CORS request
|
|
||||||
options(SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "PUT");
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
@@ -202,16 +445,61 @@ public class SystemControl {
|
|||||||
response.header("Content-Type", "text/html; charset=utf-8");
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
put (SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
put (SYSTEM_CONTEXT + "/backup/download", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create download: {}", request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
String backupContent = bridgeSettings.downloadBackup(aFilename.getFilename());
|
||||||
|
return backupContent;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/devices/backup/upload CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/backup/upload/:filename", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (SYSTEM_CONTEXT + "/backup/upload/:filename", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create upload: {} - {}", request.params(":filename"), request.body());
|
||||||
|
String theSuccess = bridgeSettings.uploadBackup(request.params(":filename"), request.body());
|
||||||
|
if(theSuccess.contains("Error:"))
|
||||||
|
response.status(HttpStatus.SC_METHOD_FAILURE);
|
||||||
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return theSuccess;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/available returns a list of config backup filenames
|
||||||
|
get (SYSTEM_CONTEXT + "/backup/available", (request, response) -> {
|
||||||
|
log.debug("Get backup filenames");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return bridgeSettings.getBackups();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/create CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/backup/create", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (SYSTEM_CONTEXT + "/backup/create", (request, response) -> {
|
||||||
log.debug("Create backup: " + request.body());
|
log.debug("Create backup: " + request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
BackupFilename returnFilename = new BackupFilename();
|
BackupFilename returnFilename = new BackupFilename();
|
||||||
returnFilename.setFilename(bridgeSettings.backup(aFilename.getFilename()));
|
returnFilename.setFilename(bridgeSettings.backup(aFilename.getFilename()));
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return returnFilename;
|
return returnFilename;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/backup/delete CORS request
|
// http://ip_address:port/system/backup/delete CORS request
|
||||||
options(SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/backup/delete", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "POST");
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
@@ -219,18 +507,20 @@ public class SystemControl {
|
|||||||
response.header("Content-Type", "text/html; charset=utf-8");
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
post (SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
post (SYSTEM_CONTEXT + "/backup/delete", (request, response) -> {
|
||||||
log.debug("Delete backup: " + request.body());
|
log.debug("Delete backup: " + request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
if(aFilename != null)
|
if(aFilename != null)
|
||||||
bridgeSettings.deleteBackup(aFilename.getFilename());
|
bridgeSettings.deleteBackup(aFilename.getFilename());
|
||||||
else
|
else
|
||||||
log.warn("No filename given for delete backup.");
|
log.warn("No filename given for delete backup.");
|
||||||
return null;
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
|
return "";
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/system/backup/restore CORS request
|
// http://ip_address:port/system/backup/restore CORS request
|
||||||
options(SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
options(SYSTEM_CONTEXT + "/backup/restore", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.header("Access-Control-Allow-Methods", "POST");
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
@@ -238,7 +528,7 @@ public class SystemControl {
|
|||||||
response.header("Content-Type", "text/html; charset=utf-8");
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
post (SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
post (SYSTEM_CONTEXT + "/backup/restore", (request, response) -> {
|
||||||
log.debug("Restore backup: " + request.body());
|
log.debug("Restore backup: " + request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
if(aFilename != null) {
|
if(aFilename != null) {
|
||||||
@@ -247,15 +537,48 @@ public class SystemControl {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
log.warn("No filename given for restore backup.");
|
log.warn("No filename given for restore backup.");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.type("application/json");
|
||||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void reacquireCBA() {
|
private void setupLoggerSettings() {
|
||||||
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
|
// final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
|
|
||||||
|
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
|
||||||
Logger.ROOT_LOGGER_NAME).getAppender(CYCLIC_BUFFER_APPENDER_NAME);
|
Logger.ROOT_LOGGER_NAME).getAppender(CYCLIC_BUFFER_APPENDER_NAME);
|
||||||
cyclicBufferAppender.setMaxSize(bridgeSettings.getBridgeSettingsDescriptor().getNumberoflogmessages());
|
cyclicBufferAppender.setMaxSize(bridgeSettings.getBridgeSettingsDescriptor().getNumberoflogmessages());
|
||||||
}
|
// if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() != null) {
|
||||||
|
// for (NameValue temp : bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers()) {
|
||||||
|
// if(temp.getValue().equals("false"))
|
||||||
|
// logger.detachAppender(temp.getName());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// private List<NameValue> getLogAppenders() {
|
||||||
|
// final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
|
//
|
||||||
|
// final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
|
||||||
|
//
|
||||||
|
// List<NameValue> theLoggers = new ArrayList<NameValue>();
|
||||||
|
//
|
||||||
|
// while (it.hasNext()) {
|
||||||
|
//
|
||||||
|
// final Appender<ILoggingEvent> appender = it.next();
|
||||||
|
//
|
||||||
|
// if (!(appender instanceof CyclicBufferAppender)) {
|
||||||
|
// NameValue theLogger = new NameValue();
|
||||||
|
// theLogger.setName(appender.getName());
|
||||||
|
// theLogger.setValue("true");
|
||||||
|
// theLoggers.add(theLogger);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return theLoggers;
|
||||||
|
// }
|
||||||
|
|
||||||
protected void pingListener() {
|
protected void pingListener() {
|
||||||
try {
|
try {
|
||||||
@@ -276,6 +599,11 @@ public class SystemControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String removeHttpsSettings() {
|
||||||
|
bridgeSettings.getBridgeSecurity().removeHttpsSettings();
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
|
||||||
public String reinit() {
|
public String reinit() {
|
||||||
bridgeSettings.getBridgeControl().setReinit(true);
|
bridgeSettings.getBridgeControl().setReinit(true);
|
||||||
pingListener();
|
pingListener();
|
||||||
@@ -287,4 +615,5 @@ public class SystemControl {
|
|||||||
pingListener();
|
pingListener();
|
||||||
return "{\"control\":\"stopping\"}";
|
return "{\"control\":\"stopping\"}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
65
src/main/java/com/bwssystems/HABridge/User.java
Normal file
65
src/main/java/com/bwssystems/HABridge/User.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import spark.utils.StringUtils;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String password2;
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword2() {
|
||||||
|
return password2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword2(String password2) {
|
||||||
|
this.password2 = password2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String validate() {
|
||||||
|
String error = null;
|
||||||
|
|
||||||
|
if(StringUtils.isEmpty(username)) {
|
||||||
|
error = "You have to enter a username";
|
||||||
|
} else if(StringUtils.isEmpty(password)) {
|
||||||
|
error = "You have to enter a password";
|
||||||
|
} else if(!password.equals(password2)) {
|
||||||
|
error = "The two passwords do not match";
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validatePassword() {
|
||||||
|
if(password != null && password2 != null)
|
||||||
|
return password.equals(password2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
|
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
@@ -14,6 +15,9 @@ public class DeviceResponse {
|
|||||||
private String luminaireuniqueid;
|
private String luminaireuniqueid;
|
||||||
private String uniqueid;
|
private String uniqueid;
|
||||||
private String swversion;
|
private String swversion;
|
||||||
|
private String swconfigid;
|
||||||
|
private String productid;
|
||||||
|
private String productname;
|
||||||
|
|
||||||
public DeviceState getState() {
|
public DeviceState getState() {
|
||||||
return state;
|
return state;
|
||||||
@@ -71,6 +75,31 @@ public class DeviceResponse {
|
|||||||
this.swversion = swversion;
|
this.swversion = swversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSwconfigid() {
|
||||||
|
return swconfigid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwconfigid(String swconfigid) {
|
||||||
|
this.swconfigid = swconfigid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProductid() {
|
||||||
|
return productid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProductid(String productid) {
|
||||||
|
this.productid = productid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProductName() {
|
||||||
|
return productname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProductName(String productname) {
|
||||||
|
this.productname = productname;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getLuminaireuniqueid() {
|
public String getLuminaireuniqueid() {
|
||||||
return luminaireuniqueid;
|
return luminaireuniqueid;
|
||||||
}
|
}
|
||||||
@@ -86,11 +115,43 @@ public class DeviceResponse {
|
|||||||
response.setName(device.getName());
|
response.setName(device.getName());
|
||||||
response.setUniqueid(device.getUniqueid());
|
response.setUniqueid(device.getUniqueid());
|
||||||
response.setManufacturername("Philips");
|
response.setManufacturername("Philips");
|
||||||
response.setType("Dimmable light");
|
|
||||||
response.setModelid("LWB004");
|
if (device.isColorDevice()) {
|
||||||
response.setSwversion("66012040");
|
response.setType("Extended color light");
|
||||||
|
response.setModelid("LCT015");
|
||||||
|
response.setSwversion("1.46.13_r26312");
|
||||||
|
response.setSwconfigid("52E3234B");
|
||||||
|
response.setProductid("Philips-LCT015-1-A19ECLv5");
|
||||||
|
response.setProductName("Hue color lamp");
|
||||||
|
} else {
|
||||||
|
response.setType("Dimmable light");
|
||||||
|
response.setModelid("LWB007");
|
||||||
|
response.setSwversion("66012040");
|
||||||
|
}
|
||||||
|
|
||||||
response.setLuminaireuniqueid(null);
|
response.setLuminaireuniqueid(null);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DeviceResponse createResponseForVirtualLight(GroupDescriptor group){
|
||||||
|
DeviceResponse response = new DeviceResponse();
|
||||||
|
response.setState(group.getAction());
|
||||||
|
|
||||||
|
response.setName(group.getName());
|
||||||
|
response.setUniqueid("00:11:22:33:44:55:66:77-" + String.format("%02X", Integer.parseInt(group.getId())));
|
||||||
|
response.setManufacturername("Philips");
|
||||||
|
response.setType("Extended color light");
|
||||||
|
response.setModelid("LCT015");
|
||||||
|
response.setSwversion("1.46.13_r26312");
|
||||||
|
response.setSwconfigid("52E3234B");
|
||||||
|
response.setProductid("Philips-LCT015-1-A19ECLv5");
|
||||||
|
response.setProductName("Hue color lamp");
|
||||||
|
|
||||||
|
response.setLuminaireuniqueid(null);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
// import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,14 +9,15 @@ import java.util.List;
|
|||||||
public class DeviceState {
|
public class DeviceState {
|
||||||
private boolean on;
|
private boolean on;
|
||||||
private int bri;
|
private int bri;
|
||||||
private int hue;
|
private Integer hue;
|
||||||
private int sat;
|
private Integer sat;
|
||||||
private String effect;
|
private String effect;
|
||||||
private int ct;
|
private List<Double> xy;
|
||||||
|
private Integer ct;
|
||||||
private String alert;
|
private String alert;
|
||||||
private String colormode;
|
private String colormode;
|
||||||
private boolean reachable;
|
private boolean reachable;
|
||||||
private List<Double> xy;
|
|
||||||
// private int transitiontime;
|
// private int transitiontime;
|
||||||
|
|
||||||
public boolean isOn() {
|
public boolean isOn() {
|
||||||
@@ -36,19 +37,21 @@ public class DeviceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getHue() {
|
public int getHue() {
|
||||||
return hue;
|
return hue != null ? hue.intValue() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHue(int hue) {
|
public void setHue(int hue) {
|
||||||
this.hue = hue;
|
this.hue = hue;
|
||||||
|
this.colormode = "hs";
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSat() {
|
public int getSat() {
|
||||||
return sat;
|
return sat != null ? sat.intValue() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSat(int sat) {
|
public void setSat(int sat) {
|
||||||
this.sat = sat;
|
this.sat = sat;
|
||||||
|
this.colormode = "hs";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEffect() {
|
public String getEffect() {
|
||||||
@@ -60,11 +63,12 @@ public class DeviceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getCt() {
|
public int getCt() {
|
||||||
return ct;
|
return ct != null ? ct.intValue() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCt(int ct) {
|
public void setCt(int ct) {
|
||||||
this.ct = ct;
|
this.ct = ct;
|
||||||
|
this.colormode = "ct";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlert() {
|
public String getAlert() {
|
||||||
@@ -97,6 +101,7 @@ public class DeviceState {
|
|||||||
|
|
||||||
public void setXy(List<Double> xy) {
|
public void setXy(List<Double> xy) {
|
||||||
this.xy = xy;
|
this.xy = xy;
|
||||||
|
this.colormode = "xy";
|
||||||
}
|
}
|
||||||
// public int getTransitiontime() {
|
// public int getTransitiontime() {
|
||||||
// return transitiontime;
|
// return transitiontime;
|
||||||
@@ -106,22 +111,28 @@ public class DeviceState {
|
|||||||
// this.transitiontime = transitiontime;
|
// this.transitiontime = transitiontime;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static DeviceState createDeviceState() {
|
public static DeviceState createDeviceState(boolean color) {
|
||||||
DeviceState newDeviceState = new DeviceState();
|
DeviceState newDeviceState = new DeviceState();
|
||||||
newDeviceState.fillIn();
|
newDeviceState.fillIn(color);
|
||||||
// newDeviceState.setColormode("none");
|
if (color) {
|
||||||
// ArrayList<Double> doubleArray = new ArrayList<Double>();
|
newDeviceState.setColormode("xy");
|
||||||
// doubleArray.add(new Double(0));
|
newDeviceState.setHue(0);
|
||||||
// doubleArray.add(new Double(0));
|
newDeviceState.setSat(0);
|
||||||
// newDeviceState.setXy(doubleArray);
|
newDeviceState.setCt(153);
|
||||||
|
ArrayList<Double> doubleArray = new ArrayList<Double>();
|
||||||
|
doubleArray.add(0.3146);
|
||||||
|
doubleArray.add(0.3303);
|
||||||
|
newDeviceState.setXy(doubleArray);
|
||||||
|
}
|
||||||
return newDeviceState;
|
return newDeviceState;
|
||||||
}
|
}
|
||||||
public void fillIn() {
|
public void fillIn(boolean color) {
|
||||||
if(this.getAlert() == null)
|
if(this.getAlert() == null)
|
||||||
this.setAlert("none");
|
this.setAlert("none");
|
||||||
if(this.getEffect() == null)
|
if (color) {
|
||||||
this.setEffect("none");
|
if(this.getEffect() == null)
|
||||||
|
this.setEffect("none");
|
||||||
|
}
|
||||||
this.setReachable(true);
|
this.setReachable(true);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class GroupClassTypes {
|
||||||
|
|
||||||
|
public final static String BATHROOM = "Bathroom";
|
||||||
|
public final static String BEDROOM = "Bedroom";
|
||||||
|
public final static String CARPORT = "Carport";
|
||||||
|
public final static String DINING = "Dining";
|
||||||
|
public final static String DRIVEWAY = "Driveway";
|
||||||
|
public final static String FRONT_DOOR = "Front door";
|
||||||
|
public final static String GARAGE = "Garage";
|
||||||
|
public final static String GARDEN = "Garden";
|
||||||
|
public final static String GYM = "Gym";
|
||||||
|
public final static String HALLWAY = "Hallway";
|
||||||
|
public final static String BEDROOM_KIDS = "Kids bedroom";
|
||||||
|
public final static String KITCHEN = "Kitchen";
|
||||||
|
public final static String LIVING_ROOM = "Living room";
|
||||||
|
public final static String NURSERY = "Nursery";
|
||||||
|
public final static String OFFICE = "Office";
|
||||||
|
public final static String OTHER = "Other";
|
||||||
|
public final static String RECREATION = "Recreation";
|
||||||
|
public final static String TERRACE = "Terrace";
|
||||||
|
public final static String TOILET = "Toilet";
|
||||||
|
|
||||||
|
ArrayList<String> groupClassTypes;
|
||||||
|
|
||||||
|
public GroupClassTypes() {
|
||||||
|
groupClassTypes = new ArrayList<String>();
|
||||||
|
groupClassTypes.add(BATHROOM);
|
||||||
|
groupClassTypes.add(BEDROOM);
|
||||||
|
groupClassTypes.add(CARPORT);
|
||||||
|
groupClassTypes.add(DINING);
|
||||||
|
groupClassTypes.add(DRIVEWAY);
|
||||||
|
groupClassTypes.add(FRONT_DOOR);
|
||||||
|
groupClassTypes.add(GARAGE);
|
||||||
|
groupClassTypes.add(GARDEN);
|
||||||
|
groupClassTypes.add(GYM);
|
||||||
|
groupClassTypes.add(HALLWAY);
|
||||||
|
groupClassTypes.add(BEDROOM_KIDS);
|
||||||
|
groupClassTypes.add(KITCHEN);
|
||||||
|
groupClassTypes.add(LIVING_ROOM);
|
||||||
|
groupClassTypes.add(NURSERY);
|
||||||
|
groupClassTypes.add(OFFICE);
|
||||||
|
groupClassTypes.add(OTHER);
|
||||||
|
groupClassTypes.add(RECREATION);
|
||||||
|
groupClassTypes.add(TERRACE);
|
||||||
|
groupClassTypes.add(TOILET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean validateType(String type) {
|
||||||
|
if(type == null || type.trim().isEmpty())
|
||||||
|
return false;
|
||||||
|
for(String classType : groupClassTypes) {
|
||||||
|
if(type.trim().contentEquals(classType))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
public class GroupResponse {
|
public class GroupResponse {
|
||||||
@@ -16,6 +16,8 @@ public class GroupResponse {
|
|||||||
private String type;
|
private String type;
|
||||||
@SerializedName("class")
|
@SerializedName("class")
|
||||||
String class_name;
|
String class_name;
|
||||||
|
@SerializedName("state")
|
||||||
|
private GroupState state;
|
||||||
|
|
||||||
public DeviceState getAction() {
|
public DeviceState getAction() {
|
||||||
return action;
|
return action;
|
||||||
@@ -23,6 +25,14 @@ public class GroupResponse {
|
|||||||
public void setAction(DeviceState action) {
|
public void setAction(DeviceState action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GroupState getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
public void setState(GroupState state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
public String[] getLights() {
|
public String[] getLights() {
|
||||||
return lights;
|
return lights;
|
||||||
}
|
}
|
||||||
@@ -48,34 +58,69 @@ public class GroupResponse {
|
|||||||
public void setClass_name(String class_name) {
|
public void setClass_name(String class_name) {
|
||||||
this.class_name = class_name;
|
this.class_name = class_name;
|
||||||
}
|
}
|
||||||
public static GroupResponse createDefaultGroupResponse(List<DeviceDescriptor> deviceList) {
|
|
||||||
String[] theList = new String[deviceList.size()];
|
|
||||||
int i = 0;
|
|
||||||
for (DeviceDescriptor device : deviceList) {
|
|
||||||
theList[i] = device.getId();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
GroupResponse theResponse = new GroupResponse();
|
|
||||||
theResponse.setAction(DeviceState.createDeviceState());
|
|
||||||
theResponse.setName("Lightset 0");
|
|
||||||
theResponse.setLights(theList);
|
|
||||||
theResponse.setType("LightGroup");
|
|
||||||
return theResponse;
|
|
||||||
}
|
|
||||||
public static GroupResponse createOtherGroupResponse(List<DeviceDescriptor> deviceList) {
|
|
||||||
String[] theList = new String[deviceList.size()];
|
|
||||||
int i = 0;
|
|
||||||
for (DeviceDescriptor device : deviceList) {
|
|
||||||
theList[i] = device.getId();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
GroupResponse theResponse = new GroupResponse();
|
|
||||||
theResponse.setAction(DeviceState.createDeviceState());
|
|
||||||
theResponse.setName("AGroup");
|
|
||||||
theResponse.setLights(theList);
|
|
||||||
theResponse.setType("Room");
|
|
||||||
theResponse.setClass_name("Other");
|
|
||||||
|
|
||||||
return theResponse;
|
public static GroupResponse createDefaultGroupResponse(Map<String, DeviceResponse> deviceList) {
|
||||||
}
|
String[] theList = new String[deviceList.size()];
|
||||||
|
Boolean all_on = true;
|
||||||
|
Boolean any_on = false;
|
||||||
|
int i = 0;
|
||||||
|
for (Map.Entry<String, DeviceResponse> device : deviceList.entrySet()) {
|
||||||
|
if (Integer.parseInt(device.getKey()) >= 10000) { // don't show fake lights for other groups
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
theList[i] = device.getKey();
|
||||||
|
Boolean is_on = device.getValue().getState().isOn();
|
||||||
|
if (is_on)
|
||||||
|
any_on = true;
|
||||||
|
else
|
||||||
|
all_on = false;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
GroupResponse theResponse = new GroupResponse();
|
||||||
|
theResponse.setAction(DeviceState.createDeviceState(true));
|
||||||
|
theResponse.setState(new GroupState(all_on, any_on));
|
||||||
|
theResponse.setName("Group 0");
|
||||||
|
theResponse.setLights(theList);
|
||||||
|
theResponse.setType("LightGroup");
|
||||||
|
return theResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupResponse createResponse(GroupDescriptor group, Map<String, DeviceResponse> lights){
|
||||||
|
GroupResponse response = new GroupResponse();
|
||||||
|
Boolean all_on = true;
|
||||||
|
Boolean any_on = false;
|
||||||
|
String[] groupLights = null;
|
||||||
|
if (lights == null) {
|
||||||
|
all_on = false;
|
||||||
|
groupLights = group.getLights();
|
||||||
|
} else {
|
||||||
|
for (DeviceResponse light : lights.values()) {
|
||||||
|
Boolean is_on = light.getState().isOn();
|
||||||
|
if (is_on)
|
||||||
|
any_on = true;
|
||||||
|
else
|
||||||
|
all_on = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// group.getLights() is not filtered by requester, lights is
|
||||||
|
// we want the filtered version but keep the order from group.getLights()
|
||||||
|
groupLights = new String[lights.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (String light : group.getLights()) {
|
||||||
|
if (lights.keySet().contains(light)) {
|
||||||
|
groupLights[i] = light;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setState(new GroupState(all_on, any_on));
|
||||||
|
response.setAction(group.getAction());
|
||||||
|
response.setName(group.getName());
|
||||||
|
response.setType(group.getGroupType());
|
||||||
|
response.setLights(groupLights);
|
||||||
|
response.setClass_name(group.getGroupClass());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Florian Foerderreuther on 07/23/17
|
||||||
|
*/
|
||||||
|
public class GroupState {
|
||||||
|
private boolean all_on;
|
||||||
|
private boolean any_on;
|
||||||
|
|
||||||
|
public boolean isAllOn() {
|
||||||
|
return all_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAnyOn() {
|
||||||
|
return any_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(boolean all_on, boolean any_on) {
|
||||||
|
this.all_on = all_on;
|
||||||
|
this.any_on = any_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupState(boolean all_on, boolean any_on) {
|
||||||
|
this.all_on = all_on;
|
||||||
|
this.any_on = any_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "GroupState{" +
|
||||||
|
"all_on=" + all_on +
|
||||||
|
", any_on=" + any_on +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,9 @@ public class HueApiResponse {
|
|||||||
private Map<String, JsonObject> rules;
|
private Map<String, JsonObject> rules;
|
||||||
private HueConfig config;
|
private HueConfig config;
|
||||||
|
|
||||||
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion) {
|
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) {
|
||||||
super();
|
super();
|
||||||
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion));
|
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion, isLinkButtonPressed, emulateMAC));
|
||||||
this.setRules(new HashMap<>());
|
this.setRules(new HashMap<>());
|
||||||
this.setSensors(new HashMap<>());
|
this.setSensors(new HashMap<>());
|
||||||
this.setSchedules(new HashMap<>());
|
this.setSchedules(new HashMap<>());
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class HueConfig
|
|||||||
private String replacesbridgeid;
|
private String replacesbridgeid;
|
||||||
private Map<String, WhitelistEntry> whitelist;
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
|
|
||||||
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion) {
|
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) {
|
||||||
HueConfig aConfig = new HueConfig();
|
HueConfig aConfig = new HueConfig();
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
@@ -44,7 +44,7 @@ public class HueConfig
|
|||||||
aConfig.setPortalservices(false);
|
aConfig.setPortalservices(false);
|
||||||
aConfig.setGateway(ipaddress);
|
aConfig.setGateway(ipaddress);
|
||||||
aConfig.setSwversion(emulateHubVersion);
|
aConfig.setSwversion(emulateHubVersion);
|
||||||
aConfig.setLinkbutton(true);
|
aConfig.setLinkbutton(isLinkButtonPressed);
|
||||||
aConfig.setIpaddress(ipaddress);
|
aConfig.setIpaddress(ipaddress);
|
||||||
aConfig.setProxyport(0);
|
aConfig.setProxyport(0);
|
||||||
aConfig.setSwupdate(Swupdate.createSwupdate());
|
aConfig.setSwupdate(Swupdate.createSwupdate());
|
||||||
@@ -56,7 +56,7 @@ public class HueConfig
|
|||||||
aConfig.setLocaltime(dateFormat.format(new Date()));
|
aConfig.setLocaltime(dateFormat.format(new Date()));
|
||||||
aConfig.setTimezone(TimeZone.getDefault().getID());
|
aConfig.setTimezone(TimeZone.getDefault().getID());
|
||||||
aConfig.setZigbeechannel("6");
|
aConfig.setZigbeechannel("6");
|
||||||
aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion).getHueBridgeIdFromMac());
|
aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion, emulateMAC).getHueBridgeIdFromMac());
|
||||||
aConfig.setModelid(HueConstants.MODEL_ID);
|
aConfig.setModelid(HueConstants.MODEL_ID);
|
||||||
aConfig.setFactorynew(false);
|
aConfig.setFactorynew(false);
|
||||||
aConfig.setReplacesbridgeid(null);
|
aConfig.setReplacesbridgeid(null);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
public class HueConstants {
|
public class HueConstants {
|
||||||
public final static String HUB_VERSION = "01036659";
|
public final static String HUB_VERSION = "9999999999";
|
||||||
public final static String API_VERSION = "1.15.0";
|
public final static String API_VERSION = "1.19.0";
|
||||||
public final static String MODEL_ID = "BSB002";
|
public final static String MODEL_ID = "BSB002";
|
||||||
public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-";
|
public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ public class HuePublicConfig
|
|||||||
private Boolean factorynew;
|
private Boolean factorynew;
|
||||||
private String modelid;
|
private String modelid;
|
||||||
|
|
||||||
public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion) {
|
public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion, String emulateMAC) {
|
||||||
HuePublicConfig aConfig = new HuePublicConfig();
|
HuePublicConfig aConfig = new HuePublicConfig();
|
||||||
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
|
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress, emulateMAC));
|
||||||
aConfig.setApiversion(HueConstants.API_VERSION);
|
aConfig.setApiversion(HueConstants.API_VERSION);
|
||||||
aConfig.setSwversion(emulateHubVersion);
|
aConfig.setSwversion(emulateHubVersion);
|
||||||
aConfig.setName(name);
|
aConfig.setName(name);
|
||||||
@@ -32,34 +32,39 @@ public class HuePublicConfig
|
|||||||
return aConfig;
|
return aConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getMacAddress(String addr)
|
private static String getMacAddress(String addr, String aMAC)
|
||||||
{
|
{
|
||||||
InetAddress ip;
|
InetAddress ip;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try {
|
if(aMAC == null || aMAC.trim().length() <= 0) {
|
||||||
|
try {
|
||||||
|
|
||||||
ip = InetAddress.getByName(addr);
|
ip = InetAddress.getByName(addr);
|
||||||
|
|
||||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||||
|
|
||||||
byte[] mac = network.getHardwareAddress();
|
byte[] mac = network.getHardwareAddress();
|
||||||
|
|
||||||
|
for (int i = 0; i < mac.length; i++) {
|
||||||
|
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (SocketException e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
for (int i = 0; i < mac.length; i++) {
|
|
||||||
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (UnknownHostException e) {
|
else {
|
||||||
|
sb.append(aMAC.trim());
|
||||||
sb.append("00:00:88:00:bb:ee");
|
|
||||||
|
|
||||||
} catch (SocketException e){
|
|
||||||
|
|
||||||
sb.append("00:00:88:00:bb:ee");
|
|
||||||
|
|
||||||
} catch (Exception e){
|
|
||||||
|
|
||||||
sb.append("00:00:88:00:bb:ee");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
public class WhitelistEntry
|
public class WhitelistEntry
|
||||||
{
|
{
|
||||||
private String lastUseDate;
|
private String lastUseDate;
|
||||||
private String createDate;
|
private String createDate;
|
||||||
private String name;
|
private String name;
|
||||||
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
|
||||||
public static WhitelistEntry createEntry(String devicetype) {
|
public static WhitelistEntry createEntry(String devicetype) {
|
||||||
WhitelistEntry anEntry = new WhitelistEntry();
|
WhitelistEntry anEntry = new WhitelistEntry();
|
||||||
@@ -18,9 +18,9 @@ public class WhitelistEntry
|
|||||||
return anEntry;
|
return anEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCurrentDate() {
|
public static String getCurrentDate() {
|
||||||
return dateFormat.format(new Date());
|
return LocalDateTime.now().format(dateTimeFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLastUseDate() {
|
public String getLastUseDate() {
|
||||||
return lastUseDate;
|
return lastUseDate;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.dao;
|
|||||||
|
|
||||||
public class BackupFilename {
|
public class BackupFilename {
|
||||||
private String filename;
|
private String filename;
|
||||||
|
private String file;
|
||||||
|
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
return filename;
|
return filename;
|
||||||
@@ -10,4 +11,13 @@ public class BackupFilename {
|
|||||||
public void setFilename(String filename) {
|
public void setFilename(String filename) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFile(String file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ public class DeviceDescriptor{
|
|||||||
@SerializedName("onUrl")
|
@SerializedName("onUrl")
|
||||||
@Expose
|
@Expose
|
||||||
private String onUrl;
|
private String onUrl;
|
||||||
|
@SerializedName("colorUrl")
|
||||||
|
@Expose
|
||||||
|
private String colorUrl;
|
||||||
@SerializedName("headers")
|
@SerializedName("headers")
|
||||||
@Expose
|
@Expose
|
||||||
private String headers;
|
private String headers;
|
||||||
@@ -74,8 +77,21 @@ public class DeviceDescriptor{
|
|||||||
@SerializedName("comments")
|
@SerializedName("comments")
|
||||||
@Expose
|
@Expose
|
||||||
private String comments;
|
private String comments;
|
||||||
|
@SerializedName("deviceState")
|
||||||
|
@Expose
|
||||||
private DeviceState deviceState;
|
private DeviceState deviceState;
|
||||||
|
@SerializedName("onFirstDim")
|
||||||
|
@Expose
|
||||||
|
private boolean onFirstDim;
|
||||||
|
@SerializedName("onWhenDimPresent")
|
||||||
|
@Expose
|
||||||
|
private boolean onWhenDimPresent;
|
||||||
|
@SerializedName("lockDeviceId")
|
||||||
|
@Expose
|
||||||
|
private boolean lockDeviceId;
|
||||||
|
@SerializedName("startupActions")
|
||||||
|
@Expose
|
||||||
|
private String startupActions;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@@ -141,6 +157,14 @@ public class DeviceDescriptor{
|
|||||||
this.onUrl = onUrl;
|
this.onUrl = onUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getColorUrl() {
|
||||||
|
return colorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorUrl(String colorUrl) {
|
||||||
|
this.colorUrl = colorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -207,7 +231,7 @@ public class DeviceDescriptor{
|
|||||||
|
|
||||||
public DeviceState getDeviceState() {
|
public DeviceState getDeviceState() {
|
||||||
if(deviceState == null)
|
if(deviceState == null)
|
||||||
deviceState = DeviceState.createDeviceState();
|
deviceState = DeviceState.createDeviceState(this.isColorDevice());
|
||||||
return deviceState;
|
return deviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,6 +287,22 @@ public class DeviceDescriptor{
|
|||||||
this.comments = comments;
|
this.comments = comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOnFirstDim() {
|
||||||
|
return onFirstDim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnFirstDim(boolean onFirstDim) {
|
||||||
|
this.onFirstDim = onFirstDim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnWhenDimPresent() {
|
||||||
|
return onWhenDimPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnWhenDimPresent(boolean onWhenDimPresent) {
|
||||||
|
this.onWhenDimPresent = onWhenDimPresent;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean containsType(String aType) {
|
public boolean containsType(String aType) {
|
||||||
if(aType == null)
|
if(aType == null)
|
||||||
return false;
|
return false;
|
||||||
@@ -282,6 +322,37 @@ public class DeviceDescriptor{
|
|||||||
if(this.offUrl != null && this.offUrl.contains(aType))
|
if(this.offUrl != null && this.offUrl.contains(aType))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if(this.colorUrl != null && this.colorUrl.contains(aType))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isColorDevice() {
|
||||||
|
boolean color = true;
|
||||||
|
if ((deviceType == null || !deviceType.trim().equals("passthru")) && (colorUrl == null || colorUrl.trim().equals(""))) {
|
||||||
|
color = false;
|
||||||
|
} else if (deviceType != null && deviceType.trim().equals("passthru")) {
|
||||||
|
if (deviceState != null && (deviceState.getColormode() == null || deviceState.getColormode().equals(""))) {
|
||||||
|
color = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLockDeviceId() {
|
||||||
|
return lockDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockDeviceId(boolean lockDeviceId) {
|
||||||
|
this.lockDeviceId = lockDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStartupActions() {
|
||||||
|
return startupActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartupActions(String startupActions) {
|
||||||
|
this.startupActions = startupActions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.dao;
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -13,61 +11,74 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
|
import com.bwssystems.HABridge.plugins.hue.HueHome;
|
||||||
import com.bwssystems.HABridge.util.BackupHandler;
|
import com.bwssystems.HABridge.util.BackupHandler;
|
||||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
||||||
* loading.
|
* loading.
|
||||||
*/
|
*/
|
||||||
public class DeviceRepository extends BackupHandler {
|
public class DeviceRepository extends BackupHandler {
|
||||||
private Map<String, DeviceDescriptor> devices;
|
private Map<String, DeviceDescriptor> devices;
|
||||||
private Path repositoryPath;
|
private Path repositoryPath;
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private Integer nextId;
|
private Integer nextId;
|
||||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
private Integer seedId;
|
||||||
|
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||||
|
|
||||||
public DeviceRepository(String deviceDb) {
|
public DeviceRepository(String deviceDb, Integer seedid) {
|
||||||
super();
|
super();
|
||||||
gson =
|
gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
|
||||||
new GsonBuilder()
|
|
||||||
.excludeFieldsWithoutExposeAnnotation()
|
|
||||||
.create();
|
|
||||||
repositoryPath = null;
|
repositoryPath = null;
|
||||||
repositoryPath = Paths.get(deviceDb);
|
repositoryPath = Paths.get(deviceDb);
|
||||||
setupParams(repositoryPath, ".bk", "device.db-");
|
setupParams(repositoryPath, ".bk", "device.db-");
|
||||||
nextId = 0;
|
nextId = seedid;
|
||||||
|
seedId = seedid;
|
||||||
_loadRepository(repositoryPath);
|
_loadRepository(repositoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRepository() {
|
public void loadRepository() {
|
||||||
if(repositoryPath != null)
|
if (repositoryPath != null)
|
||||||
_loadRepository(repositoryPath);
|
_loadRepository(repositoryPath);
|
||||||
}
|
}
|
||||||
private void _loadRepository(Path aPath){
|
|
||||||
|
private void _loadRepository(Path aPath) {
|
||||||
String jsonContent = repositoryReader(aPath);
|
String jsonContent = repositoryReader(aPath);
|
||||||
devices = new HashMap<String, DeviceDescriptor>();
|
devices = new HashMap<String, DeviceDescriptor>();
|
||||||
|
|
||||||
if(jsonContent != null)
|
if (jsonContent != null) {
|
||||||
{
|
|
||||||
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
||||||
for(int i = 0; i < list.length; i++) {
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].getColorUrl() == null || list[i].getColorUrl().isEmpty())
|
||||||
|
list[i].setDeviceState(DeviceState.createDeviceState(false));
|
||||||
|
else
|
||||||
|
list[i].setDeviceState(DeviceState.createDeviceState(true));
|
||||||
put(list[i].getId(), list[i]);
|
put(list[i].getId(), list[i]);
|
||||||
if(Integer.decode(list[i].getId()) > nextId) {
|
if (Integer.decode(list[i].getId()) > nextId) {
|
||||||
nextId = Integer.decode(list[i].getId());
|
nextId = Integer.decode(list[i].getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextId = nextId + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DeviceDescriptor> findAll() {
|
public List<DeviceDescriptor> findAll() {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||||
@@ -76,8 +87,8 @@ public class DeviceRepository extends BackupHandler {
|
|||||||
|
|
||||||
public List<DeviceDescriptor> findActive() {
|
public List<DeviceDescriptor> findActive() {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>();
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>();
|
||||||
for(DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
|
for (DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
|
||||||
if(!aDevice.isInactive())
|
if (!aDevice.isInactive())
|
||||||
list.add(aDevice);
|
list.add(aDevice);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
@@ -85,17 +96,21 @@ public class DeviceRepository extends BackupHandler {
|
|||||||
|
|
||||||
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
|
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||||
|
return findAllByRequester(anAddress, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DeviceDescriptor> findAllByRequester(String anAddress, Collection<DeviceDescriptor> list) {
|
||||||
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
|
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
|
||||||
Iterator<DeviceDescriptor> anIterator = list.iterator();
|
Iterator<DeviceDescriptor> anIterator = list.iterator();
|
||||||
DeviceDescriptor theDevice;
|
DeviceDescriptor theDevice;
|
||||||
String theRequesterAddress;
|
String theRequesterAddress;
|
||||||
|
|
||||||
HashMap<String,String > addressMap;
|
HashMap<String, String> addressMap;
|
||||||
while (anIterator.hasNext()) {
|
while (anIterator.hasNext()) {
|
||||||
theDevice = anIterator.next();
|
theDevice = anIterator.next();
|
||||||
theRequesterAddress = theDevice.getRequesterAddress();
|
theRequesterAddress = theDevice.getRequesterAddress();
|
||||||
addressMap = new HashMap<String, String>();
|
addressMap = new HashMap<String, String>();
|
||||||
if(theRequesterAddress != null) {
|
if (theRequesterAddress != null) {
|
||||||
if (theRequesterAddress.contains(",")) {
|
if (theRequesterAddress.contains(",")) {
|
||||||
String[] theArray = theRequesterAddress.split(",");
|
String[] theArray = theRequesterAddress.split(",");
|
||||||
for (String v : theArray) {
|
for (String v : theArray) {
|
||||||
@@ -110,116 +125,199 @@ public class DeviceRepository extends BackupHandler {
|
|||||||
return theReturnList;
|
return theReturnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||||
|
HueHome myHueHome, Gson aGsonBuilder) {
|
||||||
|
return findAllByGroupWithState(lightsInGroup, anAddress, myHueHome, aGsonBuilder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||||
|
HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) {
|
||||||
|
Map<String, DeviceResponse> deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||||
|
Map<String, DeviceDescriptor> lights = new HashMap<String, DeviceDescriptor>(devices);
|
||||||
|
lights.keySet().retainAll(Arrays.asList(lightsInGroup));
|
||||||
|
for (DeviceDescriptor light : (ignoreAddress ? lights.values()
|
||||||
|
: findAllByRequester(anAddress, lights.values()))) {
|
||||||
|
DeviceResponse deviceResponse = null;
|
||||||
|
if (!light.isInactive()) {
|
||||||
|
if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||||
|
CallItem[] callItems = null;
|
||||||
|
try {
|
||||||
|
if (light.getOnUrl() != null)
|
||||||
|
callItems = aGsonBuilder.fromJson(light.getOnUrl(), CallItem[].class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
log.warn("Could not decode Json for url items to get Hue state for device: {}",
|
||||||
|
light.getName());
|
||||||
|
callItems = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||||
|
if ((callItems[i].getType() != null
|
||||||
|
&& callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]))
|
||||||
|
|| (callItems[i].getItem() != null && callItems[i].getItem().getAsString() != null
|
||||||
|
&& callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||||
|
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], light);
|
||||||
|
i = callItems.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceResponse == null) {
|
||||||
|
deviceResponse = DeviceResponse.createResponse(light);
|
||||||
|
}
|
||||||
|
deviceResponseMap.put(light.getId(), deviceResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (deviceResponseMap.size() == 0) ? null : deviceResponseMap;
|
||||||
|
}
|
||||||
|
|
||||||
public DeviceDescriptor findOne(String id) {
|
public DeviceDescriptor findOne(String id) {
|
||||||
return devices.get(id);
|
return devices.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void put(String id, DeviceDescriptor aDescriptor) {
|
private void put(String id, DeviceDescriptor aDescriptor) {
|
||||||
devices.put(id, aDescriptor);
|
devices.put(id, aDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(DeviceDescriptor[] descriptors) {
|
public void save(DeviceDescriptor[] descriptors) {
|
||||||
String theNames = "";
|
String theNames = "";
|
||||||
for(int i = 0; i < descriptors.length; i++) {
|
for (int i = 0; i < descriptors.length; i++) {
|
||||||
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
if (descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||||
devices.remove(descriptors[i].getId());
|
devices.remove(descriptors[i].getId());
|
||||||
else {
|
else {
|
||||||
nextId++;
|
descriptors[i].setId(String.valueOf(nextId));
|
||||||
descriptors[i].setId(String.valueOf(nextId));
|
nextId++;
|
||||||
}
|
}
|
||||||
if(descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
|
if (descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
|
||||||
BigInteger bigInt = BigInteger.valueOf(Integer.decode(descriptors[i].getId()));
|
descriptors[i].setUniqueid("00:11:22:33:44:55:66:" + hueUniqueId(Integer.valueOf(descriptors[i].getId())));
|
||||||
byte[] theBytes = bigInt.toByteArray();
|
}
|
||||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
put(descriptors[i].getId(), descriptors[i]);
|
||||||
|
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||||
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
|
||||||
}
|
|
||||||
put(descriptors[i].getId(), descriptors[i]);
|
|
||||||
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
|
||||||
}
|
}
|
||||||
String jsonValue = gson.toJson(findAll());
|
String jsonValue = gson.toJson(findAll());
|
||||||
repositoryWriter(jsonValue, repositoryPath);
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
log.debug("Save device(s): " + theNames);
|
log.debug("Save device(s): {}", theNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renumber() {
|
public void renumber() {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||||
Iterator<DeviceDescriptor> deviceIterator = list.iterator();
|
Iterator<DeviceDescriptor> deviceIterator = list.iterator();
|
||||||
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();;
|
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();
|
||||||
nextId = 0;
|
List<String> lockedIds = new ArrayList<String>();
|
||||||
log.debug("Renumber devices.");
|
DeviceDescriptor theDevice;
|
||||||
while(deviceIterator.hasNext()) {
|
boolean findNext = true;
|
||||||
nextId++;
|
|
||||||
DeviceDescriptor theDevice = deviceIterator.next();
|
|
||||||
theDevice.setId(String.valueOf(nextId));
|
|
||||||
BigInteger bigInt = BigInteger.valueOf(nextId);
|
|
||||||
byte[] theBytes = bigInt.toByteArray();
|
|
||||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
|
||||||
|
|
||||||
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
|
||||||
newdevices.put(theDevice.getId(), theDevice);
|
nextId = seedId;
|
||||||
|
while(deviceIterator.hasNext()) {
|
||||||
|
theDevice = deviceIterator.next();
|
||||||
|
if(theDevice.isLockDeviceId()) {
|
||||||
|
lockedIds.add(theDevice.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
devices = newdevices;
|
log.debug("Renumber devices starting with: {}", nextId);
|
||||||
String jsonValue = gson.toJson(findAll());
|
deviceIterator = list.iterator();
|
||||||
repositoryWriter(jsonValue, repositoryPath);
|
while (deviceIterator.hasNext()) {
|
||||||
}
|
theDevice = deviceIterator.next();
|
||||||
|
if (!theDevice.isLockDeviceId()) {
|
||||||
|
findNext = true;
|
||||||
|
while(findNext) {
|
||||||
|
if(lockedIds.contains(String.valueOf(nextId))) {
|
||||||
|
nextId++;
|
||||||
|
} else {
|
||||||
|
findNext = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theDevice.setId(String.valueOf(nextId));
|
||||||
|
theDevice.setUniqueid("00:11:22:33:44:55:66:" + hueUniqueId(nextId));
|
||||||
|
nextId++;
|
||||||
|
}
|
||||||
|
newdevices.put(theDevice.getId(), theDevice);
|
||||||
|
}
|
||||||
|
devices = newdevices;
|
||||||
|
String jsonValue = gson.toJson(findAll());
|
||||||
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
public String delete(DeviceDescriptor aDescriptor) {
|
public String delete(DeviceDescriptor aDescriptor) {
|
||||||
if (aDescriptor != null) {
|
if (aDescriptor != null) {
|
||||||
devices.remove(aDescriptor.getId());
|
devices.remove(aDescriptor.getId());
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
String jsonValue = aRenderer.render(findAll());
|
String jsonValue = aRenderer.render(findAll());
|
||||||
repositoryWriter(jsonValue, repositoryPath);
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
return "Device with id '" + aDescriptor.getId() + "' deleted";
|
return "Device with id '" + aDescriptor.getId() + "' deleted";
|
||||||
} else {
|
} else {
|
||||||
return "Device not found";
|
return "Device not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void repositoryWriter(String content, Path filePath) {
|
private void repositoryWriter(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);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Files.notExists(filePath.getParent())) {
|
if (Files.notExists(filePath.getParent())) {
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(filePath.getParent());
|
Files.createDirectories(filePath.getParent());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error creating the directory: " + filePath + " message: " + e.getMessage(), e);
|
log.error("Error creating the directory: {} message: {}", filePath, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path target = null;
|
Path target = null;
|
||||||
if(Files.exists(filePath)) {
|
if (Files.exists(filePath)) {
|
||||||
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
|
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
|
||||||
Files.move(filePath, target);
|
Files.move(filePath, target);
|
||||||
}
|
}
|
||||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
if(target != null)
|
if (target != null)
|
||||||
Files.delete(target);
|
Files.delete(target);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
log.error("Error writing the file: {} message: {}", filePath, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String repositoryReader(Path filePath) {
|
private String repositoryReader(Path filePath) {
|
||||||
|
|
||||||
String content = null;
|
String content = null;
|
||||||
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
if (Files.notExists(filePath) || !Files.isReadable(filePath)) {
|
||||||
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
|
log.warn("Error reading the file: {} - Does not exist or is not readable. continuing...", filePath);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
content = new String(Files.readAllBytes(filePath));
|
content = new String(Files.readAllBytes(filePath));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
log.error("Error reading the file: {} message: {}", filePath, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String hueUniqueId(Integer anId) {
|
||||||
|
String theUniqueId;
|
||||||
|
Integer newValue;
|
||||||
|
String hexValueLeft;
|
||||||
|
String hexValueRight;
|
||||||
|
|
||||||
|
newValue = anId % 256;
|
||||||
|
if (newValue <= 0)
|
||||||
|
newValue = 1;
|
||||||
|
else if (newValue > 255)
|
||||||
|
newValue = 255;
|
||||||
|
hexValueLeft = HexLibrary.byteToHex(newValue.byteValue());
|
||||||
|
newValue = anId / 256;
|
||||||
|
newValue = newValue % 256;
|
||||||
|
if (newValue < 0)
|
||||||
|
newValue = 0;
|
||||||
|
else if (newValue > 255)
|
||||||
|
newValue = 255;
|
||||||
|
hexValueRight = HexLibrary.byteToHex(newValue.byteValue());
|
||||||
|
|
||||||
|
theUniqueId = String.format("%s-%s", hexValueLeft, hexValueRight).toUpperCase();
|
||||||
|
|
||||||
|
return theUniqueId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
147
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
147
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import com.bwssystems.HABridge.api.hue.GroupState;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Object to handle the device configuration
|
||||||
|
*/
|
||||||
|
public class GroupDescriptor{
|
||||||
|
@SerializedName("id")
|
||||||
|
@Expose
|
||||||
|
private String id;
|
||||||
|
@SerializedName("name")
|
||||||
|
@Expose
|
||||||
|
private String name;
|
||||||
|
@SerializedName("groupType")
|
||||||
|
@Expose
|
||||||
|
private String groupType;
|
||||||
|
@SerializedName("groupClass")
|
||||||
|
@Expose
|
||||||
|
private String groupClass;
|
||||||
|
@SerializedName("requesterAddress")
|
||||||
|
@Expose
|
||||||
|
private String requesterAddress;
|
||||||
|
@SerializedName("inactive")
|
||||||
|
@Expose
|
||||||
|
private boolean inactive;
|
||||||
|
@SerializedName("description")
|
||||||
|
@Expose
|
||||||
|
private String description;
|
||||||
|
@SerializedName("comments")
|
||||||
|
@Expose
|
||||||
|
private String comments;
|
||||||
|
|
||||||
|
private DeviceState action;
|
||||||
|
private GroupState groupState;
|
||||||
|
|
||||||
|
@SerializedName("lights")
|
||||||
|
@Expose
|
||||||
|
private String[] lights;
|
||||||
|
@SerializedName("exposeAsLight")
|
||||||
|
@Expose
|
||||||
|
private String exposeAsLight;
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupType() {
|
||||||
|
return groupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupType(String groupType) {
|
||||||
|
this.groupType = groupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupClass() {
|
||||||
|
return groupClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupClass(String groupClass) {
|
||||||
|
this.groupClass = groupClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupState getGroupState() {
|
||||||
|
if(groupState == null)
|
||||||
|
groupState = new GroupState(false,false);
|
||||||
|
return groupState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupState(GroupState groupState) {
|
||||||
|
this.groupState = groupState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceState getAction() {
|
||||||
|
if(action == null)
|
||||||
|
action = DeviceState.createDeviceState(true);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(DeviceState action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInactive() {
|
||||||
|
return inactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInactive(boolean inactive) {
|
||||||
|
this.inactive = inactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 String[] getLights() {
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLights(String[] lights) {
|
||||||
|
this.lights = lights;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExposeAsLight(String exposeFor) {
|
||||||
|
this.exposeAsLight = exposeFor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExposeAsLight() {
|
||||||
|
return exposeAsLight;
|
||||||
|
}
|
||||||
|
}
|
||||||
224
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
224
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||||
|
import com.bwssystems.HABridge.util.BackupHandler;
|
||||||
|
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
/*
|
||||||
|
* This is an in memory list to manage the configured groups and saves the list as a JSON string to a file for later
|
||||||
|
* loading.
|
||||||
|
*/
|
||||||
|
public class GroupRepository extends BackupHandler {
|
||||||
|
private Map<String, GroupDescriptor> groups;
|
||||||
|
private Path repositoryPath;
|
||||||
|
private Gson gson;
|
||||||
|
private Integer nextId;
|
||||||
|
private Logger log = LoggerFactory.getLogger(GroupRepository.class);
|
||||||
|
|
||||||
|
public GroupRepository(String groupDb) {
|
||||||
|
super();
|
||||||
|
gson =
|
||||||
|
new GsonBuilder()
|
||||||
|
.excludeFieldsWithoutExposeAnnotation()
|
||||||
|
.create();
|
||||||
|
nextId = 0;
|
||||||
|
try {
|
||||||
|
repositoryPath = null;
|
||||||
|
repositoryPath = Paths.get(groupDb);
|
||||||
|
setupParams(repositoryPath, ".bk", "group.db-");
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
groups = new HashMap<String, GroupDescriptor>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadRepository() {
|
||||||
|
if(repositoryPath != null)
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
}
|
||||||
|
private void _loadRepository(Path aPath){
|
||||||
|
String jsonContent = repositoryReader(aPath);
|
||||||
|
groups = new HashMap<String, GroupDescriptor>();
|
||||||
|
|
||||||
|
if(jsonContent != null)
|
||||||
|
{
|
||||||
|
GroupDescriptor list[] = gson.fromJson(jsonContent, GroupDescriptor[].class);
|
||||||
|
for(int i = 0; i < list.length; i++) {
|
||||||
|
list[i].setGroupState(null);
|
||||||
|
put(list[i].getId(), list[i]);
|
||||||
|
if(Integer.decode(list[i].getId()) > nextId) {
|
||||||
|
nextId = Integer.decode(list[i].getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GroupDescriptor> findAll() {
|
||||||
|
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GroupDescriptor> findActive() {
|
||||||
|
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
|
||||||
|
for(GroupDescriptor aGroup : new ArrayList<GroupDescriptor>(groups.values())) {
|
||||||
|
if(!aGroup.isInactive())
|
||||||
|
list.add(aGroup);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GroupDescriptor> findAllByRequester(String anAddress) {
|
||||||
|
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
|
||||||
|
List<GroupDescriptor> theReturnList = new ArrayList<GroupDescriptor>();
|
||||||
|
Iterator<GroupDescriptor> anIterator = list.iterator();
|
||||||
|
GroupDescriptor theGroup;
|
||||||
|
String theRequesterAddress;
|
||||||
|
|
||||||
|
HashMap<String,String > addressMap;
|
||||||
|
while (anIterator.hasNext()) {
|
||||||
|
theGroup = anIterator.next();
|
||||||
|
theRequesterAddress = theGroup.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(theGroup);
|
||||||
|
}
|
||||||
|
return theReturnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GroupDescriptor> findVirtualLights(String anAddress) {
|
||||||
|
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
|
||||||
|
for (GroupDescriptor group : groups.values()) {
|
||||||
|
String expose = group.getExposeAsLight();
|
||||||
|
if (expose != null && expose.contains(anAddress)) {
|
||||||
|
list.add(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupDescriptor findOne(String id) {
|
||||||
|
return groups.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void put(String id, GroupDescriptor aDescriptor) {
|
||||||
|
groups.put(id, aDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
save(groups.values().toArray(new GroupDescriptor[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(GroupDescriptor[] descriptors) {
|
||||||
|
String theNames = "";
|
||||||
|
for(int i = 0; i < descriptors.length; i++) {
|
||||||
|
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||||
|
groups.remove(descriptors[i].getId());
|
||||||
|
else {
|
||||||
|
nextId++;
|
||||||
|
descriptors[i].setId(String.valueOf(nextId));
|
||||||
|
}
|
||||||
|
|
||||||
|
put(descriptors[i].getId(), descriptors[i]);
|
||||||
|
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||||
|
}
|
||||||
|
String jsonValue = gson.toJson(findAll());
|
||||||
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
|
log.debug("Save group(s): " + theNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNewId() {
|
||||||
|
return nextId + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String delete(GroupDescriptor aDescriptor) {
|
||||||
|
if (aDescriptor != null) {
|
||||||
|
groups.remove(aDescriptor.getId());
|
||||||
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
|
String jsonValue = aRenderer.render(findAll());
|
||||||
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
|
return "Group with id '" + aDescriptor.getId() + "' deleted";
|
||||||
|
} else {
|
||||||
|
return "Group not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repositoryWriter(String content, Path filePath) {
|
||||||
|
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||||
|
log.error("Error file is not writable: " + filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Files.notExists(filePath.getParent())) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(filePath.getParent());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error creating the directory: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path target = null;
|
||||||
|
if(Files.exists(filePath)) {
|
||||||
|
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "group.db.old");
|
||||||
|
Files.move(filePath, target);
|
||||||
|
}
|
||||||
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
|
if(target != null)
|
||||||
|
Files.delete(target);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String repositoryReader(Path filePath) {
|
||||||
|
|
||||||
|
String content = null;
|
||||||
|
if(Files.notExists(filePath)){
|
||||||
|
log.debug("Error, the file: " + filePath + " - does not exist. continuing...");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Files.isReadable(filePath)){
|
||||||
|
log.warn("Error, the file: " + filePath + " - is not readable. continuing...");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
content = new String(Files.readAllBytes(filePath));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.bwssystems.HABridge.devicemanagmeent;
|
package com.bwssystems.HABridge.devicemanagmeent;
|
||||||
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
|
import static spark.Spark.halt;
|
||||||
import static spark.Spark.options;
|
import static spark.Spark.options;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
|
import static spark.Spark.before;
|
||||||
import static spark.Spark.delete;
|
import static spark.Spark.delete;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -15,13 +17,15 @@ import org.apache.http.HttpStatus;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
import com.bwssystems.HABridge.HomeManager;
|
import com.bwssystems.HABridge.HomeManager;
|
||||||
|
import com.bwssystems.HABridge.User;
|
||||||
import com.bwssystems.HABridge.api.CallItem;
|
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.GroupRepository;
|
||||||
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;
|
||||||
@@ -35,14 +39,20 @@ public class DeviceResource {
|
|||||||
private static final String API_CONTEXT = "/api/devices";
|
private static final String API_CONTEXT = "/api/devices";
|
||||||
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 GroupRepository groupRepository;
|
||||||
private HomeManager homeManager;
|
private HomeManager homeManager;
|
||||||
|
private BridgeSettings bridgeSettings;
|
||||||
private Gson aGsonHandler;
|
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"));
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
|
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
|
||||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
bridgeSettings = theSettings;
|
||||||
|
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb(), bridgeSettings.getBridgeSettingsDescriptor().getSeedid());
|
||||||
|
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
|
||||||
homeManager = aHomeManager;
|
homeManager = aHomeManager;
|
||||||
aGsonHandler = new GsonBuilder().create();
|
aGsonHandler = new GsonBuilder().create();
|
||||||
|
errorMessage = null;
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +60,21 @@ public class DeviceResource {
|
|||||||
return deviceRepository;
|
return deviceRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GroupRepository getGroupRepository() {
|
||||||
|
return groupRepository;
|
||||||
|
}
|
||||||
|
|
||||||
private void setupEndpoints() {
|
private void setupEndpoints() {
|
||||||
log.info("HABridge device management service started.... ");
|
log.info("HABridge device management service started.... ");
|
||||||
|
before(API_CONTEXT + "/*", (request, response) -> {
|
||||||
|
// This never gets called as the HueMulator class covers this path. This is here for backup
|
||||||
|
if(bridgeSettings.getBridgeSecurity().isSecure()) {
|
||||||
|
User authUser = bridgeSettings.getBridgeSecurity().getAuthenticatedUser(request);
|
||||||
|
if(authUser == null) {
|
||||||
|
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
// http://ip_address:port/api/devices CORS request
|
// http://ip_address:port/api/devices CORS request
|
||||||
options(API_CONTEXT, "application/json", (request, response) -> {
|
options(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -62,7 +85,7 @@ public class DeviceResource {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
post(API_CONTEXT, "application/json", (request, response) -> {
|
post(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
log.debug("Create a Device(s) - request body: " + request.body());
|
log.debug("Create a Device(s) - request body: {}", request.body());
|
||||||
DeviceDescriptor devices[];
|
DeviceDescriptor devices[];
|
||||||
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
|
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
|
||||||
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
|
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
|
||||||
@@ -70,14 +93,14 @@ public class DeviceResource {
|
|||||||
else {
|
else {
|
||||||
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("unused")
|
||||||
CallItem[] callItems = null;
|
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);
|
||||||
errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
|
errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
|
||||||
log.debug(errorMessage);
|
log.warn(errorMessage);
|
||||||
return new ErrorMessage(errorMessage);
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +110,7 @@ public class DeviceResource {
|
|||||||
} catch(JsonSyntaxException e) {
|
} catch(JsonSyntaxException e) {
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
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();
|
errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
|
||||||
log.debug(errorMessage);
|
log.warn(errorMessage);
|
||||||
return new ErrorMessage(errorMessage);
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -96,7 +119,7 @@ public class DeviceResource {
|
|||||||
} catch(JsonSyntaxException e) {
|
} catch(JsonSyntaxException e) {
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
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();
|
errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
|
||||||
log.debug(errorMessage);
|
log.warn(errorMessage);
|
||||||
return new ErrorMessage(errorMessage);
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -105,13 +128,22 @@ public class DeviceResource {
|
|||||||
} catch(JsonSyntaxException e) {
|
} catch(JsonSyntaxException e) {
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
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();
|
errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
|
||||||
log.debug(errorMessage);
|
log.warn(errorMessage);
|
||||||
|
return new ErrorMessage(errorMessage);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(devices[i].getColorUrl() != null && !devices[i].getColorUrl().isEmpty())
|
||||||
|
callItems = aGsonHandler.fromJson(devices[i].getColorUrl(), CallItem[].class);
|
||||||
|
} catch(JsonSyntaxException e) {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
|
errorMessage = "Bad color URL JSON in create device(s) for name: " + devices[i].getName() + " with color URL: " + devices[i].getColorUrl();
|
||||||
|
log.warn(errorMessage);
|
||||||
return new ErrorMessage(errorMessage);
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceRepository.save(devices);
|
deviceRepository.save(devices);
|
||||||
log.debug("Created a Device(s): " + request.body());
|
log.debug("Created a Device(s): {}", request.body());
|
||||||
|
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
response.status(HttpStatus.SC_CREATED);
|
response.status(HttpStatus.SC_CREATED);
|
||||||
@@ -129,16 +161,17 @@ public class DeviceResource {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Edit a Device - request body: " + request.body());
|
log.debug("Edit a Device - request body: {}", request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
if(deviceRepository.findOne(request.params(":id")) == null){
|
if(deviceRepository.findOne(request.params(":id")) == null){
|
||||||
log.debug("Could not save an edited device, Device Id not found: " + request.params(":id"));
|
errorMessage = "Could not save an edited device, Device Id not found: " + request.params(":id");
|
||||||
|
log.warn(errorMessage);
|
||||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.debug("Saving an edited Device: " + device.getName());
|
log.debug("Saving an edited Device: {}", device.getName());
|
||||||
|
|
||||||
if (device.getDeviceType() != null)
|
if (device.getDeviceType() != null)
|
||||||
device.setDeviceType(device.getDeviceType());
|
device.setDeviceType(device.getDeviceType());
|
||||||
@@ -156,17 +189,19 @@ public class DeviceResource {
|
|||||||
log.debug("Get all devices");
|
log.debug("Get all devices");
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
String theStream = aRenderer.render(deviceList);
|
String theStream = aRenderer.render(deviceList);
|
||||||
log.debug("The Device List: " + theStream);
|
log.debug("The Device List: {}", theStream);
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return deviceList;
|
return deviceList;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Get a device");
|
log.debug("Get a device: {}", request.params(":id"));
|
||||||
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
||||||
if(descriptor == null) {
|
if(descriptor == null) {
|
||||||
|
errorMessage = "Could not find, id: " + request.params(":id");
|
||||||
|
log.warn(errorMessage);
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return new ErrorMessage("Could not find, id: " + request.params(":id") + " ");
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -175,11 +210,13 @@ public class DeviceResource {
|
|||||||
|
|
||||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
String anId = request.params(":id");
|
String anId = request.params(":id");
|
||||||
log.debug("Delete a device: " + anId);
|
log.debug("Delete a device: {}", anId);
|
||||||
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
||||||
if(deleted == null) {
|
if(deleted == null) {
|
||||||
|
errorMessage = "Could not delete, id: " + anId + " not found. ";
|
||||||
|
log.warn(errorMessage);
|
||||||
response.status(HttpStatus.SC_NOT_FOUND);
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return new ErrorMessage("Could not delete, id: " + anId + " not found. ");
|
return new ErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -201,6 +238,18 @@ public class DeviceResource {
|
|||||||
return homeManager.findResource(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex]);
|
return homeManager.findResource(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex]);
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/fibaro/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get fibaro devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/fibaro/scenes", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get fibaro scenes");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||||
log.debug("Get harmony activities");
|
log.debug("Get harmony activities");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -248,6 +297,12 @@ public class DeviceResource {
|
|||||||
return homeManager.findResource(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]);
|
return homeManager.findResource(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/homewizard/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get HomeWizard Clients");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/domoticz/devices", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/domoticz/devices", "application/json", (request, response) -> {
|
||||||
log.debug("Get Domoticz Clients");
|
log.debug("Get Domoticz Clients");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -266,11 +321,49 @@ public class DeviceResource {
|
|||||||
return homeManager.findResource(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]);
|
return homeManager.findResource(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/openhab/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get OpenHAB devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/fhem/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get FHEM devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/broadlink/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get Broadlink devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/moziot/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get Mozilla IOT devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.MOZIOT_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.MOZIOT_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/homegenie/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get HomeGenie devices");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return homeManager.findResource(DeviceMapTypes.HOMEGENIE_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HOMEGENIE_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();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/refresh/:typeIndex", "application/json", (request, response) -> {
|
||||||
|
String typeIndex = request.params(":typeIndex");
|
||||||
|
log.debug("Refresh Home: {}", typeIndex);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
homeManager.findResource(typeIndex).refresh();
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api/devices/exec/renumber CORS request
|
// http://ip_address:port/api/devices/exec/renumber CORS request
|
||||||
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -287,11 +380,46 @@ public class DeviceResource {
|
|||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||||
log.debug("Get backup filenames");
|
log.debug("Get backup filenames.");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
return deviceRepository.getBackups();
|
return deviceRepository.getBackups();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/download CORS request
|
||||||
|
options(API_CONTEXT + "/backup/download", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (API_CONTEXT + "/backup/download", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create download: {}", request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
String backupContent = deviceRepository.downloadBackup(aFilename.getFilename());
|
||||||
|
return backupContent;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/upload CORS request
|
||||||
|
options(API_CONTEXT + "/backup/upload/:filename", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (API_CONTEXT + "/backup/upload/:filename", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create upload: {} - {}", request.params(":filename"), request.body());
|
||||||
|
String theSuccess = deviceRepository.uploadBackup(request.params(":filename"), request.body());
|
||||||
|
if(theSuccess.contains("Error:"))
|
||||||
|
response.status(HttpStatus.SC_METHOD_FAILURE);
|
||||||
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return theSuccess;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
// http://ip_address:port/api/devices/backup/create CORS request
|
// http://ip_address:port/api/devices/backup/create CORS request
|
||||||
options(API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
options(API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
@@ -302,7 +430,7 @@ public class DeviceResource {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
put (API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
put (API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
log.debug("Create backup: " + request.body());
|
log.debug("Create backup: {}", request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
BackupFilename returnFilename = new BackupFilename();
|
BackupFilename returnFilename = new BackupFilename();
|
||||||
returnFilename.setFilename(deviceRepository.backup(aFilename.getFilename()));
|
returnFilename.setFilename(deviceRepository.backup(aFilename.getFilename()));
|
||||||
@@ -319,7 +447,7 @@ public class DeviceResource {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
post (API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
post (API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
log.debug("Delete backup: " + request.body());
|
log.debug("Delete backup: {}", request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
if(aFilename != null)
|
if(aFilename != null)
|
||||||
deviceRepository.deleteBackup(aFilename.getFilename());
|
deviceRepository.deleteBackup(aFilename.getFilename());
|
||||||
@@ -338,7 +466,7 @@ public class DeviceResource {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
log.debug("Restore backup: " + request.body());
|
log.debug("Restore backup: {}", request.body());
|
||||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
if(aFilename != null) {
|
if(aFilename != null) {
|
||||||
deviceRepository.restoreBackup(aFilename.getFilename());
|
deviceRepository.restoreBackup(aFilename.getFilename());
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ package com.bwssystems.HABridge.devicemanagmeent;
|
|||||||
|
|
||||||
public interface ResourceHandler {
|
public interface ResourceHandler {
|
||||||
public Object getItems(String type);
|
public Object getItems(String type);
|
||||||
|
public void refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.hue;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Conversion;
|
import org.apache.commons.lang3.Conversion;
|
||||||
@@ -25,7 +26,7 @@ public class BrightnessDecode {
|
|||||||
if (targetBri != null) {
|
if (targetBri != null) {
|
||||||
setIntensity = targetBri;
|
setIntensity = targetBri;
|
||||||
} else if (targetBriInc != null) {
|
} else if (targetBriInc != null) {
|
||||||
if ((setIntensity + targetBriInc) <= 0)
|
if ((setIntensity + targetBriInc) <= 1)
|
||||||
setIntensity = targetBriInc;
|
setIntensity = targetBriInc;
|
||||||
else if ((setIntensity + targetBriInc) > 254)
|
else if ((setIntensity + targetBriInc) > 254)
|
||||||
setIntensity = targetBriInc;
|
setIntensity = targetBriInc;
|
||||||
@@ -51,11 +52,22 @@ public class BrightnessDecode {
|
|||||||
boolean notDone = true;
|
boolean notDone = true;
|
||||||
String replaceValue = null;
|
String replaceValue = null;
|
||||||
String replaceTarget = null;
|
String replaceTarget = null;
|
||||||
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
|
int percentBrightness = 0;
|
||||||
float decimalBrightness = (float) (intensity / 255.0);
|
float decimalBrightness = (float) 1.0;
|
||||||
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
||||||
String mathDescriptor = null;
|
String mathDescriptor = null;
|
||||||
|
|
||||||
|
if(intensity > 0) {
|
||||||
|
decimalBrightness = (float) (intensity / 255.0);
|
||||||
|
if(intensity > 0 && intensity < 5)
|
||||||
|
percentBrightness = 1;
|
||||||
|
else
|
||||||
|
percentBrightness = (int) Math.round(intensity / 255.0 * 100);
|
||||||
|
} else {
|
||||||
|
decimalBrightness = (float) 1.0;
|
||||||
|
percentBrightness = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while(notDone) {
|
while(notDone) {
|
||||||
notDone = false;
|
notDone = false;
|
||||||
if (request.contains(INTENSITY_BYTE)) {
|
if (request.contains(INTENSITY_BYTE)) {
|
||||||
@@ -83,7 +95,7 @@ public class BrightnessDecode {
|
|||||||
replaceTarget = INTENSITY_PERCENT_HEX;
|
replaceTarget = INTENSITY_PERCENT_HEX;
|
||||||
notDone = true;
|
notDone = true;
|
||||||
} else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
|
} else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
|
||||||
replaceValue = String.format("%1.2f", decimalBrightness);
|
replaceValue = String.format(Locale.ROOT, "%1.2f", decimalBrightness);
|
||||||
replaceTarget = INTENSITY_DECIMAL_PERCENT;
|
replaceTarget = INTENSITY_DECIMAL_PERCENT;
|
||||||
notDone = true;
|
notDone = true;
|
||||||
} else if (request.contains(INTENSITY_MATH_CLOSE)) {
|
} else if (request.contains(INTENSITY_MATH_CLOSE)) {
|
||||||
@@ -110,11 +122,7 @@ public class BrightnessDecode {
|
|||||||
|
|
||||||
Integer endResult = calculateMath(variables, mathDescriptor);
|
Integer endResult = calculateMath(variables, mathDescriptor);
|
||||||
if(endResult != null) {
|
if(endResult != null) {
|
||||||
if (isHex) {
|
replaceValue = convertToHex(endResult);
|
||||||
replaceValue = convertToHex(endResult);
|
|
||||||
} else {
|
|
||||||
replaceValue = endResult.toString();
|
|
||||||
}
|
|
||||||
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE_HEX;
|
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE_HEX;
|
||||||
notDone = true;
|
notDone = true;
|
||||||
}
|
}
|
||||||
|
|||||||
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
@@ -0,0 +1,963 @@
|
|||||||
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert between different color spaces supported.
|
||||||
|
* RGB -> CMYK -> RGB
|
||||||
|
* RGB -> YIQ -> RGB
|
||||||
|
* RGB -> YCbCr -> RGB
|
||||||
|
* RGB -> YUV -> RGB
|
||||||
|
* RGB -> RGChromaticity
|
||||||
|
* RGB -> HSV -> RGB
|
||||||
|
* RGB -> YCC -> RGB
|
||||||
|
* RGB -> YCoCg -> RGB
|
||||||
|
* RGB -> XYZ -> RGB
|
||||||
|
* RGB -> HunterLAB -> RGB
|
||||||
|
* RGB -> HLS -> RGB
|
||||||
|
* RGB -> CIE-LAB -> RGB
|
||||||
|
* XYZ -> HunterLAB -> XYZ
|
||||||
|
* XYZ -> CIE-LAB -> XYZ
|
||||||
|
* @author Diego Catalano
|
||||||
|
*/
|
||||||
|
public class ColorConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't let anyone instantiate this class.
|
||||||
|
*/
|
||||||
|
private ColorConverter() {}
|
||||||
|
|
||||||
|
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
|
||||||
|
|
||||||
|
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
|
||||||
|
|
||||||
|
//2o Observer (CIE 1931)
|
||||||
|
// X2, Y2, Z2
|
||||||
|
public static float[] CIE2_A = {109.850f, 100f, 35.585f}; //Incandescent
|
||||||
|
public static float[] CIE2_C = {98.074f, 100f, 118.232f};
|
||||||
|
public static float[] CIE2_D50 = {96.422f, 100f, 82.521f};
|
||||||
|
public static float[] CIE2_D55 = {95.682f, 100f, 92.149f};
|
||||||
|
public static float[] CIE2_D65 = {95.047f, 100f, 108.883f}; //Daylight
|
||||||
|
public static float[] CIE2_D75 = {94.972f, 100f, 122.638f};
|
||||||
|
public static float[] CIE2_F2 = {99.187f, 100f, 67.395f}; //Fluorescent
|
||||||
|
public static float[] CIE2_F7 = {95.044f, 100f, 108.755f};
|
||||||
|
public static float[] CIE2_F11 = {100.966f, 100f, 64.370f};
|
||||||
|
|
||||||
|
//10o Observer (CIE 1964)
|
||||||
|
// X2, Y2, Z2
|
||||||
|
public static float[] CIE10_A = {111.144f, 100f, 35.200f}; //Incandescent
|
||||||
|
public static float[] CIE10_C = {97.285f, 100f, 116.145f};
|
||||||
|
public static float[] CIE10_D50 = {96.720f, 100f, 81.427f};
|
||||||
|
public static float[] CIE10_D55 = {95.799f, 100f, 90.926f};
|
||||||
|
public static float[] CIE10_D65 = {94.811f, 100f, 107.304f}; //Daylight
|
||||||
|
public static float[] CIE10_D75 = {94.416f, 100f, 120.641f};
|
||||||
|
public static float[] CIE10_F2 = {103.280f, 100f, 69.026f}; //Fluorescent
|
||||||
|
public static float[] CIE10_F7 = {95.792f, 100f, 107.687f};
|
||||||
|
public static float[] CIE10_F11 = {103.866f, 100f, 65.627f};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFB -> CMYK
|
||||||
|
* @param red Values in the range [0..255].
|
||||||
|
* @param green Values in the range [0..255].
|
||||||
|
* @param blue Values in the range [0..255].
|
||||||
|
* @return CMYK color space. Normalized.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoCMYK(int red, int green, int blue){
|
||||||
|
float[] cmyk = new float[4];
|
||||||
|
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
float k = 1.0f - Math.max(r, Math.max(g, b));
|
||||||
|
float c = (1f-r-k) / (1f-k);
|
||||||
|
float m = (1f-g-k) / (1f-k);
|
||||||
|
float y = (1f-b-k) / (1f-k);
|
||||||
|
|
||||||
|
cmyk[0] = c;
|
||||||
|
cmyk[1] = m;
|
||||||
|
cmyk[2] = y;
|
||||||
|
cmyk[3] = k;
|
||||||
|
|
||||||
|
return cmyk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CMYK -> RGB
|
||||||
|
* @param c Cyan.
|
||||||
|
* @param m Magenta.
|
||||||
|
* @param y Yellow.
|
||||||
|
* @param k Black.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] CMYKtoRGB(float c, float m, float y, float k){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
|
||||||
|
rgb[0] = (int)(255 * (1-c) * (1-k));
|
||||||
|
rgb[1] = (int)(255 * (1-m) * (1-k));
|
||||||
|
rgb[2] = (int)(255 * (1-y) * (1-k));
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> YUV.
|
||||||
|
* Y in the range [0..1].
|
||||||
|
* U in the range [-0.5..0.5].
|
||||||
|
* V in the range [-0.5..0.5].
|
||||||
|
* @param red Values in the range [0..255].
|
||||||
|
* @param green Values in the range [0..255].
|
||||||
|
* @param blue Values in the range [0..255].
|
||||||
|
* @return YUV color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoYUV(int red, int green, int blue){
|
||||||
|
|
||||||
|
float r = (float)red / 255;
|
||||||
|
float g = (float)green / 255;
|
||||||
|
float b = (float)blue / 255;
|
||||||
|
|
||||||
|
float[] yuv = new float[3];
|
||||||
|
float y,u,v;
|
||||||
|
|
||||||
|
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||||
|
u = (float)(-0.14713 * r - 0.28886 * g + 0.436 * b);
|
||||||
|
v = (float)(0.615 * r - 0.51499 * g - 0.10001 * b);
|
||||||
|
|
||||||
|
yuv[0] = y;
|
||||||
|
yuv[1] = u;
|
||||||
|
yuv[2] = v;
|
||||||
|
|
||||||
|
return yuv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YUV -> RGB.
|
||||||
|
* @param y Luma. In the range [0..1].
|
||||||
|
* @param u Chrominance. In the range [-0.5..0.5].
|
||||||
|
* @param v Chrominance. In the range [-0.5..0.5].
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] YUVtoRGB(float y, float u, float v){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
float r,g,b;
|
||||||
|
|
||||||
|
r = (float)((y + 0.000 * u + 1.140 * v) * 255);
|
||||||
|
g = (float)((y - 0.396 * u - 0.581 * v) * 255);
|
||||||
|
b = (float)((y + 2.029 * u + 0.000 * v) * 255);
|
||||||
|
|
||||||
|
rgb[0] = (int)r;
|
||||||
|
rgb[1] = (int)g;
|
||||||
|
rgb[2] = (int)b;
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> YIQ.
|
||||||
|
* @param red Values in the range [0..255].
|
||||||
|
* @param green Values in the range [0..255].
|
||||||
|
* @param blue Values in the range [0..255].
|
||||||
|
* @return YIQ color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoYIQ(int red, int green, int blue){
|
||||||
|
float[] yiq = new float[3];
|
||||||
|
float y,i,q;
|
||||||
|
|
||||||
|
float r = (float)red / 255;
|
||||||
|
float g = (float)green / 255;
|
||||||
|
float b = (float)blue / 255;
|
||||||
|
|
||||||
|
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||||
|
i = (float)(0.596 * r - 0.275 * g - 0.322 * b);
|
||||||
|
q = (float)(0.212 * r - 0.523 * g + 0.311 * b);
|
||||||
|
|
||||||
|
yiq[0] = y;
|
||||||
|
yiq[1] = i;
|
||||||
|
yiq[2] = q;
|
||||||
|
|
||||||
|
return yiq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YIQ -> RGB.
|
||||||
|
* @param y Luma. Values in the range [0..1].
|
||||||
|
* @param i In-phase. Values in the range [-0.5..0.5].
|
||||||
|
* @param q Quadrature. Values in the range [-0.5..0.5].
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] YIQtoRGB(double y, double i, double q){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
int r,g,b;
|
||||||
|
|
||||||
|
r = (int)((y + 0.956 * i + 0.621 * q) * 255);
|
||||||
|
g = (int)((y - 0.272 * i - 0.647 * q) * 255);
|
||||||
|
b = (int)((y - 1.105 * i + 1.702 * q) * 255);
|
||||||
|
|
||||||
|
r = Math.max(0,Math.min(255,r));
|
||||||
|
g = Math.max(0,Math.min(255,g));
|
||||||
|
b = Math.max(0,Math.min(255,b));
|
||||||
|
|
||||||
|
rgb[0] = r;
|
||||||
|
rgb[1] = g;
|
||||||
|
rgb[2] = b;
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float[] RGBtoYCbCr(int red, int green, int blue, YCbCrColorSpace colorSpace){
|
||||||
|
|
||||||
|
float r = (float)red / 255;
|
||||||
|
float g = (float)green / 255;
|
||||||
|
float b = (float)blue / 255;
|
||||||
|
|
||||||
|
float[] YCbCr = new float[3];
|
||||||
|
float y,cb,cr;
|
||||||
|
|
||||||
|
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||||
|
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||||
|
cb = (float)(-0.169 * r - 0.331 * g + 0.500 * b);
|
||||||
|
cr = (float)(0.500 * r - 0.419 * g - 0.081 * b);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
y = (float)(0.2215 * r + 0.7154 * g + 0.0721 * b);
|
||||||
|
cb = (float)(-0.1145 * r - 0.3855 * g + 0.5000 * b);
|
||||||
|
cr = (float)(0.5016 * r - 0.4556 * g - 0.0459 * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
YCbCr[0] = (float)y;
|
||||||
|
YCbCr[1] = (float)cb;
|
||||||
|
YCbCr[2] = (float)cr;
|
||||||
|
|
||||||
|
return YCbCr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] YCbCrtoRGB(float y, float cb, float cr, YCbCrColorSpace colorSpace){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
float r,g,b;
|
||||||
|
|
||||||
|
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||||
|
r = (float)(y + 0.000 * cb + 1.403 * cr) * 255;
|
||||||
|
g = (float)(y - 0.344 * cb - 0.714 * cr) * 255;
|
||||||
|
b = (float)(y + 1.773 * cb + 0.000 * cr) * 255;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
r = (float)(y + 0.000 * cb + 1.5701 * cr) * 255;
|
||||||
|
g = (float)(y - 0.1870 * cb - 0.4664 * cr) * 255;
|
||||||
|
b = (float)(y + 1.8556 * cb + 0.000 * cr) * 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb[0] = (int)r;
|
||||||
|
rgb[1] = (int)g;
|
||||||
|
rgb[2] = (int)b;
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rg-Chromaticity space is already known to remove ambiguities due to illumination or surface pose.
|
||||||
|
* @see Neural Information Processing - Chi Sing Leung. p. 668
|
||||||
|
* @param red Red coefficient.
|
||||||
|
* @param green Green coefficient.
|
||||||
|
* @param blue Blue coefficient.
|
||||||
|
* @return Normalized RGChromaticity. Range[0..1].
|
||||||
|
*/
|
||||||
|
public static double[] RGChromaticity(int red, int green, int blue){
|
||||||
|
double[] color = new double[5];
|
||||||
|
|
||||||
|
double sum = red + green + blue;
|
||||||
|
|
||||||
|
//red
|
||||||
|
color[0] = red / sum;
|
||||||
|
|
||||||
|
//green
|
||||||
|
color[1] = green / sum;
|
||||||
|
|
||||||
|
//blue
|
||||||
|
color[2] = 1 - color[0] - color[1];
|
||||||
|
|
||||||
|
double rS = color[0] - 0.333;
|
||||||
|
double gS = color[1] - 0.333;
|
||||||
|
|
||||||
|
//saturation
|
||||||
|
color[3] = Math.sqrt(rS * rS + gS * gS);
|
||||||
|
|
||||||
|
//hue
|
||||||
|
color[4] = Math.atan(rS / gS);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> HSV.
|
||||||
|
* Adds (hue + 360) % 360 for represent hue in the range [0..359].
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return HSV color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoHSV(int red, int green, int blue){
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
float max = Math.max(r, Math.max(g, b));
|
||||||
|
float min = Math.min(r, Math.min(g, b));
|
||||||
|
float delta = max - min;
|
||||||
|
|
||||||
|
// Hue
|
||||||
|
if (max == min){
|
||||||
|
hsv[0] = 0;
|
||||||
|
}
|
||||||
|
else if (max == r){
|
||||||
|
hsv[0] = ((g - b) / delta) * 60f;
|
||||||
|
}
|
||||||
|
else if (max == g){
|
||||||
|
hsv[0] = ((b - r) / delta + 2f) * 60f;
|
||||||
|
}
|
||||||
|
else if (max == b){
|
||||||
|
hsv[0] = ((r - g) / delta + 4f) * 60f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saturation
|
||||||
|
if (delta == 0)
|
||||||
|
hsv[1] = 0;
|
||||||
|
else
|
||||||
|
hsv[1] = delta / max;
|
||||||
|
|
||||||
|
//Value
|
||||||
|
hsv[2] = max;
|
||||||
|
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HSV -> RGB.
|
||||||
|
* @param hue Hue.
|
||||||
|
* @param saturation Saturation. In the range[0..1].
|
||||||
|
* @param value Value. In the range[0..1].
|
||||||
|
* @return RGB color space. In the range[0..255].
|
||||||
|
*/
|
||||||
|
public static int[] HSVtoRGB(float hue, float saturation, float value){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
|
||||||
|
float hi = (float)Math.floor(hue / 60.0) % 6;
|
||||||
|
float f = (float)((hue / 60.0) - Math.floor(hue / 60.0));
|
||||||
|
float p = (float)(value * (1.0 - saturation));
|
||||||
|
float q = (float)(value * (1.0 - (f * saturation)));
|
||||||
|
float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));
|
||||||
|
|
||||||
|
if (hi == 0){
|
||||||
|
rgb[0] = (int)(value * 255);
|
||||||
|
rgb[1] = (int)(t * 255);
|
||||||
|
rgb[2] = (int)(p * 255);
|
||||||
|
}
|
||||||
|
else if (hi == 1){
|
||||||
|
rgb[0] = (int)(q * 255);
|
||||||
|
rgb[1] = (int)(value * 255);
|
||||||
|
rgb[2] = (int)(p * 255);
|
||||||
|
}
|
||||||
|
else if (hi == 2){
|
||||||
|
rgb[0] = (int)(p * 255);
|
||||||
|
rgb[1] = (int)(value * 255);
|
||||||
|
rgb[2] = (int)(t * 255);
|
||||||
|
}
|
||||||
|
else if (hi == 3){
|
||||||
|
rgb[0] = (int)(p * 255);
|
||||||
|
rgb[1] = (int)(value * 255);
|
||||||
|
rgb[2] = (int)(q * 255);
|
||||||
|
}
|
||||||
|
else if (hi == 4){
|
||||||
|
rgb[0] = (int)(t * 255);
|
||||||
|
rgb[1] = (int)(value * 255);
|
||||||
|
rgb[2] = (int)(p * 255);
|
||||||
|
}
|
||||||
|
else if (hi == 5){
|
||||||
|
rgb[0] = (int)(value * 255);
|
||||||
|
rgb[1] = (int)(p * 255);
|
||||||
|
rgb[2] = (int)(q * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> YCC.
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return YCC color space. In the range [0..1].
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoYCC(int red, int green, int blue){
|
||||||
|
float[] ycc = new float[3];
|
||||||
|
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
float y = 0.213f * r + 0.419f * g + 0.081f * b;
|
||||||
|
float c1 = -0.131f * r - 0.256f * g + 0.387f * b + 0.612f;
|
||||||
|
float c2 = 0.373f * r - 0.312f * r - 0.061f * b + 0.537f;
|
||||||
|
|
||||||
|
ycc[0] = y;
|
||||||
|
ycc[1] = c1;
|
||||||
|
ycc[2] = c2;
|
||||||
|
|
||||||
|
return ycc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YCC -> RGB.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @param c1 C coefficient.
|
||||||
|
* @param c2 C coefficient.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] YCCtoRGB(float y, float c1, float c2){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
|
||||||
|
float r = 0.981f * y + 1.315f * (c2 - 0.537f);
|
||||||
|
float g = 0.981f * y - 0.311f * (c1 - 0.612f)- 0.669f * (c2 - 0.537f);
|
||||||
|
float b = 0.981f * y + 1.601f * (c1 - 0.612f);
|
||||||
|
|
||||||
|
rgb[0] = (int)(r * 255f);
|
||||||
|
rgb[1] = (int)(g * 255f);
|
||||||
|
rgb[2] = (int)(b * 255f);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> YCoCg.
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return YCoCg color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoYCoCg(int red, int green, int blue){
|
||||||
|
float[] yCoCg = new float[3];
|
||||||
|
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
float y = r / 4f + g / 2f + b / 4f;
|
||||||
|
float co = r / 2f - b / 2f;
|
||||||
|
float cg = -r / 4f + g / 2f - b / 4f;
|
||||||
|
|
||||||
|
yCoCg[0] = y;
|
||||||
|
yCoCg[1] = co;
|
||||||
|
yCoCg[2] = cg;
|
||||||
|
|
||||||
|
return yCoCg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YCoCg -> RGB.
|
||||||
|
* @param y Pseudo luminance, or intensity.
|
||||||
|
* @param co Orange chrominance.
|
||||||
|
* @param cg Green chrominance.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] YCoCgtoRGB(float y, float co, float cg){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
|
||||||
|
float r = y + co - cg;
|
||||||
|
float g = y + cg;
|
||||||
|
float b = y - co - cg;
|
||||||
|
|
||||||
|
rgb[0] = (int)(r * 255f);
|
||||||
|
rgb[1] = (int)(g * 255f);
|
||||||
|
rgb[2] = (int)(b * 255f);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> XYZ
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return XYZ color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoXYZ(int red, int green, int blue){
|
||||||
|
float[] xyz = new float[3];
|
||||||
|
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
//R
|
||||||
|
if ( r > 0.04045)
|
||||||
|
r = (float)Math.pow(( ( r + 0.055f ) / 1.055f ), 2.4f);
|
||||||
|
else
|
||||||
|
r /= 12.92f;
|
||||||
|
|
||||||
|
//G
|
||||||
|
if ( g > 0.04045)
|
||||||
|
g = (float)Math.pow(( ( g + 0.055f ) / 1.055f ), 2.4f);
|
||||||
|
else
|
||||||
|
g /= 12.92f;
|
||||||
|
|
||||||
|
//B
|
||||||
|
if ( b > 0.04045)
|
||||||
|
b = (float)Math.pow(( ( b + 0.055f ) / 1.055f ), 2.4f);
|
||||||
|
else
|
||||||
|
b /= 12.92f;
|
||||||
|
|
||||||
|
r *= 100;
|
||||||
|
g *= 100;
|
||||||
|
b *= 100;
|
||||||
|
|
||||||
|
float x = 0.412453f * r + 0.35758f * g + 0.180423f * b;
|
||||||
|
float y = 0.212671f * r + 0.71516f * g + 0.072169f * b;
|
||||||
|
float z = 0.019334f * r + 0.119193f * g + 0.950227f * b;
|
||||||
|
|
||||||
|
xyz[0] = x;
|
||||||
|
xyz[1] = y;
|
||||||
|
xyz[2] = z;
|
||||||
|
|
||||||
|
return xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XYZ -> RGB
|
||||||
|
* @param x X coefficient.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @param z Z coefficient.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] XYZtoRGB(float x, float y, float z){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
|
||||||
|
x /= 100;
|
||||||
|
y /= 100;
|
||||||
|
z /= 100;
|
||||||
|
|
||||||
|
float r = 3.240479f * x - 1.53715f * y - 0.498535f * z;
|
||||||
|
float g = -0.969256f * x + 1.875991f * y + 0.041556f * z;
|
||||||
|
float b = 0.055648f * x - 0.204043f * y + 1.057311f * z;
|
||||||
|
|
||||||
|
if ( r > 0.0031308 )
|
||||||
|
r = 1.055f * ( (float)Math.pow(r, 0.4166f) ) - 0.055f;
|
||||||
|
else
|
||||||
|
r = 12.92f * r;
|
||||||
|
|
||||||
|
if ( g > 0.0031308 )
|
||||||
|
g = 1.055f * ( (float)Math.pow(g, 0.4166f) ) - 0.055f;
|
||||||
|
else
|
||||||
|
g = 12.92f * g;
|
||||||
|
|
||||||
|
if ( b > 0.0031308 )
|
||||||
|
b = 1.055f * ( (float)Math.pow(b, 0.4166f) ) - 0.055f;
|
||||||
|
else
|
||||||
|
b = 12.92f * b;
|
||||||
|
|
||||||
|
rgb[0] = (int)(r * 255);
|
||||||
|
rgb[1] = (int)(g * 255);
|
||||||
|
rgb[2] = (int)(b * 255);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XYZ -> HunterLAB
|
||||||
|
* @param x X coefficient.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @param z Z coefficient.
|
||||||
|
* @return HunterLab coefficient.
|
||||||
|
*/
|
||||||
|
public static float[] XYZtoHunterLAB(float x, float y, float z){
|
||||||
|
float[] hunter = new float[3];
|
||||||
|
|
||||||
|
|
||||||
|
float sqrt = (float)Math.sqrt(y);
|
||||||
|
|
||||||
|
float l = 10 * sqrt;
|
||||||
|
float a = 17.5f * (((1.02f * x) - y) / sqrt);
|
||||||
|
float b = 7f * ((y - (0.847f * z)) / sqrt);
|
||||||
|
|
||||||
|
hunter[0] = l;
|
||||||
|
hunter[1] = a;
|
||||||
|
hunter[2] = b;
|
||||||
|
|
||||||
|
return hunter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HunterLAB -> XYZ
|
||||||
|
* @param l L coefficient.
|
||||||
|
* @param a A coefficient.
|
||||||
|
* @param b B coefficient.
|
||||||
|
* @return XYZ color space.
|
||||||
|
*/
|
||||||
|
public static float[] HunterLABtoXYZ(float l, float a, float b){
|
||||||
|
float[] xyz = new float[3];
|
||||||
|
|
||||||
|
|
||||||
|
float tempY = l / 10f;
|
||||||
|
float tempX = a / 17.5f * l / 10f;
|
||||||
|
float tempZ = b / 7f * l / 10f;
|
||||||
|
|
||||||
|
float y = tempY * tempY;
|
||||||
|
float x = (tempX + y) / 1.02f;
|
||||||
|
float z = -(tempZ - y) / 0.847f;
|
||||||
|
|
||||||
|
xyz[0] = x;
|
||||||
|
xyz[1] = y;
|
||||||
|
xyz[2] = z;
|
||||||
|
|
||||||
|
return xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> HunterLAB.
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return HunterLAB color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoHunterLAB(int red, int green, int blue){
|
||||||
|
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||||
|
return XYZtoHunterLAB(xyz[0], xyz[1], xyz[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HunterLAB -> RGB.
|
||||||
|
* @param l L coefficient.
|
||||||
|
* @param a A coefficient.
|
||||||
|
* @param b B coefficient.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] HunterLABtoRGB(float l, float a, float b){
|
||||||
|
float[] xyz = HunterLABtoXYZ(l, a, b);
|
||||||
|
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> HLS.
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return HLS color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoHLS(int red, int green, int blue){
|
||||||
|
float[] hsl = new float[3];
|
||||||
|
|
||||||
|
float r = red / 255f;
|
||||||
|
float g = green / 255f;
|
||||||
|
float b = blue / 255f;
|
||||||
|
|
||||||
|
float max = Math.max(r,Math.max(r,b));
|
||||||
|
float min = Math.min(r,Math.min(r,b));
|
||||||
|
float delta = max - min;
|
||||||
|
|
||||||
|
//HSK
|
||||||
|
float h = 0;
|
||||||
|
float s = 0;
|
||||||
|
float l = (max + min) / 2;
|
||||||
|
|
||||||
|
if ( delta == 0 ){
|
||||||
|
// gray color
|
||||||
|
h = 0;
|
||||||
|
s = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get saturation value
|
||||||
|
s = ( l <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) );
|
||||||
|
|
||||||
|
// get hue value
|
||||||
|
float hue;
|
||||||
|
|
||||||
|
if ( r == max )
|
||||||
|
{
|
||||||
|
hue = ( ( g - b ) / 6 ) / delta;
|
||||||
|
}
|
||||||
|
else if ( g == max )
|
||||||
|
{
|
||||||
|
hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// correct hue if needed
|
||||||
|
if ( hue < 0 )
|
||||||
|
hue += 1;
|
||||||
|
if ( hue > 1 )
|
||||||
|
hue -= 1;
|
||||||
|
|
||||||
|
h = (int) ( hue * 360 );
|
||||||
|
}
|
||||||
|
|
||||||
|
hsl[0] = h;
|
||||||
|
hsl[1] = s;
|
||||||
|
hsl[2] = l;
|
||||||
|
|
||||||
|
return hsl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HLS -> RGB.
|
||||||
|
* @param hue Hue.
|
||||||
|
* @param saturation Saturation.
|
||||||
|
* @param luminance Luminance.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] HSLtoRGB(float hue, float saturation, float luminance){
|
||||||
|
int[] rgb = new int[3];
|
||||||
|
float r = 0, g = 0, b = 0;
|
||||||
|
|
||||||
|
if ( saturation == 0 )
|
||||||
|
{
|
||||||
|
// gray values
|
||||||
|
r = g = b = (int) ( luminance * 255 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float v1, v2;
|
||||||
|
float h = (float) hue / 360;
|
||||||
|
|
||||||
|
v2 = ( luminance < 0.5 ) ?
|
||||||
|
( luminance * ( 1 + saturation ) ) :
|
||||||
|
( ( luminance + saturation ) - ( luminance * saturation ) );
|
||||||
|
v1 = 2 * luminance - v2;
|
||||||
|
|
||||||
|
r = (int) ( 255 * Hue_2_RGB( v1, v2, h + ( 1.0f / 3 ) ) );
|
||||||
|
g = (int) ( 255 * Hue_2_RGB( v1, v2, h ) );
|
||||||
|
b = (int) ( 255 * Hue_2_RGB( v1, v2, h - ( 1.0f / 3 ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb[0] = (int)r;
|
||||||
|
rgb[1] = (int)g;
|
||||||
|
rgb[2] = (int)b;
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float Hue_2_RGB( float v1, float v2, float vH ){
|
||||||
|
if ( vH < 0 )
|
||||||
|
vH += 1;
|
||||||
|
if ( vH > 1 )
|
||||||
|
vH -= 1;
|
||||||
|
if ( ( 6 * vH ) < 1 )
|
||||||
|
return ( v1 + ( v2 - v1 ) * 6 * vH );
|
||||||
|
if ( ( 2 * vH ) < 1 )
|
||||||
|
return v2;
|
||||||
|
if ( ( 3 * vH ) < 2 )
|
||||||
|
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> CIE-LAB.
|
||||||
|
* @param red Red coefficient. Values in the range [0..255].
|
||||||
|
* @param green Green coefficient. Values in the range [0..255].
|
||||||
|
* @param blue Blue coefficient. Values in the range [0..255].
|
||||||
|
* @param tristimulus XYZ Tristimulus.
|
||||||
|
* @return CIE-LAB color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoLAB(int red, int green, int blue, float[] tristimulus){
|
||||||
|
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||||
|
float[] lab = XYZtoLAB(xyz[0], xyz[1], xyz[2], tristimulus);
|
||||||
|
|
||||||
|
return lab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CIE-LAB -> RGB.
|
||||||
|
* @param l L coefficient.
|
||||||
|
* @param a A coefficient.
|
||||||
|
* @param b B coefficient.
|
||||||
|
* @param tristimulus XYZ Tristimulus.
|
||||||
|
* @return RGB color space.
|
||||||
|
*/
|
||||||
|
public static int[] LABtoRGB(float l, float a, float b, float[] tristimulus){
|
||||||
|
float[] xyz = LABtoXYZ(l, a, b, tristimulus);
|
||||||
|
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XYZ -> CIE-LAB.
|
||||||
|
* @param x X coefficient.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @param z Z coefficient.
|
||||||
|
* @param tristimulus XYZ Tristimulus.
|
||||||
|
* @return CIE-LAB color space.
|
||||||
|
*/
|
||||||
|
public static float[] XYZtoLAB(float x, float y, float z, float[] tristimulus){
|
||||||
|
float[] lab = new float[3];
|
||||||
|
|
||||||
|
x /= tristimulus[0];
|
||||||
|
y /= tristimulus[1];
|
||||||
|
z /= tristimulus[2];
|
||||||
|
|
||||||
|
if (x > 0.008856)
|
||||||
|
x = (float)Math.pow(x,0.33f);
|
||||||
|
else
|
||||||
|
x = (7.787f * x) + ( 0.1379310344827586f );
|
||||||
|
|
||||||
|
if (y > 0.008856)
|
||||||
|
y = (float)Math.pow(y,0.33f);
|
||||||
|
else
|
||||||
|
y = (7.787f * y) + ( 0.1379310344827586f );
|
||||||
|
|
||||||
|
if (z > 0.008856)
|
||||||
|
z = (float)Math.pow(z,0.33f);
|
||||||
|
else
|
||||||
|
z = (7.787f * z) + ( 0.1379310344827586f );
|
||||||
|
|
||||||
|
lab[0] = ( 116 * y ) - 16;
|
||||||
|
lab[1] = 500 * ( x - y );
|
||||||
|
lab[2] = 200 * ( y - z );
|
||||||
|
|
||||||
|
return lab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CIE-LAB -> XYZ.
|
||||||
|
* @param l L coefficient.
|
||||||
|
* @param a A coefficient.
|
||||||
|
* @param b B coefficient.
|
||||||
|
* @param tristimulus XYZ Tristimulus.
|
||||||
|
* @return XYZ color space.
|
||||||
|
*/
|
||||||
|
public static float[] LABtoXYZ(float l, float a, float b, float[] tristimulus){
|
||||||
|
float[] xyz = new float[3];
|
||||||
|
|
||||||
|
float y = ( l + 16f ) / 116f;
|
||||||
|
float x = a / 500f + y;
|
||||||
|
float z = y - b / 200f;
|
||||||
|
|
||||||
|
//Y
|
||||||
|
if ( Math.pow(y,3) > 0.008856 )
|
||||||
|
y = (float)Math.pow(y,3);
|
||||||
|
else
|
||||||
|
y = (float)(( y - 16 / 116 ) / 7.787);
|
||||||
|
|
||||||
|
//X
|
||||||
|
if ( Math.pow(x,3) > 0.008856 )
|
||||||
|
x = (float)Math.pow(x,3);
|
||||||
|
else
|
||||||
|
x = (float)(( x - 16 / 116 ) / 7.787);
|
||||||
|
|
||||||
|
// Z
|
||||||
|
if ( Math.pow(z,3) > 0.008856 )
|
||||||
|
z = (float)Math.pow(z,3);
|
||||||
|
else
|
||||||
|
z = (float)(( z - 16 / 116 ) / 7.787);
|
||||||
|
|
||||||
|
xyz[0] = x * tristimulus[0];
|
||||||
|
xyz[1] = y * tristimulus[1];
|
||||||
|
xyz[2] = z * tristimulus[2];
|
||||||
|
|
||||||
|
return xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> C1C2C3.
|
||||||
|
* @param r Red coefficient. Values in the range [0..255].
|
||||||
|
* @param g Green coefficient. Values in the range [0..255].
|
||||||
|
* @param b Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return C1C2C3 color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoC1C2C3(int r, int g, int b){
|
||||||
|
|
||||||
|
float[] c = new float[3];
|
||||||
|
|
||||||
|
c[0] = (float)Math.atan(r / Math.max(g, b));
|
||||||
|
c[1] = (float)Math.atan(g / Math.max(r, b));
|
||||||
|
c[2] = (float)Math.atan(b / Math.max(r, g));
|
||||||
|
|
||||||
|
return c;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> O1O2.
|
||||||
|
* @param r Red coefficient. Values in the range [0..255].
|
||||||
|
* @param g Green coefficient. Values in the range [0..255].
|
||||||
|
* @param b Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return O1O2 color space.
|
||||||
|
*/
|
||||||
|
public static float[] RGBtoO1O2(int r, int g, int b){
|
||||||
|
|
||||||
|
float[] o = new float[2];
|
||||||
|
|
||||||
|
o[0] = (r - g) / 2f;
|
||||||
|
o[1] = (r + g) / 4f - (b / 2f);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB -> Grayscale.
|
||||||
|
* @param r Red coefficient. Values in the range [0..255].
|
||||||
|
* @param g Green coefficient. Values in the range [0..255].
|
||||||
|
* @param b Blue coefficient. Values in the range [0..255].
|
||||||
|
* @return Grayscale color space.
|
||||||
|
*/
|
||||||
|
public static float RGBtoGrayscale(int r, int g, int b){
|
||||||
|
|
||||||
|
return r*0.2125f + g*0.7154f + b*0.0721f;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XYZ -> Philips Hue XY
|
||||||
|
* @param x X coefficient.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @param z Z coefficient.
|
||||||
|
* @return Hue xy array
|
||||||
|
*/
|
||||||
|
public static XYColorSpace XYZtoXY(float x, float y, float z){
|
||||||
|
float[] xy = new float[2];
|
||||||
|
|
||||||
|
xy[0] = x / (x + y + z);
|
||||||
|
xy[1] = y / (x + y + z);
|
||||||
|
|
||||||
|
XYColorSpace xyColor = new XYColorSpace();
|
||||||
|
xyColor.setBrightness((int)Math.round(y * 254.0f));
|
||||||
|
xyColor.setXy(xy);
|
||||||
|
return xyColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Philips Hue XY -> XYZ
|
||||||
|
* @param x X coefficient.
|
||||||
|
* @param y Y coefficient.
|
||||||
|
* @return XYZ array
|
||||||
|
*/
|
||||||
|
public static float[] XYtoXYZ(XYColorSpace xy){
|
||||||
|
float[] xyz = new float[3];
|
||||||
|
|
||||||
|
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
|
||||||
|
xyz[1] = xy.getBrightnessAdjusted();
|
||||||
|
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
|
||||||
|
|
||||||
|
return xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] normalizeRGB(int[] rgb) {
|
||||||
|
int[] newRGB = new int[3];
|
||||||
|
|
||||||
|
newRGB[0] = assureBounds(rgb[0]);
|
||||||
|
newRGB[1] = assureBounds(rgb[1]);
|
||||||
|
newRGB[2] = assureBounds(rgb[2]);
|
||||||
|
|
||||||
|
|
||||||
|
return newRGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int assureBounds(int value) {
|
||||||
|
if (value < 0.0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
if (value > 255.0) {
|
||||||
|
value = 255;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/com/bwssystems/HABridge/hue/ColorData.java
Normal file
28
src/main/java/com/bwssystems/HABridge/hue/ColorData.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
public class ColorData {
|
||||||
|
public enum ColorMode { XY, CT, HS}
|
||||||
|
|
||||||
|
private ColorMode mode;
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public ColorData(ColorMode mode, Object value) {
|
||||||
|
this.mode = mode;
|
||||||
|
this.data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorMode getColorMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
String formatString;
|
||||||
|
|
||||||
|
formatString = "Color Data mode: " + mode + ", data: " + data;
|
||||||
|
return formatString;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,387 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.hue.ColorData;
|
||||||
|
|
||||||
public class ColorDecode {
|
public class ColorDecode {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ColorDecode.class);
|
||||||
|
private static final String COLOR_R = "${color.r}";
|
||||||
|
private static final String COLOR_G = "${color.g}";
|
||||||
|
private static final String COLOR_B = "${color.b}";
|
||||||
|
private static final String COLOR_RX = "${color.rx}";
|
||||||
|
private static final String COLOR_GX = "${color.gx}";
|
||||||
|
private static final String COLOR_BX = "${color.bx}";
|
||||||
|
private static final String COLOR_RGBX = "${color.rgbx}";
|
||||||
|
private static final String COLOR_HSB = "${color.hsb}";
|
||||||
|
private static final String COLOR_H = "${color.h}";
|
||||||
|
private static final String COLOR_S = "${color.s}";
|
||||||
|
private static final String COLOR_XY = "${color.xy}";
|
||||||
|
private static final String COLOR_BRI = "${colorbri}";
|
||||||
|
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
|
||||||
|
|
||||||
public static String convertCIEtoRGB(List<Double> xy) {
|
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
|
||||||
double x;
|
List<Integer> rgb;
|
||||||
double y;
|
Float hue = (Float)(hsb.getHue()*1.0f);
|
||||||
double Y;
|
Float saturation = (Float)(hsb.getSat()*1.0f);
|
||||||
|
Float brightness = (Float)(hsb.getBri()*1.0f);
|
||||||
|
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
|
||||||
|
//Convert Hue into degrees for HSB
|
||||||
|
hue = hue / 182.04f;
|
||||||
|
//Bri and Sat must be values from 0-1 (~percentage)
|
||||||
|
brightness = brightness / 255.0f;
|
||||||
|
saturation = saturation / 255.0f;
|
||||||
|
|
||||||
x = xy.get(0) * 100;
|
Float r = 0f;
|
||||||
y = xy.get(1) * 100;
|
Float g = 0f;
|
||||||
Y= y;
|
Float b = 0f;
|
||||||
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;
|
if (saturation == 0)
|
||||||
|
{
|
||||||
|
r = g = b = brightness;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the color wheel consists of 6 sectors.
|
||||||
|
Float sectorPos = hue / 60.0f;
|
||||||
|
int sectorNumber = (int)(Math.floor(sectorPos));
|
||||||
|
// get the fractional part of the sector
|
||||||
|
Float fractionalSector = sectorPos - sectorNumber;
|
||||||
|
|
||||||
|
// calculate values for the three axes of the color.
|
||||||
|
Float p = brightness * (1.0f - saturation);
|
||||||
|
Float q = brightness * (1.0f - (saturation * fractionalSector));
|
||||||
|
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
|
||||||
|
|
||||||
|
// assign the fractional colors to r, g, and b based on the sector the angle is in.
|
||||||
|
switch (sectorNumber)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r = brightness;
|
||||||
|
g = t;
|
||||||
|
b = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r = q;
|
||||||
|
g = brightness;
|
||||||
|
b = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r = p;
|
||||||
|
g = brightness;
|
||||||
|
b = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
r = p;
|
||||||
|
g = q;
|
||||||
|
b = brightness;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
r = t;
|
||||||
|
g = p;
|
||||||
|
b = brightness;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
r = brightness;
|
||||||
|
g = p;
|
||||||
|
b = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if any value is out of byte range
|
||||||
|
if (r < 0f)
|
||||||
|
{
|
||||||
|
r = 0f;
|
||||||
|
}
|
||||||
|
if (g < 0f)
|
||||||
|
{
|
||||||
|
g = 0f;
|
||||||
|
}
|
||||||
|
if (b < 0f)
|
||||||
|
{
|
||||||
|
b = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb = new ArrayList<Integer>();
|
||||||
|
rgb.add((int)Math.round(r*255));
|
||||||
|
rgb.add((int)Math.round(g*255));
|
||||||
|
rgb.add((int)Math.round(b*255));
|
||||||
|
log.debug("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||||
|
+ rgb.get(2));
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
|
||||||
|
List<Integer> rgb;
|
||||||
|
XYColorSpace xyColor = new XYColorSpace();
|
||||||
|
xyColor.setBrightness(brightness);
|
||||||
|
float[] xyFloat = new float[2];
|
||||||
|
xyFloat[0] = xy.get(0).floatValue();
|
||||||
|
xyFloat[1] = xy.get(1).floatValue();
|
||||||
|
xyColor.setXy(xyFloat);
|
||||||
|
float[] xyz = ColorConverter.XYtoXYZ(xyColor);
|
||||||
|
int[] rgbInt = ColorConverter.normalizeRGB(ColorConverter.XYZtoRGB(xyz[0], xyz[1], xyz[2]));
|
||||||
|
rgb = new ArrayList<Integer>();
|
||||||
|
rgb.add(rgbInt[0]);
|
||||||
|
rgb.add(rgbInt[1]);
|
||||||
|
rgb.add(rgbInt[2]);
|
||||||
|
log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||||
|
+ " " + rgb.get(2));
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// took that approximation from
|
||||||
|
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||||
|
public static List<Integer> convertCTtoRGB(Integer ct) {
|
||||||
|
double temperature = 1000000.0 / (double) ct;
|
||||||
|
temperature /= 100;
|
||||||
|
double r, g, b;
|
||||||
|
if (temperature <= 66) {
|
||||||
|
r = 255;
|
||||||
|
g = temperature;
|
||||||
|
g = 99.4708025861 * Math.log(g) - 161.1195681661;
|
||||||
|
} else {
|
||||||
|
r = temperature - 60;
|
||||||
|
r = 329.698727446 * (Math.pow(r, -0.1332047592));
|
||||||
|
g = temperature - 60;
|
||||||
|
g = 288.1221695283 * (Math.pow(g, -0.0755148492));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temperature >= 66) {
|
||||||
|
b = 255;
|
||||||
|
} else {
|
||||||
|
if (temperature <= 19) {
|
||||||
|
b = 0;
|
||||||
|
} else {
|
||||||
|
b = temperature - 10;
|
||||||
|
b = 138.5177312231 * Math.log(b) - 305.0447927307;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = assureBounds(r);
|
||||||
|
g = assureBounds(g);
|
||||||
|
b = assureBounds(b);
|
||||||
|
List<Integer> rgb = new ArrayList<Integer>();
|
||||||
|
rgb.add((int) Math.round(r));
|
||||||
|
rgb.add((int) Math.round(g));
|
||||||
|
rgb.add((int) Math.round(b));
|
||||||
|
log.debug("Color change with CT: " + ct + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||||
|
+ rgb.get(2));
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double assureBounds(double value) {
|
||||||
|
if (value < 0.0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
if (value > 255.0) {
|
||||||
|
value = 255;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static String replaceColorData(String request, ColorData colorData, int setIntensity, boolean isHex) {
|
||||||
|
if (request == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (colorData == null) {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
boolean notDone = true;
|
||||||
|
ColorData.ColorMode colorMode = colorData.getColorMode();
|
||||||
|
List<Integer> rgb = null;
|
||||||
|
if (colorMode == ColorData.ColorMode.XY) {
|
||||||
|
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
|
||||||
|
} else if (colorMode == ColorData.ColorMode.CT) {
|
||||||
|
rgb = convertCTtoRGB((Integer) colorData.getData());
|
||||||
|
} else if (colorMode == ColorData.ColorMode.HS) {
|
||||||
|
rgb = convertHSBtoRGB((HueSatBri) colorData.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (notDone) {
|
||||||
|
notDone = false;
|
||||||
|
if (request.contains(COLOR_R)) {
|
||||||
|
request = request.replace(COLOR_R,
|
||||||
|
isHex ? String.format("%02X", rgb.get(0)) : String.valueOf(rgb.get(0)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_G)) {
|
||||||
|
request = request.replace(COLOR_G,
|
||||||
|
isHex ? String.format("%02X", rgb.get(1)) : String.valueOf(rgb.get(1)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_B)) {
|
||||||
|
request = request.replace(COLOR_B,
|
||||||
|
isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_RX)) {
|
||||||
|
request = request.replace(COLOR_RX, String.format("%02X", rgb.get(0)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_GX)) {
|
||||||
|
request = request.replace(COLOR_GX, String.format("%02X", rgb.get(1)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_BX)) {
|
||||||
|
request = request.replace(COLOR_BX, String.format("%02X", rgb.get(2)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_RGBX)) {
|
||||||
|
request = request.replace(COLOR_RGBX,
|
||||||
|
String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_XY)) {
|
||||||
|
if (colorMode == ColorData.ColorMode.XY) {
|
||||||
|
List<Double> xyData = (List<Double>) colorData.getData();
|
||||||
|
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||||
|
} else {
|
||||||
|
List<Double> xyData = (List<Double>) colorData.getData();
|
||||||
|
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||||
|
}
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_H)) {
|
||||||
|
if (colorMode == ColorData.ColorMode.HS) {
|
||||||
|
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||||
|
request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
|
||||||
|
} else {
|
||||||
|
float[] hsb = new float[3];
|
||||||
|
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||||
|
float hue = hsb[0] * (float) 360.0;
|
||||||
|
request = request.replace(COLOR_H, String.format("%f", hue));
|
||||||
|
}
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_S)) {
|
||||||
|
if (colorMode == ColorData.ColorMode.HS) {
|
||||||
|
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||||
|
request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
|
||||||
|
} else {
|
||||||
|
float[] hsb = new float[3];
|
||||||
|
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||||
|
float sat = hsb[1] * (float) 100.0;
|
||||||
|
request = request.replace(COLOR_S, String.format("%f", sat));
|
||||||
|
}
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_BRI)) {
|
||||||
|
if (colorMode == ColorData.ColorMode.HS) {
|
||||||
|
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||||
|
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
|
||||||
|
} else {
|
||||||
|
request = request.replace(COLOR_BRI, String.format("%f", setIntensity));
|
||||||
|
}
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(COLOR_HSB)) {
|
||||||
|
if (colorMode == ColorData.ColorMode.HS) {
|
||||||
|
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||||
|
request = request.replace(COLOR_HSB,
|
||||||
|
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
|
||||||
|
} else {
|
||||||
|
float[] hsb = new float[3];
|
||||||
|
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||||
|
float hue = hsb[0] * (float) 360.0;
|
||||||
|
float sat = hsb[1] * (float) 100.0;
|
||||||
|
float bright = hsb[2] * (float) 100.0;
|
||||||
|
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));
|
||||||
|
}
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher m = COLOR_MILIGHT.matcher(request);
|
||||||
|
while (m.find()) {
|
||||||
|
int group = Integer.parseInt(m.group(1));
|
||||||
|
request = m.replaceFirst(getMilightV5FromRgb(rgb, group));
|
||||||
|
m.reset(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMilightV5FromRgb(List<Integer> rgb, int group) {
|
||||||
|
double r = (double) rgb.get(0);
|
||||||
|
double g = (double) rgb.get(1);
|
||||||
|
double b = (double) rgb.get(2);
|
||||||
|
if (r > 245 && g > 245 && b > 245) { // it's white
|
||||||
|
String retVal = "";
|
||||||
|
if (group == 0) {
|
||||||
|
retVal += "C2";
|
||||||
|
} else if (group == 1) {
|
||||||
|
retVal += "C5";
|
||||||
|
} else if (group == 2) {
|
||||||
|
retVal += "C7";
|
||||||
|
} else if (group == 3) {
|
||||||
|
retVal += "C9";
|
||||||
|
} else if (group == 4) {
|
||||||
|
retVal += "CB";
|
||||||
|
}
|
||||||
|
log.debug("Convert RGB to Milight. Result: WHITE. RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||||
|
+ rgb.get(2));
|
||||||
|
return retVal + "0055";
|
||||||
|
} else { // normal color
|
||||||
|
r /= (double) 0xFF;
|
||||||
|
g /= (double) 0xFF;
|
||||||
|
b /= (double) 0xFF;
|
||||||
|
double max = Math.max(Math.max(r, g), b), min = Math.min(Math.min(r, g), b);
|
||||||
|
double h = 0;
|
||||||
|
double d = max - min;
|
||||||
|
|
||||||
|
if (max == min) {
|
||||||
|
h = 0;
|
||||||
|
} else {
|
||||||
|
if (max == r) {
|
||||||
|
h = ((g - b) / d + (g < b ? 6 : 0));
|
||||||
|
} else if (max == g) {
|
||||||
|
h = ((b - r) / d + 2);
|
||||||
|
} else if (max == b) {
|
||||||
|
h = ((r - g) / d + 4);
|
||||||
|
}
|
||||||
|
h = Math.round(h * 60);
|
||||||
|
}
|
||||||
|
int milight = (int) ((256 + 176 - Math.floor(h / 360.0 * 255.0)) % 256);
|
||||||
|
log.debug("Convert RGB to Milight. Result: " + milight + " RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||||
|
+ " " + rgb.get(2));
|
||||||
|
return "40" + String.format("%02X", milight) + "55";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static int getIntRGB(ColorData colorData, int setIntensity) {
|
||||||
|
ColorData.ColorMode colorMode = colorData.getColorMode();
|
||||||
|
List<Integer> rgb = null;
|
||||||
|
if (colorMode == ColorData.ColorMode.XY) {
|
||||||
|
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
|
||||||
|
} else if (colorMode == ColorData.ColorMode.CT) {
|
||||||
|
rgb = convertCTtoRGB((Integer) colorData.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
int rgbIntVal = Integer.parseInt(String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)), 16);
|
||||||
|
log.debug("Convert RGB to int. Result: " + rgbIntVal + " RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||||
|
+ rgb.get(2));
|
||||||
|
return rgbIntVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/main/java/com/bwssystems/HABridge/hue/ColorMap.java
Normal file
75
src/main/java/com/bwssystems/HABridge/hue/ColorMap.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
public class ColorMap {
|
||||||
|
private double red;
|
||||||
|
private double green;
|
||||||
|
private double blue;
|
||||||
|
private long R;
|
||||||
|
private long G;
|
||||||
|
private long B;
|
||||||
|
private double X;
|
||||||
|
private double Y;
|
||||||
|
private Double Z;
|
||||||
|
private double z;
|
||||||
|
public double getRed() {
|
||||||
|
return red;
|
||||||
|
}
|
||||||
|
public void setRed(double red) {
|
||||||
|
this.red = red;
|
||||||
|
}
|
||||||
|
public double getGreen() {
|
||||||
|
return green;
|
||||||
|
}
|
||||||
|
public void setGreen(double green) {
|
||||||
|
this.green = green;
|
||||||
|
}
|
||||||
|
public double getBlue() {
|
||||||
|
return blue;
|
||||||
|
}
|
||||||
|
public void setBlue(double blue) {
|
||||||
|
this.blue = blue;
|
||||||
|
}
|
||||||
|
public long getR() {
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
public void setR(long r) {
|
||||||
|
R = r;
|
||||||
|
}
|
||||||
|
public long getG() {
|
||||||
|
return G;
|
||||||
|
}
|
||||||
|
public void setG(long g) {
|
||||||
|
G = g;
|
||||||
|
}
|
||||||
|
public long getB() {
|
||||||
|
return B;
|
||||||
|
}
|
||||||
|
public void setB(long b) {
|
||||||
|
B = b;
|
||||||
|
}
|
||||||
|
public double getX() {
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
public void setX(double x) {
|
||||||
|
X = x;
|
||||||
|
}
|
||||||
|
public double getY() {
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
public void setY(double y) {
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
public Double getZ() {
|
||||||
|
return Z;
|
||||||
|
}
|
||||||
|
public void setZ(Double z) {
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
public double getz() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
public void setz(double z) {
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,6 +14,9 @@ public class DeviceDataDecode {
|
|||||||
private static final String DEVICE_MAPTYPE = "${device.mapType}";
|
private static final String DEVICE_MAPTYPE = "${device.mapType}";
|
||||||
private static final String DEVICE_DEVICETYPE = "${device.deviceType}";
|
private static final String DEVICE_DEVICETYPE = "${device.deviceType}";
|
||||||
private static final String DEVICE_TARGETDEVICE = "${device.targetDevice}";
|
private static final String DEVICE_TARGETDEVICE = "${device.targetDevice}";
|
||||||
|
private static final String DEVICE_REQUESTERADDRESS = "${device.requesterAddress}";
|
||||||
|
private static final String DEVICE_DESCRIPTION = "${device.description}";
|
||||||
|
private static final String DEVICE_COMMENTS = "${device.comments}";
|
||||||
|
|
||||||
public static String replaceDeviceData(String request, DeviceDescriptor device) {
|
public static String replaceDeviceData(String request, DeviceDescriptor device) {
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
@@ -58,6 +61,21 @@ public class DeviceDataDecode {
|
|||||||
notDone = true;
|
notDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.contains(DEVICE_REQUESTERADDRESS)) {
|
||||||
|
request = request.replace(DEVICE_REQUESTERADDRESS, device.getRequesterAddress());
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(DEVICE_DESCRIPTION)) {
|
||||||
|
request = request.replace(DEVICE_DESCRIPTION, device.getDescription());
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.contains(DEVICE_COMMENTS)) {
|
||||||
|
request = request.replace(DEVICE_COMMENTS, device.getComments());
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,8 @@ package com.bwssystems.HABridge.hue;
|
|||||||
|
|
||||||
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.ColorData;
|
||||||
|
|
||||||
public interface HueMulatorHandler {
|
public interface HueMulatorHandler {
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body);
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body);
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/main/java/com/bwssystems/HABridge/hue/HueSatBri.java
Normal file
38
src/main/java/com/bwssystems/HABridge/hue/HueSatBri.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
public class HueSatBri {
|
||||||
|
int hue;
|
||||||
|
int sat;
|
||||||
|
int bri;
|
||||||
|
|
||||||
|
public int getHue() {
|
||||||
|
return hue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHue(int hue) {
|
||||||
|
this.hue = hue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSat() {
|
||||||
|
return sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSat(int sat) {
|
||||||
|
this.sat = sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBri() {
|
||||||
|
return bri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBri(int bri) {
|
||||||
|
this.bri = bri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
String formatString = new String();
|
||||||
|
|
||||||
|
formatString = "Hue: " + Integer.toString(hue) + ", Sat: " + Integer.toString(sat) + ", Bri: " + Integer.toString(bri);
|
||||||
|
return formatString;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
public class TimeDecode {
|
public class TimeDecode {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TimeDecode.class);
|
private static final Logger log = LoggerFactory.getLogger(TimeDecode.class);
|
||||||
private static final String TIME_FORMAT = "${time.format(";
|
private static final String TIME_FORMAT = "${time.format(";
|
||||||
|
private static final String TIMESTAMP = "${time.millis}";
|
||||||
private static final String TIME_FORMAT_CLOSE = ")}";
|
private static final String TIME_FORMAT_CLOSE = ")}";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -38,6 +39,10 @@ public class TimeDecode {
|
|||||||
log.warn("Could not format current time: " + timeFormatDescriptor, e);
|
log.warn("Could not format current time: " + timeFormatDescriptor, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (request.contains(TIMESTAMP)) {
|
||||||
|
request = request.replace(TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
||||||
|
notDone = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
|
public class XYColorSpace {
|
||||||
|
float[] xy;
|
||||||
|
int brightness;
|
||||||
|
|
||||||
|
public float[] getXy() {
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXy(float[] xy) {
|
||||||
|
this.xy = xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBrightness() {
|
||||||
|
return brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBrightnessAdjusted() {
|
||||||
|
return ((float) brightness / 254.0f) * 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrightness(int brightness) {
|
||||||
|
this.brightness = brightness;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,11 +7,12 @@ import java.util.Set;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
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.ColorData;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.nest.controller.Home;
|
import com.bwssystems.nest.controller.Home;
|
||||||
import com.bwssystems.nest.controller.Nest;
|
import com.bwssystems.nest.controller.Nest;
|
||||||
@@ -31,10 +32,13 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
|||||||
private Gson aGsonHandler;
|
private Gson aGsonHandler;
|
||||||
private Boolean isFarenheit;
|
private Boolean isFarenheit;
|
||||||
private Boolean validNest;
|
private Boolean validNest;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public NestHome(BridgeSettingsDescriptor bridgeSettings) {
|
public NestHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,30 +96,36 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(theSession != null) {
|
if(theSession != null) {
|
||||||
theNest.endNestSession();
|
theNest.endNestSession();
|
||||||
}
|
}
|
||||||
theNest = null;
|
theNest = null;
|
||||||
theSession = null;
|
theSession = null;
|
||||||
nestItems = null;
|
nestItems = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
log.debug("executing HUE api request to set away for nest " + anItem.getType() + ": " + anItem.getItem().toString());
|
log.debug("executing HUE api request to set away for nest " + anItem.getType() + ": " + anItem.getItem().toString());
|
||||||
if(!validNest) {
|
if(!validNest) {
|
||||||
log.warn("Should not get here, no Nest available");
|
log.warn("Should not get here, no Nest available");
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Should not get here, no Nest available\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"Should not get here, no Nest available\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_HOMEAWAY[DeviceMapTypes.typeIndex])) {
|
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_HOMEAWAY[DeviceMapTypes.typeIndex])) {
|
||||||
NestInstruction homeAway = null;
|
NestInstruction homeAway = null;
|
||||||
if(anItem.getItem().isJsonObject())
|
if(anItem.getItem().isJsonObject())
|
||||||
homeAway = aGsonHandler.fromJson(anItem.getItem(), NestInstruction.class);
|
homeAway = aGsonHandler.fromJson(anItem.getItem(), NestInstruction.class);
|
||||||
else
|
else
|
||||||
homeAway = aGsonHandler.fromJson(anItem.getItem().getAsString(), NestInstruction.class);
|
homeAway = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), NestInstruction.class);
|
||||||
theNest.getHome(homeAway.getName()).setAway(homeAway.getAway());
|
theNest.getHome(homeAway.getName()).setAway(homeAway.getAway());
|
||||||
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_THERMO_SET[DeviceMapTypes.typeIndex])) {
|
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_THERMO_SET[DeviceMapTypes.typeIndex])) {
|
||||||
NestInstruction thermoSetting = null;
|
NestInstruction thermoSetting = null;
|
||||||
@@ -157,27 +167,27 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
|||||||
log.warn("no valid Nest control info: " + thermoSetting.getControl());
|
log.warn("no valid Nest control info: " + thermoSetting.getControl());
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"no valid Nest control info\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"no valid Nest control info\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public com.bwssystems.HABridge.Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public com.bwssystems.HABridge.Home createHome(BridgeSettings bridgeSettings) {
|
||||||
theSession = null;
|
theSession = null;
|
||||||
theNest = null;
|
theNest = null;
|
||||||
nestItems = null;
|
nestItems = null;
|
||||||
validNest = bridgeSettings.isValidNest();
|
validNest = bridgeSettings.getBridgeSettingsDescriptor().isValidNest();
|
||||||
aGsonHandler = null;
|
aGsonHandler = null;
|
||||||
log.info("Nest Home created." + (validNest ? "" : " No Nest configured."));
|
log.info("Nest Home created." + (validNest ? "" : " No Nest configured."));
|
||||||
|
|
||||||
if(validNest) {
|
if(validNest) {
|
||||||
aGsonHandler = new GsonBuilder().create();
|
aGsonHandler = new GsonBuilder().create();
|
||||||
|
|
||||||
isFarenheit = bridgeSettings.isFarenheit();
|
isFarenheit = bridgeSettings.getBridgeSettingsDescriptor().isFarenheit();
|
||||||
try {
|
try {
|
||||||
theSession = new NestSession(bridgeSettings.getNestuser(), bridgeSettings.getNestpwd());
|
theSession = new NestSession(bridgeSettings.getBridgeSettingsDescriptor().getNestuser(), bridgeSettings.getBridgeSettingsDescriptor().getNestpwd());
|
||||||
theNest = new Nest(theSession);
|
theNest = new Nest(theSession);
|
||||||
} catch (LoginException e) {
|
} catch (LoginException e) {
|
||||||
log.error("Caught Login Exception, setting Nest to invalid....");
|
log.error("Caught Login Exception, setting Nest to invalid....");
|
||||||
@@ -187,5 +197,10 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
public class BroadlinkEntry {
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
private String ipAddr;
|
||||||
|
private String macAddr;
|
||||||
|
private String command;
|
||||||
|
private String data;
|
||||||
|
private String type;
|
||||||
|
private String baseType;
|
||||||
|
private String desc;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public String getIpAddr() {
|
||||||
|
return ipAddr;
|
||||||
|
}
|
||||||
|
public void setIpAddr(String ipAddr) {
|
||||||
|
this.ipAddr = ipAddr;
|
||||||
|
}
|
||||||
|
public String getMacAddr() {
|
||||||
|
return macAddr;
|
||||||
|
}
|
||||||
|
public void setMacAddr(String macAddr) {
|
||||||
|
this.macAddr = macAddr;
|
||||||
|
}
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
public void setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public String getBaseType() {
|
||||||
|
return baseType;
|
||||||
|
}
|
||||||
|
public void setBaseType(String baseType) {
|
||||||
|
this.baseType = baseType;
|
||||||
|
}
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
public void setDesc(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
public boolean hasIpAndMac() {
|
||||||
|
boolean deviceOk = true;
|
||||||
|
if(ipAddr == null || ipAddr.trim().isEmpty())
|
||||||
|
deviceOk = false;
|
||||||
|
else if(macAddr == null || macAddr.trim().isEmpty())
|
||||||
|
deviceOk = false;
|
||||||
|
else if(type == null || type.trim().isEmpty())
|
||||||
|
deviceOk = false;
|
||||||
|
return deviceOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.BindException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
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.BridgeSettings;
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.Configuration;
|
||||||
|
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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
import com.github.mob41.blapi.BLDevice;
|
||||||
|
import com.github.mob41.blapi.MP1Device;
|
||||||
|
import com.github.mob41.blapi.SP1Device;
|
||||||
|
import com.github.mob41.blapi.SP2Device;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.mac.MacFormatException;
|
||||||
|
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class BroadlinkHome implements Home {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BroadlinkHome.class);
|
||||||
|
private Map<String, BLDevice> broadlinkMap;
|
||||||
|
private Boolean validBroadlink;
|
||||||
|
private boolean closed;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
private BridgeSettingsDescriptor bridgeSettingsDesc;
|
||||||
|
|
||||||
|
public BroadlinkHome(BridgeSettings bridgeSettings) {
|
||||||
|
super();
|
||||||
|
closed = true;
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
|
broadlinkMap = null;
|
||||||
|
bridgeSettingsDesc = bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
|
validBroadlink = bridgeSettings.getBridgeSettingsDescriptor().isValidBroadlink();
|
||||||
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
|
if (isDevMode)
|
||||||
|
validBroadlink = true;
|
||||||
|
|
||||||
|
if(validBroadlink)
|
||||||
|
broadlinkDiscover();
|
||||||
|
|
||||||
|
log.info("Broadlink Home created." + (validBroadlink ? "" : " No Broadlinks configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItems(String type) {
|
||||||
|
List<BroadlinkEntry> deviceList = new ArrayList<BroadlinkEntry>();
|
||||||
|
if(!validBroadlink || broadlinkMap == null)
|
||||||
|
return deviceList;
|
||||||
|
BroadlinkEntry theResponse = null;
|
||||||
|
log.debug("consolidating devices for Broadlink");
|
||||||
|
Iterator<String> keys = broadlinkMap.keySet().iterator();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
theResponse = toEntry(broadlinkMap.get(key));
|
||||||
|
if(theResponse != null)
|
||||||
|
deviceList.add(theResponse);
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get BroadlinkDevice with name: " + key + ", skipping this Broadlink.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
if(validBroadlink)
|
||||||
|
broadlinkDiscover();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
|
String theReturn = null;
|
||||||
|
boolean changeState = false;
|
||||||
|
String theStringData = null;
|
||||||
|
log.debug("executing HUE api request to send message to BroadlinkDevice: " + anItem.getItem().toString());
|
||||||
|
if(!validBroadlink) {
|
||||||
|
log.warn("Should not get here, no Broadlinks configured");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
BroadlinkEntry broadlinkCommand = null;
|
||||||
|
if(anItem.getItem().isJsonObject())
|
||||||
|
broadlinkCommand = new Gson().fromJson(anItem.getItem(), BroadlinkEntry.class);
|
||||||
|
else
|
||||||
|
broadlinkCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), BroadlinkEntry.class);
|
||||||
|
BLDevice theDevice = null;
|
||||||
|
if(broadlinkMap != null && !broadlinkMap.isEmpty())
|
||||||
|
theDevice = broadlinkMap.get(broadlinkCommand.getId());
|
||||||
|
|
||||||
|
if (theDevice == null) {
|
||||||
|
if(broadlinkCommand.hasIpAndMac()) {
|
||||||
|
byte[] intBytes = HexLibrary.decodeHexString(broadlinkCommand.getType());
|
||||||
|
BigInteger theBig = new BigInteger(intBytes);
|
||||||
|
int theType = theBig.intValue();
|
||||||
|
try {
|
||||||
|
theDevice = BLDevice.createInstance((short)theType, broadlinkCommand.getIpAddr(), new Mac(broadlinkCommand.getMacAddr()));
|
||||||
|
} catch (MacFormatException e) {
|
||||||
|
log.warn("Could not initialize BroadlinkDevice device due to Mac (" + broadlinkCommand.getId() + ") format exception: " + e.getMessage());
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to Mac format exception\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not initialize BroadlinkDevice device due to IP Address (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to IP Address exception\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Could not initialize BroadlinkDevice device due to (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to exception\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(broadlinkMap == null)
|
||||||
|
broadlinkMap = new HashMap<String, BLDevice>();
|
||||||
|
|
||||||
|
if (theDevice != null) {
|
||||||
|
String newId = theDevice.getHost() + "-" + String.format("%04x", theDevice.getDeviceType());
|
||||||
|
if (broadlinkMap.get(newId) == null) {
|
||||||
|
broadlinkMap.put(newId, theDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (theDevice == null) {
|
||||||
|
log.warn("Should not get here, no BroadlinkDevice not available");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no Broadlinks available\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
} else {
|
||||||
|
log.debug("calling BroadlinkDevice: " + broadlinkCommand.getName());
|
||||||
|
try {
|
||||||
|
if(!isDevMode) {
|
||||||
|
if(!theDevice.auth()) {
|
||||||
|
log.error("Call to " + broadlinkCommand.getId() + " device authorization failed.");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device auth error.\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (theDevice.getDeviceType()) {
|
||||||
|
case BLDevice.DEV_A1:
|
||||||
|
log.debug("Broadlink A1 device called and not supported. No Action, device name = " + device.getName() + ", id= " + broadlinkCommand.getId());
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_MP1:
|
||||||
|
if(broadlinkCommand.getCommand().equals("on"))
|
||||||
|
changeState = true;
|
||||||
|
else
|
||||||
|
changeState = false;
|
||||||
|
((MP1Device) theDevice).setState(Integer.parseInt(broadlinkCommand.getData()), changeState);
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_SP2:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
|
||||||
|
case BLDevice.DEV_SPMINI:
|
||||||
|
case BLDevice.DEV_SP3:
|
||||||
|
case BLDevice.DEV_SPMINI2:
|
||||||
|
case BLDevice.DEV_SPMINI_OEM_ALT1:
|
||||||
|
case BLDevice.DEV_SPMINI_OEM_ALT2:
|
||||||
|
case BLDevice.DEV_SPMINI_PLUS:
|
||||||
|
if(broadlinkCommand.getCommand().equals("on"))
|
||||||
|
changeState = true;
|
||||||
|
else
|
||||||
|
changeState = false;
|
||||||
|
((SP2Device) theDevice).setState(changeState);
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_SP1:
|
||||||
|
if(broadlinkCommand.getCommand().equals("on"))
|
||||||
|
changeState = true;
|
||||||
|
else
|
||||||
|
changeState = false;
|
||||||
|
((SP1Device) theDevice).setPower(changeState);
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_RM_2:
|
||||||
|
case BLDevice.DEV_RM_MINI:
|
||||||
|
case BLDevice.DEV_RM_PRO_PHICOMM:
|
||||||
|
case BLDevice.DEV_RM_2_HOME_PLUS:
|
||||||
|
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS_2:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
|
||||||
|
case BLDevice.DEV_RM_MINI_SHATE:
|
||||||
|
if(broadlinkCommand.getData() != null && !broadlinkCommand.getData().trim().isEmpty()) {
|
||||||
|
theStringData = broadlinkCommand.getData().trim();
|
||||||
|
if(targetBri != null || targetBriInc != null) {
|
||||||
|
theStringData = BrightnessDecode.calculateReplaceIntensityValue(theStringData, intensity, targetBri, targetBriInc, true);
|
||||||
|
}
|
||||||
|
if(colorData != null) {
|
||||||
|
theStringData = ColorDecode.replaceColorData(theStringData, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||||
|
}
|
||||||
|
theStringData = DeviceDataDecode.replaceDeviceData(theStringData, device);
|
||||||
|
theStringData = TimeDecode.replaceTimeValue(theStringData);
|
||||||
|
byte[] theData = HexLibrary.decodeHexString(theStringData);
|
||||||
|
SendDataCmdPayload thePayload = new SendDataCmdPayload(theData);
|
||||||
|
|
||||||
|
DatagramPacket thePacket = theDevice.sendCmdPkt(Configuration.BROADLINK_DISCONVER_TIMEOUT, thePayload);
|
||||||
|
String returnData = null;
|
||||||
|
if(thePacket != null)
|
||||||
|
returnData = HexLibrary.encodeHexString(thePacket.getData());
|
||||||
|
else
|
||||||
|
returnData = "No Data - null";
|
||||||
|
log.debug("RM2 Device data return: <<<" + returnData + ">>>");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.error("Call to " + broadlinkCommand.getId() + " with no data, noop");
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"" + broadlinkCommand.getId() + " could not call device without data.\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Call to " + broadlinkCommand.getId() + " device failed with exception: " + e.getMessage(), e);
|
||||||
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device call error.\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BroadlinkEntry toEntry(BLDevice broadlinkObject) {
|
||||||
|
short baseType = 0;
|
||||||
|
switch (broadlinkObject.getDeviceType()) {
|
||||||
|
case BLDevice.DEV_MP1:
|
||||||
|
baseType = BLDevice.DEV_MP1;
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_SP2:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
|
||||||
|
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
|
||||||
|
case BLDevice.DEV_SPMINI:
|
||||||
|
case BLDevice.DEV_SP3:
|
||||||
|
case BLDevice.DEV_SPMINI2:
|
||||||
|
case BLDevice.DEV_SPMINI_OEM_ALT1:
|
||||||
|
case BLDevice.DEV_SPMINI_OEM_ALT2:
|
||||||
|
case BLDevice.DEV_SPMINI_PLUS:
|
||||||
|
baseType = BLDevice.DEV_SP2;
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_SP1:
|
||||||
|
baseType = BLDevice.DEV_SP1;
|
||||||
|
break;
|
||||||
|
case BLDevice.DEV_RM_2:
|
||||||
|
case BLDevice.DEV_RM_MINI:
|
||||||
|
case BLDevice.DEV_RM_PRO_PHICOMM:
|
||||||
|
case BLDevice.DEV_RM_2_HOME_PLUS:
|
||||||
|
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS_2:
|
||||||
|
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
|
||||||
|
case BLDevice.DEV_RM_MINI_SHATE:
|
||||||
|
baseType = BLDevice.DEV_RM_2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BroadlinkEntry anEntry = new BroadlinkEntry();
|
||||||
|
anEntry.setId(broadlinkObject.getHost() + "-" + String.format("%04x", broadlinkObject.getDeviceType()));
|
||||||
|
anEntry.setName(broadlinkObject.getDeviceDescription());
|
||||||
|
anEntry.setType(String.format("%04x", broadlinkObject.getDeviceType()));
|
||||||
|
anEntry.setBaseType(String.format("%04x", baseType));
|
||||||
|
anEntry.setDesc(BLDevice.getDescOfType(broadlinkObject.getDeviceType()));
|
||||||
|
anEntry.setIpAddr(broadlinkObject.getHost());
|
||||||
|
anEntry.setMacAddr(broadlinkObject.getMac().getMacString());
|
||||||
|
return anEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BLDevice[] broadlinkDiscover () {
|
||||||
|
BLDevice[] clients = null;
|
||||||
|
int aDiscoverPort = Configuration.BROADLINK_DISCOVER_PORT;
|
||||||
|
broadlinkMap = new HashMap<String, BLDevice>();
|
||||||
|
while(aDiscoverPort > 0) {
|
||||||
|
try {
|
||||||
|
log.info("Broadlink discover....");
|
||||||
|
if(isDevMode) {
|
||||||
|
clients = TestBLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clients = BLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||||
|
for(int i = 0; i < clients.length; i++) {
|
||||||
|
if(clients[i].getDeviceType() != BLDevice.DEV_A1 && broadlinkMap.get(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType())) == null) {
|
||||||
|
broadlinkMap.put(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType()), clients[i]);
|
||||||
|
log.debug("Adding Device to Map - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||||
|
} else {
|
||||||
|
log.debug("Ignoring Device (already in the list or an A1 Device) - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aDiscoverPort = 0;
|
||||||
|
} catch (BindException e) {
|
||||||
|
log.warn("Could not discover Broadlinks, Port in use, increasing by 11");
|
||||||
|
aDiscoverPort += 11;
|
||||||
|
if(aDiscoverPort > Configuration.BROADLINK_DISCOVER_PORT + 110)
|
||||||
|
aDiscoverPort = 0;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not discover Broadlinks, with IO Exception", e);
|
||||||
|
broadlinkMap = null;
|
||||||
|
aDiscoverPort = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(clients == null || clients.length <= 0) {
|
||||||
|
log.warn("Did not discover any Broadlinks.");
|
||||||
|
broadlinkMap = null;
|
||||||
|
} else {
|
||||||
|
log.info("Broadlink discover found " + clients.length + " clients.");
|
||||||
|
}
|
||||||
|
return clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
if(!validBroadlink)
|
||||||
|
return;
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(broadlinkMap != null) {
|
||||||
|
broadlinkMap.clear();
|
||||||
|
broadlinkMap = null;
|
||||||
|
}
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.mob41.blapi.BLDevice;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||||
|
|
||||||
|
public class TestBLDevice extends BLDevice {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestBLDevice.class);
|
||||||
|
|
||||||
|
protected TestBLDevice(short deviceType, String deviceDesc, String host, Mac mac) throws IOException {
|
||||||
|
super(deviceType, deviceDesc, host, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(boolean aState) {
|
||||||
|
log.info("setState called with " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(int anIndex, boolean aState) {
|
||||||
|
log.info("setState called with index " + anIndex + " and state " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPower(boolean aState) {
|
||||||
|
log.info("setPower called with " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||||
|
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BLDevice[] discoverDevices(InetAddress theAddress, int aport, int timeout) {
|
||||||
|
TestMP1Device mp1Device = null;
|
||||||
|
TestSP1Device sp1Device = null;
|
||||||
|
TestSP2Device sp2Device = null;
|
||||||
|
TestRM2Device rm2Device = null;
|
||||||
|
try {
|
||||||
|
mp1Device = new TestMP1Device("mp1host", null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sp1Device = new TestSP1Device("sp1host", null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sp2Device = new TestSP2Device("sp2host", null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
rm2Device = new TestRM2Device("rm2host", null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
BLDevice[] devices = { mp1Device, sp1Device, sp2Device, rm2Device };
|
||||||
|
log.info("Created test devices");
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.mob41.blapi.MP1Device;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||||
|
|
||||||
|
public class TestMP1Device extends MP1Device {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestMP1Device.class);
|
||||||
|
|
||||||
|
protected TestMP1Device(String host, Mac mac) throws IOException {
|
||||||
|
super(host, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(int anIndex, boolean aState) {
|
||||||
|
log.info("setState called with index " + anIndex + " and state " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||||
|
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.mob41.blapi.RM2Device;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||||
|
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
|
||||||
|
|
||||||
|
public class TestRM2Device extends RM2Device {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestRM2Device.class);
|
||||||
|
|
||||||
|
protected TestRM2Device(String host, Mac mac) throws IOException {
|
||||||
|
super(host, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||||
|
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(((SendDataCmdPayload)aCmd).getData()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.mob41.blapi.SP1Device;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||||
|
|
||||||
|
public class TestSP1Device extends SP1Device {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestSP1Device.class);
|
||||||
|
|
||||||
|
protected TestSP1Device(String host, Mac mac) throws IOException {
|
||||||
|
super(host, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPower(boolean aState) {
|
||||||
|
log.info("setPower called with " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||||
|
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.broadlink;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.util.HexLibrary;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.mob41.blapi.SP2Device;
|
||||||
|
import com.github.mob41.blapi.mac.Mac;
|
||||||
|
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||||
|
|
||||||
|
public class TestSP2Device extends SP2Device {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestSP2Device.class);
|
||||||
|
|
||||||
|
protected TestSP2Device(String host, Mac mac) throws IOException {
|
||||||
|
super(host, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(boolean aState) {
|
||||||
|
log.info("setState called with " + aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||||
|
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,10 @@ 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;
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ public class DomoticzHandler {
|
|||||||
theUrl = buildUrl(rootRequest + type + postpend);
|
theUrl = buildUrl(rootRequest + type + postpend);
|
||||||
else
|
else
|
||||||
theUrl = buildUrl(rootRequest + type);
|
theUrl = buildUrl(rootRequest + type);
|
||||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, buildHeaders());
|
theData = httpClient.doHttpRequest(theUrl, null, null, null, httpClient.addBasicAuthHeader(null, domoticzAddress));
|
||||||
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);
|
||||||
@@ -76,15 +74,7 @@ public class DomoticzHandler {
|
|||||||
String newUrl = null;
|
String newUrl = null;
|
||||||
|
|
||||||
if(thePayload != null && !thePayload.isEmpty()) {
|
if(thePayload != null && !thePayload.isEmpty()) {
|
||||||
if(domoticzAddress.getSecure() != null && domoticzAddress.getSecure())
|
newUrl = domoticzAddress.getHttpPreamble();
|
||||||
newUrl = "https://";
|
|
||||||
else
|
|
||||||
newUrl = "http://";
|
|
||||||
|
|
||||||
newUrl = newUrl + domoticzAddress.getIp();
|
|
||||||
|
|
||||||
if(domoticzAddress.getPort() != null && !domoticzAddress.getPort().isEmpty())
|
|
||||||
newUrl = newUrl + ":" + domoticzAddress.getPort();
|
|
||||||
|
|
||||||
if(thePayload.startsWith("/"))
|
if(thePayload.startsWith("/"))
|
||||||
newUrl = newUrl + thePayload;
|
newUrl = newUrl + thePayload;
|
||||||
@@ -95,21 +85,6 @@ public class DomoticzHandler {
|
|||||||
return newUrl;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
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;
|
||||||
@@ -17,8 +17,13 @@ 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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
|
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.plugins.http.HTTPHandler;
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class DomoticzHome implements Home {
|
public class DomoticzHome implements Home {
|
||||||
@@ -26,17 +31,20 @@ public class DomoticzHome implements Home {
|
|||||||
private Map<String, DomoticzHandler> domoticzs;
|
private Map<String, DomoticzHandler> domoticzs;
|
||||||
private Boolean validDomoticz;
|
private Boolean validDomoticz;
|
||||||
private HTTPHandler httpClient;
|
private HTTPHandler httpClient;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
|
public DomoticzHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItems(String type) {
|
public Object getItems(String type) {
|
||||||
if(!validDomoticz)
|
if(!validDomoticz)
|
||||||
return null;
|
return null;
|
||||||
log.debug("consolidating devices for hues");
|
log.debug("consolidating devices for Domoticzs");
|
||||||
List<DomoticzDevice> theResponse = null;
|
List<DomoticzDevice> theResponse = null;
|
||||||
Iterator<String> keys = domoticzs.keySet().iterator();
|
Iterator<String> keys = domoticzs.keySet().iterator();
|
||||||
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
|
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
|
||||||
@@ -58,9 +66,14 @@ public class DomoticzHome implements Home {
|
|||||||
return deviceList;
|
return deviceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
private Boolean addDomoticzDevices(List<DomoticzDevice> theDeviceList, List<DomoticzDevice> theSourceList, String theKey) {
|
private Boolean addDomoticzDevices(List<DomoticzDevice> theDeviceList, List<DomoticzDevice> theSourceList, String theKey) {
|
||||||
if(!validDomoticz)
|
if(!validDomoticz)
|
||||||
return null;
|
return false;
|
||||||
Iterator<DomoticzDevice> devices = theSourceList.iterator();
|
Iterator<DomoticzDevice> devices = theSourceList.iterator();
|
||||||
while(devices.hasNext()) {
|
while(devices.hasNext()) {
|
||||||
DomoticzDevice theDevice = devices.next();
|
DomoticzDevice theDevice = devices.next();
|
||||||
@@ -71,11 +84,11 @@ 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, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
Devices theDomoticzApiResponse = null;
|
Devices theDomoticzApiResponse = null;
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
|
|
||||||
String theUrl = anItem.getItem().getAsString();
|
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
||||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
@@ -90,7 +103,23 @@ public class DomoticzHome implements Home {
|
|||||||
String theData;
|
String theData;
|
||||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
|
||||||
intensity, targetBri, targetBriInc, false);
|
intensity, targetBri, targetBriInc, false);
|
||||||
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, null, theHandler.buildHeaders());
|
if (colorData != null) {
|
||||||
|
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
|
String aBody = null;
|
||||||
|
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
|
||||||
|
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
|
||||||
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
aBody = ColorDecode.replaceColorData(aBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
|
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
|
||||||
|
aBody = TimeDecode.replaceTimeValue(aBody);
|
||||||
|
}
|
||||||
|
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, aBody, httpClient.addBasicAuthHeader(null, theHandler.getDomoticzAddress()));
|
||||||
try {
|
try {
|
||||||
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
|
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
|
||||||
if(theDomoticzApiResponse.getStatus().equals("OK"))
|
if(theDomoticzApiResponse.getStatus().equals("OK"))
|
||||||
@@ -99,38 +128,38 @@ public class DomoticzHome implements Home {
|
|||||||
log.warn("Call failed for Domoticz " + theHandler.getDomoticzAddress().getName() + " with status " + theDomoticzApiResponse.getStatus() + " for item " + theDomoticzApiResponse.getTitle());
|
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,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Cannot interrpret result from call for Domoticz " + theHandler.getDomoticzAddress().getName() + " as response is not parsable.");
|
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,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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 {
|
} else {
|
||||||
log.warn("Domoticz Call could not complete, no address found: " + theUrl);
|
log.warn("Domoticz Call could not complete, no address found: " + theUrl);
|
||||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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 {
|
} else {
|
||||||
log.warn("Domoticz Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
|
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,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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);
|
||||||
}
|
}
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
validDomoticz = bridgeSettings.isValidDomoticz();
|
validDomoticz = bridgeSettings.getBridgeSettingsDescriptor().isValidDomoticz();
|
||||||
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();
|
httpClient = HTTPHome.getHandler();
|
||||||
domoticzs = new HashMap<String, DomoticzHandler>();
|
domoticzs = new HashMap<String, DomoticzHandler>();
|
||||||
Iterator<NamedIP> theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getDomoticzaddress().getDevices().iterator();
|
||||||
while(theList.hasNext()) {
|
while(theList.hasNext()) {
|
||||||
NamedIP aDomoticz = theList.next();
|
NamedIP aDomoticz = theList.next();
|
||||||
try {
|
try {
|
||||||
@@ -161,8 +190,16 @@ public class DomoticzHome implements Home {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed || !validDomoticz) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(httpClient != null)
|
if(httpClient != null)
|
||||||
httpClient.closeHandler();
|
httpClient.closeHandler();
|
||||||
|
|
||||||
|
domoticzs = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,55 @@
|
|||||||
package com.bwssystems.HABridge.plugins.exec;
|
package com.bwssystems.HABridge.plugins.exec;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.Home;
|
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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
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 CommandHome implements Home {
|
public class CommandHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CommandHome.class);
|
private static final Logger log = LoggerFactory.getLogger(CommandHome.class);
|
||||||
|
private BridgeSettings theSettings;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public CommandHome(BridgeSettingsDescriptor bridgeSettings) {
|
public CommandHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int itensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
log.debug("Exec Request called with url: " + anItem.getItem().getAsString());
|
String theItem = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
|
log.debug("Exec Request called with url: {} and exec Garden: {}", theItem, (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
String intermediate;
|
String intermediate;
|
||||||
if (anItem.getItem().getAsString().contains("exec://"))
|
if (theItem.contains("exec://"))
|
||||||
intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
intermediate = theItem.substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
||||||
else
|
else
|
||||||
intermediate = anItem.getItem().getAsString();
|
intermediate = theItem;
|
||||||
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
|
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
intermediate = ColorDecode.replaceColorData(intermediate, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
||||||
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
||||||
|
String execGarden = theSettings.getBridgeSecurity().getExecGarden();
|
||||||
|
if(execGarden != null && !execGarden.trim().isEmpty()) {
|
||||||
|
intermediate = new File(execGarden.trim(), intermediate).getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
String anError = doExecRequest(intermediate, lightId);
|
String anError = doExecRequest(intermediate, lightId);
|
||||||
if (anError != null) {
|
if (anError != null) {
|
||||||
responseString = anError;
|
responseString = anError;
|
||||||
@@ -49,24 +65,25 @@ public class CommandHome implements Home {
|
|||||||
Process p = Runtime.getRuntime().exec(anItem);
|
Process p = Runtime.getRuntime().exec(anItem);
|
||||||
log.debug("Process running: " + p.isAlive());
|
log.debug("Process running: " + p.isAlive());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn("Could not execute request: " + anItem, e);
|
log.warn("Could not execute request: " + anItem + " with message: " + e.getMessage());
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
||||||
+ "state\"}}]";
|
+ "/state\"}}]";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("Could not execute request. Request is empty.");
|
log.warn("Could not execute request. Request is empty.");
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
||||||
+ "state\"}}]";
|
+ "/state\"}}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
log.info("Command Home for system program execution created.");
|
log.info("Command Home for system program execution created.");
|
||||||
|
this.theSettings = bridgeSettings;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,9 +94,19 @@ public class CommandHome implements Home {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void refresh() {
|
||||||
// noop
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
public class FHEMCommand {
|
||||||
|
private String url;
|
||||||
|
private String command;
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
public void setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
public class FHEMDevice {
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
private String name;
|
||||||
|
private Result item;
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Result getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
public void setItem(Result item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
218
src/main/java/com/bwssystems/HABridge/plugins/fhem/FHEMHome.java
Normal file
218
src/main/java/com/bwssystems/HABridge/plugins/fhem/FHEMHome.java
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
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.BridgeSettings;
|
||||||
|
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.api.hue.HueError;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HttpTestHandler;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
public class FHEMHome implements Home {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FHEMHome.class);
|
||||||
|
private Map<String, FHEMInstance> fhemMap;
|
||||||
|
private Boolean validFhem;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
private HTTPHandler httpClient;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
|
public FHEMHome(BridgeSettings bridgeSettings) {
|
||||||
|
super();
|
||||||
|
closed = true;
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
|
|
||||||
|
JsonElement jsonUrl = anItem.getItem();
|
||||||
|
String theUrl = jsonUrl.toString();
|
||||||
|
String responseString = null;
|
||||||
|
|
||||||
|
if(theUrl != null && !theUrl.isEmpty()) {
|
||||||
|
FHEMCommand theCommand = null;
|
||||||
|
try {
|
||||||
|
if(anItem.getItem().isJsonObject())
|
||||||
|
theCommand = new Gson().fromJson(anItem.getItem(), FHEMCommand.class);
|
||||||
|
else
|
||||||
|
theCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), FHEMCommand.class);
|
||||||
|
} catch(Exception e) {
|
||||||
|
log.warn("Cannot parse command to FHEM <<<" + theUrl + ">>>", e);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().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;
|
||||||
|
FHEMInstance theHandler = findHandlerByAddress(hostAddr);
|
||||||
|
if(theHandler != null) {
|
||||||
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
|
||||||
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
|
String aCommand = null;
|
||||||
|
if(theCommand.getCommand() != null && !theCommand.getCommand().isEmpty()) {
|
||||||
|
aCommand = BrightnessDecode.calculateReplaceIntensityValue(theCommand.getCommand(),
|
||||||
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
aCommand = ColorDecode.replaceColorData(aCommand, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
|
aCommand = DeviceDataDecode.replaceDeviceData(aCommand, device);
|
||||||
|
aCommand = TimeDecode.replaceTimeValue(aCommand);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
theHandler.callCommand(anUrl, aCommand, httpClient);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Cannot send comand to FHEM", e);
|
||||||
|
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("FHEM 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("FHEM 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FHEMInstance findHandlerByAddress(String hostAddress) {
|
||||||
|
FHEMInstance aHandler = null;
|
||||||
|
boolean found = false;
|
||||||
|
Iterator<String> keys = fhemMap.keySet().iterator();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
aHandler = fhemMap.get(key);
|
||||||
|
if(aHandler != null && aHandler.getFhemAddress().getIp().equals(hostAddress)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
aHandler = null;
|
||||||
|
return aHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItems(String type) {
|
||||||
|
|
||||||
|
if(!validFhem)
|
||||||
|
return null;
|
||||||
|
log.debug("consolidating devices for FHEM");
|
||||||
|
List<FHEMDevice> theResponse = null;
|
||||||
|
Iterator<String> keys = fhemMap.keySet().iterator();
|
||||||
|
List<FHEMDevice> deviceList = new ArrayList<FHEMDevice>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
theResponse = fhemMap.get(key).getDevices(httpClient);
|
||||||
|
if(theResponse != null)
|
||||||
|
addFHEMDevices(deviceList, theResponse, key);
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get devices for FHEM: " + key + ", skipping this FHEM.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean addFHEMDevices(List<FHEMDevice> theDeviceList, List<FHEMDevice> theSourceList, String theKey) {
|
||||||
|
Iterator<FHEMDevice> devices = theSourceList.iterator();
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
FHEMDevice theDevice = devices.next();
|
||||||
|
theDeviceList.add(theDevice);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
|
fhemMap = null;
|
||||||
|
validFhem = bridgeSettings.getBridgeSettingsDescriptor().isValidFhem();
|
||||||
|
log.info("FHEM Home created." + (validFhem ? "" : " No FHEMs configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||||
|
if(validFhem) {
|
||||||
|
fhemMap = new HashMap<String,FHEMInstance>();
|
||||||
|
httpClient = HTTPHome.getHandler();
|
||||||
|
if(isDevMode) {
|
||||||
|
httpClient = new HttpTestHandler();
|
||||||
|
((HttpTestHandler)httpClient).setTheData("cmd=jsonlist2", FHEMTestData.TestData);
|
||||||
|
((HttpTestHandler)httpClient).setTheData("set", "FHEM Command Received");
|
||||||
|
((HttpTestHandler)httpClient).setTheData(null, "FHEM no match");
|
||||||
|
}
|
||||||
|
httpClient.setCallType(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]);
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getFhemaddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext() && validFhem) {
|
||||||
|
NamedIP aFhem = theList.next();
|
||||||
|
try {
|
||||||
|
fhemMap.put(aFhem.getName(), new FHEMInstance(aFhem));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get FHEM (" + aFhem.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||||
|
validFhem = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(!closed && validFhem) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(httpClient != null)
|
||||||
|
httpClient.closeHandler();
|
||||||
|
|
||||||
|
fhemMap = null;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.NameValue;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class FHEMInstance {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FHEMInstance.class);
|
||||||
|
private NamedIP theFhem;
|
||||||
|
|
||||||
|
public FHEMInstance(NamedIP fhemLocation) {
|
||||||
|
super();
|
||||||
|
theFhem = fhemLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedIP getFhemAddress() {
|
||||||
|
return theFhem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFhemAddress(NamedIP fhemAddress) {
|
||||||
|
this.theFhem = fhemAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
|
||||||
|
String aUrl = null;
|
||||||
|
NameValue[] headers = null;
|
||||||
|
/* Trying new code helpers
|
||||||
|
if(theFhem.getSecure() != null && theFhem.getSecure())
|
||||||
|
aUrl = "https://";
|
||||||
|
else
|
||||||
|
aUrl = "http://";
|
||||||
|
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
|
||||||
|
aUrl = aUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
|
||||||
|
}
|
||||||
|
aUrl = aUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/" + aCommand + commandData;
|
||||||
|
*/
|
||||||
|
// New style http creation
|
||||||
|
aUrl = theFhem.getHttpPreamble() + "/" + aCommand + commandData;
|
||||||
|
headers = httpClient.addBasicAuthHeader(null, theFhem);
|
||||||
|
log.debug("calling FHEM: " + aUrl);
|
||||||
|
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", null, headers);
|
||||||
|
if(theData != null)
|
||||||
|
log.debug("doHttpRequest returned data: <" + theData + ">");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FHEMDevice> getDevices(HTTPHandler httpClient) {
|
||||||
|
List<FHEMDevice> deviceList = null;
|
||||||
|
FHEMItem theFhemStates;
|
||||||
|
String theUrl = null;
|
||||||
|
String theData;
|
||||||
|
NameValue[] headers = null;
|
||||||
|
/* Trying new code helpers
|
||||||
|
if(theFhem.getSecure() != null && theFhem.getSecure())
|
||||||
|
theUrl = "https://";
|
||||||
|
else
|
||||||
|
theUrl = "http://";
|
||||||
|
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
|
||||||
|
theUrl = theUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
|
||||||
|
}
|
||||||
|
theUrl = theUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/fhem?cmd=jsonlist2";
|
||||||
|
*/
|
||||||
|
theUrl = theFhem.getHttpPreamble() + "/fhem?cmd=jsonlist2";
|
||||||
|
headers = httpClient.addBasicAuthHeader(null, theFhem);
|
||||||
|
if(theFhem.getWebhook() != null && !theFhem.getWebhook().trim().isEmpty())
|
||||||
|
theUrl = theUrl + "%20room=" + theFhem.getWebhook().trim();
|
||||||
|
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||||
|
if(theData != null) {
|
||||||
|
log.debug("GET FHEM States - data: " + theData);
|
||||||
|
theData = getJSONData(theData);
|
||||||
|
theFhemStates = new Gson().fromJson(theData, FHEMItem.class);
|
||||||
|
if(theFhemStates == null) {
|
||||||
|
log.warn("Cannot get any devices for FHEM " + theFhem.getName() + " as response is not parsable.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deviceList = new ArrayList<FHEMDevice>();
|
||||||
|
|
||||||
|
for (Result aResult:theFhemStates.getResults()) {
|
||||||
|
String name = aResult.getName();
|
||||||
|
if(name.contains("<a href=")) {
|
||||||
|
name = name.substring(name.indexOf("<a href=") + name.indexOf(">"));
|
||||||
|
name = name.substring(1, name.indexOf("</a"));
|
||||||
|
aResult.setName(name);
|
||||||
|
}
|
||||||
|
FHEMDevice aNewFhemDeviceDevice = new FHEMDevice();
|
||||||
|
aNewFhemDeviceDevice.setItem(aResult);
|
||||||
|
aNewFhemDeviceDevice.setAddress(theFhem.getIp() + ":" + theFhem.getPort());
|
||||||
|
aNewFhemDeviceDevice.setName(theFhem.getName());
|
||||||
|
deviceList.add(aNewFhemDeviceDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("Cannot get an devices for FHEM " + theFhem.getName() + " http call failed.");
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJSONData(String response) {
|
||||||
|
String theData;
|
||||||
|
theData = response.substring(response.indexOf("<pre>") + 4);
|
||||||
|
theData = theData.substring(1, theData.indexOf("</pre>") - 1);
|
||||||
|
theData = theData.replace("\n", "");
|
||||||
|
theData = theData.replace("\r", "");
|
||||||
|
theData = theData.replace("<a href=\"", "<a href=\\\"");
|
||||||
|
theData = theData.replace("\">", "\\\">");
|
||||||
|
return theData;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void closeClient() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class FHEMItem {
|
||||||
|
|
||||||
|
@SerializedName("Arg")
|
||||||
|
@Expose
|
||||||
|
private String arg;
|
||||||
|
@SerializedName("Results")
|
||||||
|
@Expose
|
||||||
|
private List<Result> results = null;
|
||||||
|
@SerializedName("totalResultsReturned")
|
||||||
|
@Expose
|
||||||
|
private Integer totalResultsReturned;
|
||||||
|
|
||||||
|
public String getArg() {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArg(String arg) {
|
||||||
|
this.arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Result> getResults() {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResults(List<Result> results) {
|
||||||
|
this.results = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getTotalResultsReturned() {
|
||||||
|
return totalResultsReturned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalResultsReturned(Integer totalResultsReturned) {
|
||||||
|
this.totalResultsReturned = totalResultsReturned;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
public class FHEMTestData {
|
||||||
|
public final static String TestData = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
|
||||||
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
|
||||||
|
" <head root=\"/fhem\">\n" +
|
||||||
|
" <title>Home, Sweet Home</title>\n" +
|
||||||
|
" <link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
|
||||||
|
" <meta charset=\"UTF-8\">\n" +
|
||||||
|
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
|
||||||
|
" <link href=\"/fhem/pgm2/style.css?v=1513026539\" rel=\"stylesheet\"/>\n" +
|
||||||
|
" <link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_colorpicker.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_fbcalllist.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_knob.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsHistory.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_sortable.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_uzsu.js\"></script>\n" +
|
||||||
|
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_weekprofile.js\"></script>\n" +
|
||||||
|
" </head>\n" +
|
||||||
|
" <body name='Home, Sweet Home' fw_id='7880' generated=\"1513272732\" longpoll=\"1\" data-confirmDelete='1' data-confirmJSError='1' data-webName='haBridgeWeb '>\n" +
|
||||||
|
" <div id=\"menuScrollArea\">\n" +
|
||||||
|
" <div>\n" +
|
||||||
|
" <a href=\"/fhem?\">\n" +
|
||||||
|
" <div id=\"logo\"></div>\n" +
|
||||||
|
" </a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" <div id=\"menu\">\n" +
|
||||||
|
" <table>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <table class=\"room roomBlock1\">\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Save_config\">\n" +
|
||||||
|
" <a href=\"/fhem?cmd=save\">Save config</a>\n" +
|
||||||
|
" <a id=\"saveCheck\" class=\"changed\" style=\"visibility:visible\">?</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" </table>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <table class=\"room roomBlock2\">\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Alexa\">\n" +
|
||||||
|
" <a href=\"/fhem?room=Alexa\">Alexa</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_System\">\n" +
|
||||||
|
" <a href=\"/fhem?room=System\">System</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_WG_Zimmer\">\n" +
|
||||||
|
" <a href=\"/fhem?room=WG%2dZimmer\">WG-Zimmer</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_habridge\">\n" +
|
||||||
|
" <a href=\"/fhem?room=habridge\">habridge</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Everything\">\n" +
|
||||||
|
" <a href=\"/fhem?room=all\">\n" +
|
||||||
|
" <img class='icon icoEverything' src=\"/fhem/images/default/icoEverything.png\" alt=\"icoEverything\" title=\"icoEverything\"> Everything\n" +
|
||||||
|
" </a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" </table>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <table class=\"room roomBlock3\">\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Logfile\">\n" +
|
||||||
|
" <a href=\"/fhem/FileLog_logWrapper?dev=Logfile&type=text&file=fhem-2017-12.log\">Logfile</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div>\n" +
|
||||||
|
" <a href=\"/fhem/docs/commandref.html\" target=\"_blank\" >Commandref</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div>\n" +
|
||||||
|
" <a href=\"http://fhem.de/fhem.html#Documentation\" target=\"_blank\" >Remote doc</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Edit_files\">\n" +
|
||||||
|
" <a href=\"/fhem?cmd=style%20list\">Edit files</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Select_style\">\n" +
|
||||||
|
" <a href=\"/fhem?cmd=style%20select\">Select style</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td>\n" +
|
||||||
|
" <div class=\"menu_Event_monitor\">\n" +
|
||||||
|
" <a href=\"/fhem?cmd=style%20eventMonitor\">Event monitor</a>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" </table>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" </table>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" <div id=\"hdr\">\n" +
|
||||||
|
" <table border=\"0\" class=\"header\">\n" +
|
||||||
|
" <tr>\n" +
|
||||||
|
" <td style=\"padding:0\">\n" +
|
||||||
|
" <form method=\"post\" action=\"/fhem\">\n" +
|
||||||
|
" <input type=\"hidden\" name=\"fw_id\" value=\"7880\"/>\n" +
|
||||||
|
" <input type=\"text\" name=\"cmd\" class=\"maininput\" size=\"40\" value=\"\"/>\n" +
|
||||||
|
" </form>\n" +
|
||||||
|
" </td>\n" +
|
||||||
|
" </tr>\n" +
|
||||||
|
" </table>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" <div id='content' >\n" +
|
||||||
|
" <pre>{ \n" +
|
||||||
|
" \"Arg\":\"room=habridge\", \n" +
|
||||||
|
" \"Results\": [ \n" +
|
||||||
|
" { \n" +
|
||||||
|
" \"Name\":\"Arbeitslicht\", \n" +
|
||||||
|
" \"PossibleSets\":\"on off\", \n" +
|
||||||
|
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 readingList setList useSetExtensions disable disabledForIntervals event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride userattr\", \n" +
|
||||||
|
" \"Internals\": { \n" +
|
||||||
|
" \"NAME\": \"Arbeitslicht\", \n" +
|
||||||
|
" \"NR\": \"28\", \n" +
|
||||||
|
" \"STATE\": \"-\", \n" +
|
||||||
|
" \"TYPE\": \"dummy\" \n" +
|
||||||
|
" }, \n" +
|
||||||
|
" \"Readings\": { \"state\": { \"Value\":\"on\", \"Time\":\"2017-12-14 15:41:05\" } }, \n" +
|
||||||
|
" \"Attributes\": { \n" +
|
||||||
|
" \"alexaName\": \"Arbeitslicht\", \n" +
|
||||||
|
" \"alexaRoom\": \"alexaroom\", \n" +
|
||||||
|
" \"fhem_widget_command\": \"{ \\u0022allowed_values\\u0022 : [ \\u0022on\\u0022 ], \\u0022order\\u0022 : 0}\", \n" +
|
||||||
|
" \"icon\": \"scene_office\", \n" +
|
||||||
|
" \"room\": \"Alexa,habridge\", \n" +
|
||||||
|
" \"setList\": \"on off\", \n" +
|
||||||
|
" \"stateFormat\": \"-\", \n" +
|
||||||
|
" \"webCmd\": \"on\" \n" +
|
||||||
|
" } \n" +
|
||||||
|
" }, \n" +
|
||||||
|
" { \n" +
|
||||||
|
" \"Name\":\"DeckenlampeLinks\", \n" +
|
||||||
|
" \"PossibleSets\":\"on off dim dimup dimdown HSV RGB sync pair unpair\", \n" +
|
||||||
|
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 gamma dimStep defaultColor defaultRamp colorCast whitePoint event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride \n" +
|
||||||
|
" <a href=\"/fhem?detail=AlleLampen\">AlleLampen</a> AlleLampen_map\n" +
|
||||||
|
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude userattr\", \n" +
|
||||||
|
" \"Internals\": { \n" +
|
||||||
|
" \"CONNECTION\": \"bridge-V3\", \n" +
|
||||||
|
" \"DEF\": \"RGBW2 bridge-V3:10.2.3.3\", \n" +
|
||||||
|
" \"IP\": \"10.2.3.3\", \n" +
|
||||||
|
" \"LEDTYPE\": \"RGBW2\", \n" +
|
||||||
|
" \"NAME\": \"DeckenlampeLinks\", \n" +
|
||||||
|
" \"NR\": \"18\", \n" +
|
||||||
|
" \"NTFY_ORDER\": \"50-DeckenlampeLinks\", \n" +
|
||||||
|
" \"PORT\": \"8899\", \n" +
|
||||||
|
" \"PROTO\": \"0\", \n" +
|
||||||
|
" \"SLOT\": \"5\", \n" +
|
||||||
|
" \"STATE\": \"off\", \n" +
|
||||||
|
" \"TYPE\": \"WifiLight\" \n" +
|
||||||
|
" }, \n" +
|
||||||
|
" \"Readings\": { \n" +
|
||||||
|
" \"RGB\": { \"Value\":\"000000\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||||
|
" \"brightness\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||||
|
" \"hue\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||||
|
" \"saturation\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||||
|
" \"state\": { \"Value\":\"off\", \"Time\":\"2017-12-14 15:41:10\" } \n" +
|
||||||
|
" }, \n" +
|
||||||
|
" \"Attributes\": { \n" +
|
||||||
|
" \"AlleLampen\": \"AlleLampen\", \n" +
|
||||||
|
" \"DeckenLampen\": \"DeckenLampen\", \n" +
|
||||||
|
" \"fhem_widget_command\": \"{ \\u0022locations\\u0022 : [ \\u0022APP\\u0022, \\u0022WATCH\\u0022, \\u0022WIDGET\\u0022 ], \\u0022allowed_values\\u0022 : [ \\u0022off\\u0022, \\u0022on\\u0022 ], \\u0022order\\u0022 : 6}\", \n" +
|
||||||
|
" \"room\": \"habridge,Alexa,WG-Zimmer\", \n" +
|
||||||
|
" \"userattr\": \"AlleLampen AlleLampen_map\n" +
|
||||||
|
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude\", \n" +
|
||||||
|
" \"webCmd\": \"RGB\", \n" +
|
||||||
|
" \"widgetOverride\": \"RGB:colorpicker,RGB\" \n" +
|
||||||
|
" } \n" +
|
||||||
|
" } ], \n" +
|
||||||
|
" \"totalResultsReturned\":2 \n" +
|
||||||
|
"}\n" +
|
||||||
|
" </pre>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </body>\n" +
|
||||||
|
"</html>";
|
||||||
|
|
||||||
|
public final static String TestData2 = " <div id='content' >\n" +
|
||||||
|
" <pre>\n" + "{ \"Arg\":\"room=HaBridge\", \"Results\": [ { \"Name\":\"wifi_steckdose3\", \"PossibleSets\":\"on:noArg off:noArg off on toggle\", \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\", \"Internals\": { \"CHANGED\": \"null\", \"NAME\": \"wifi_steckdose3\", \"NR\": \"270\", \"STATE\": \"off\", \"TYPE\": \"MQTT_DEVICE\", \"retain\": \"*:1 \" }, \"Readings\": { \"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-01 23:01:21\" }, \"transmission-state\": { \"Value\":\"subscription acknowledged\", \"Time\":\"2018-01-03 22:34:00\" } }, \"Attributes\": { \"IODev\": \"myBroker\", \"alias\": \"Stecki\", \"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\", \"event-on-change-reading\": \"state\", \"eventMap\": \"ON:on OFF:off\", \"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\", \"retain\": \"1\", \"room\": \"HaBridge,Arbeitszimmer,mqtt\", \"stateFormat\": \"state\", \"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\", \"webCmd\": \"on:off:toggle\" } } ], \"totalResultsReturned\":1 }" +
|
||||||
|
" </pre>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </body>\n" +
|
||||||
|
"</html>";
|
||||||
|
public final static String TestData3 ="DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
|
||||||
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
|
||||||
|
"<head root=\"/fhem\">\n" +
|
||||||
|
"<title>Home, Sweet Home</title>\n" +
|
||||||
|
"<link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
|
||||||
|
"<meta charset=\"UTF-8\">\n" +
|
||||||
|
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
|
||||||
|
"<link href=\"/fhem/pgm2/style.css?v=1515015198\" rel=\"stylesheet\"/>\n" +
|
||||||
|
"<link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/doif.js\"></script>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fronthemEditor.js\"></script>\n" +
|
||||||
|
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
|
||||||
|
"</head>\n" +
|
||||||
|
"<body name='Home, Sweet Home' fw_id='1490' generated=\"1515770038\" longpoll=\"websocket\" data-confirmDelete='1' data-confirmJSError='1' data-addHtmlTitle='1' data-availableJs='sortable,iconLabel,readingsHistory,colorpicker,iconButtons,fbcalllist,knob,weekprofile,iconRadio,readingsGroup,iconSwitch,uzsu' data-webName='WEB '>\n" +
|
||||||
|
"<div id=\"menuScrollArea\">\n" +
|
||||||
|
"</div>\n" +
|
||||||
|
"<div id='content' >\n" +
|
||||||
|
"<pre>{\n" +
|
||||||
|
"\"Arg\":\"room=HaBridge\",\n" +
|
||||||
|
"\"Results\": [\n" +
|
||||||
|
"{\n" +
|
||||||
|
"\"Name\":\"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
|
||||||
|
"\"PossibleSets\":\"on:noArg off:noArg off on toggle\",\n" +
|
||||||
|
"\"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\",\n" +
|
||||||
|
"\"Internals\": {\n" +
|
||||||
|
"\"NAME\": \"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
|
||||||
|
"\"NR\": \"270\",\n" +
|
||||||
|
"\"STATE\": \"off\",\n" +
|
||||||
|
"\"TYPE\": \"MQTT_DEVICE\",\n" +
|
||||||
|
"\"retain\": \"*:1 \"\n" +
|
||||||
|
"},\n" +
|
||||||
|
"\"Readings\": {\n" +
|
||||||
|
"\"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-07 05:16:01\" },\n" +
|
||||||
|
"\"transmission-state\": { \"Value\":\"incoming publish received\", \"Time\":\"2018-01-07 05:16:01\" }\n" +
|
||||||
|
"},\n" +
|
||||||
|
"\"Attributes\": {\n" +
|
||||||
|
"\"IODev\": \"<a href='/fhem?detail=myBroker'>myBroker</a>\",\n" +
|
||||||
|
"\"alias\": \"Stecki\",\n" +
|
||||||
|
"\"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\",\n" +
|
||||||
|
"\"event-on-change-reading\": \"state\",\n" +
|
||||||
|
"\"eventMap\": \"ON:on OFF:off\",\n" +
|
||||||
|
"\"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\",\n" +
|
||||||
|
"\"retain\": \"1\",\n" +
|
||||||
|
"\"room\": \"HaBridge,Arbeitszimmer,mqtt\",\n" +
|
||||||
|
"\"stateFormat\": \"state\",\n" +
|
||||||
|
"\"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\",\n" +
|
||||||
|
"\"webCmd\": \"on:off:toggle\"\n" +
|
||||||
|
"}\n" +
|
||||||
|
"} ],\n" +
|
||||||
|
"\"totalResultsReturned\":1\n" +
|
||||||
|
"}\n" +
|
||||||
|
"</pre>\n" +
|
||||||
|
"</div>\n" +
|
||||||
|
"</body></html>";
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
package com.bwssystems.HABridge.plugins.fhem;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Result {
|
||||||
|
|
||||||
|
@SerializedName("Name")
|
||||||
|
@Expose
|
||||||
|
private String name;
|
||||||
|
@SerializedName("PossibleSets")
|
||||||
|
@Expose
|
||||||
|
private String possibleSets;
|
||||||
|
@SerializedName("PossibleAttrs")
|
||||||
|
@Expose
|
||||||
|
private String possibleAttrs;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPossibleSets() {
|
||||||
|
return possibleSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPossibleSets(String possibleSets) {
|
||||||
|
this.possibleSets = possibleSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPossibleAttrs() {
|
||||||
|
return possibleAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPossibleAttrs(String possibleAttrs) {
|
||||||
|
this.possibleAttrs = possibleAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro;
|
||||||
|
|
||||||
|
public class FibaroFilter {
|
||||||
|
boolean useSaveLogs;
|
||||||
|
boolean useUserDescription;
|
||||||
|
boolean scenesLiliCmddOnly;
|
||||||
|
boolean replaceTrash;
|
||||||
|
|
||||||
|
public boolean isUseSaveLogs() {
|
||||||
|
return useSaveLogs;
|
||||||
|
}
|
||||||
|
public void setUseSaveLogs(boolean useSaveLogs) {
|
||||||
|
this.useSaveLogs = useSaveLogs;
|
||||||
|
}
|
||||||
|
public boolean isUseUserDescription() {
|
||||||
|
return useUserDescription;
|
||||||
|
}
|
||||||
|
public void setUseUserDescription(boolean useUserDescription) {
|
||||||
|
this.useUserDescription = useUserDescription;
|
||||||
|
}
|
||||||
|
public boolean isReplaceTrash() {
|
||||||
|
return replaceTrash;
|
||||||
|
}
|
||||||
|
public void setReplaceTrash(boolean replaceTrash) {
|
||||||
|
this.replaceTrash = replaceTrash;
|
||||||
|
}
|
||||||
|
public boolean isScenesLiliCmddOnly() {
|
||||||
|
return scenesLiliCmddOnly;
|
||||||
|
}
|
||||||
|
public void setScenesLiliCmddOnly(boolean scenesLiliCmddOnly) {
|
||||||
|
this.scenesLiliCmddOnly = scenesLiliCmddOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro;
|
||||||
|
|
||||||
|
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.BridgeSettings;
|
||||||
|
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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.json.Device;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.json.Scene;
|
||||||
|
|
||||||
|
public class FibaroHome implements Home
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FibaroHome.class);
|
||||||
|
private Map<String, FibaroInfo> fibaros;
|
||||||
|
private Boolean validFibaro;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
|
public FibaroHome(BridgeSettings bridgeSettings)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
closed = true;
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices()
|
||||||
|
{
|
||||||
|
log.debug("consolidating devices for fibaros");
|
||||||
|
Iterator<String> keys = fibaros.keySet().iterator();
|
||||||
|
ArrayList<Device> deviceList = new ArrayList<>();
|
||||||
|
while(keys.hasNext())
|
||||||
|
{
|
||||||
|
String key = keys.next();
|
||||||
|
for(Device device : fibaros.get(key).getDevices())
|
||||||
|
deviceList.add(device);
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Scene> getScenes()
|
||||||
|
{
|
||||||
|
log.debug("consolidating scenes for fibaros");
|
||||||
|
Iterator<String> keys = fibaros.keySet().iterator();
|
||||||
|
ArrayList<Scene> sceneList = new ArrayList<>();
|
||||||
|
while(keys.hasNext())
|
||||||
|
{
|
||||||
|
String key = keys.next();
|
||||||
|
for(Scene scene : fibaros.get(key).getScenes())
|
||||||
|
sceneList.add(scene);
|
||||||
|
}
|
||||||
|
return sceneList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body)
|
||||||
|
{
|
||||||
|
// Not a device handler
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItems(String type)
|
||||||
|
{
|
||||||
|
if(validFibaro)
|
||||||
|
{
|
||||||
|
if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]))
|
||||||
|
return getDevices();
|
||||||
|
if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex]))
|
||||||
|
return getScenes();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings)
|
||||||
|
{
|
||||||
|
validFibaro = bridgeSettings.getBridgeSettingsDescriptor().isValidFibaro();
|
||||||
|
log.info("Fibaro Home created." + (validFibaro ? "" : " No Fibaros configured."));
|
||||||
|
if(validFibaro)
|
||||||
|
{
|
||||||
|
fibaros = new HashMap<String, FibaroInfo>();
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getFibaroAddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext())
|
||||||
|
{
|
||||||
|
NamedIP aFibaro = theList.next();
|
||||||
|
fibaros.put(aFibaro.getName(), new FibaroInfo(aFibaro));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome()
|
||||||
|
{
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fibaros = null;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.json.Device;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.json.Room;
|
||||||
|
import com.bwssystems.HABridge.plugins.fibaro.json.Scene;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class FibaroInfo
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FibaroInfo.class);
|
||||||
|
|
||||||
|
private final NamedIP fibaroAddress;
|
||||||
|
private final String fibaroAuth;
|
||||||
|
private final Gson gson;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
private FibaroFilter theFilters;
|
||||||
|
|
||||||
|
public FibaroInfo(NamedIP addressName)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
fibaroAddress = addressName;
|
||||||
|
fibaroAuth = "Basic " + addressName.getUserPass64();
|
||||||
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
|
gson = new Gson();
|
||||||
|
theFilters = null;
|
||||||
|
if(fibaroAddress.getExtensions() != null) {
|
||||||
|
try {
|
||||||
|
theFilters = gson.fromJson(fibaroAddress.getExtensions(), FibaroFilter.class);
|
||||||
|
} catch(Exception e) {
|
||||||
|
log.warn("Could not read fibaro filters - continuing with defaults.");
|
||||||
|
theFilters = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(theFilters == null) {
|
||||||
|
theFilters = new FibaroFilter();
|
||||||
|
theFilters.setUseSaveLogs(false);
|
||||||
|
theFilters.setUseUserDescription(false);
|
||||||
|
theFilters.setScenesLiliCmddOnly(false);
|
||||||
|
theFilters.setReplaceTrash(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String request(String request)
|
||||||
|
{
|
||||||
|
String result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setRequestProperty("Authorization", fibaroAuth);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||||
|
connection.connect();
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
buffer.append(line).append("\n");
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
result = buffer.toString();
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
log.warn("Error while get getJson: {} ", request, e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceTrash(String name)
|
||||||
|
{
|
||||||
|
String sanitizedName = name.replaceAll("[0-9:/-]", "");
|
||||||
|
sanitizedName = name.replaceAll("\\s+", " ");
|
||||||
|
return sanitizedName.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Room[] getRooms()
|
||||||
|
{
|
||||||
|
String result = null;
|
||||||
|
if(isDevMode)
|
||||||
|
result = FibaroTestData.RoomTestData;
|
||||||
|
else
|
||||||
|
result = request("/api/rooms");
|
||||||
|
log.debug("getRooms response: <<<" + result + ">>>");
|
||||||
|
Room[] rooms = result == null ? new Room[0] : gson.fromJson(result, Room[].class);
|
||||||
|
if(theFilters.isReplaceTrash())
|
||||||
|
for(Room r : rooms)
|
||||||
|
r.setName(replaceTrash(r.getName()));
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device[] getDevices()
|
||||||
|
{
|
||||||
|
Room[] rooms = getRooms();
|
||||||
|
|
||||||
|
log.debug("getDevices Found: " + rooms.length + " rooms");
|
||||||
|
|
||||||
|
String result = null;
|
||||||
|
if(isDevMode)
|
||||||
|
result = FibaroTestData.DeviceTestData;
|
||||||
|
else
|
||||||
|
result = request("/api/devices?enabled=true&visible=true");
|
||||||
|
log.debug("getDevices response: <<<" + result + ">>>");
|
||||||
|
Device[] all_devices = result == null ? new Device[0] : gson.fromJson(result, Device[].class);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for(Device d : all_devices)
|
||||||
|
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
|
||||||
|
count++;
|
||||||
|
|
||||||
|
Device[] devices = new Device[count];
|
||||||
|
int i = 0;
|
||||||
|
for(Device d : all_devices)
|
||||||
|
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
|
||||||
|
{
|
||||||
|
if(theFilters.isUseUserDescription() && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
|
||||||
|
d.setName(d.getProperties().getUserDescription());
|
||||||
|
if(theFilters.isReplaceTrash())
|
||||||
|
d.setName(replaceTrash(d.getName()));
|
||||||
|
|
||||||
|
devices[i++] = d;
|
||||||
|
|
||||||
|
for(Room room : rooms)
|
||||||
|
if(d.getRoomID() == room.getId())
|
||||||
|
d.setRoomName(room.getName());
|
||||||
|
|
||||||
|
d.fibaroaddress = fibaroAddress.getIp();
|
||||||
|
d.fibaroport = fibaroAddress.getPort();
|
||||||
|
d.fibaroAuth = fibaroAuth;
|
||||||
|
d.fibaroname = fibaroAddress.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("getDevices Found: " + devices.length + " devices");
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scene[] getScenes()
|
||||||
|
{
|
||||||
|
Room[] rooms = getRooms();
|
||||||
|
|
||||||
|
String result = null;
|
||||||
|
if(isDevMode)
|
||||||
|
result = FibaroTestData.SceneTestData;
|
||||||
|
else
|
||||||
|
result = request("/api/scenes?enabled=true&visible=true");
|
||||||
|
log.debug("getScenes response: <<<" + result + ">>>");
|
||||||
|
Scene[] all_scenes = result == null ? new Scene[0] : gson.fromJson(result, Scene[].class);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for(Scene s : all_scenes)
|
||||||
|
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
|
||||||
|
count++;
|
||||||
|
Scene[] scenes = new Scene[count];
|
||||||
|
int i = 0;
|
||||||
|
for(Scene s : all_scenes)
|
||||||
|
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
|
||||||
|
{
|
||||||
|
if(theFilters.isReplaceTrash())
|
||||||
|
s.setName(replaceTrash(s.getName()));
|
||||||
|
|
||||||
|
scenes[i++] = s;
|
||||||
|
|
||||||
|
for(Room room : rooms)
|
||||||
|
if(s.getRoomID() == room.getId())
|
||||||
|
s.setRoomName(room.getName());
|
||||||
|
|
||||||
|
s.fibaroaddress = fibaroAddress.getIp();
|
||||||
|
s.fibaroport = fibaroAddress.getPort();
|
||||||
|
s.fibaroAuth = fibaroAuth;
|
||||||
|
s.fibaroname = fibaroAddress.getName();
|
||||||
|
}
|
||||||
|
log.debug("getScenes Found: " + count + " scenes");
|
||||||
|
return scenes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro;
|
||||||
|
|
||||||
|
public class FibaroTestData {
|
||||||
|
public final static String DeviceTestData = "[{\"id\":7,\"name\":\"Deckenspots\",\"roomID\":12,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":5,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"7.23\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"2\",\"parametersTemplate\":\"796\",\"power\":\"5.80\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"25\",\"serialNumber\":\"h'000000000001c1b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"5\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":1},{\"id\":13,\"name\":\"Licht Küche\",\"roomID\":13,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":fals" +
|
||||||
|
"e,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"9.51\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"16.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":2},{\"id\":14,\"name\":\"Lampe Tisch\",\"roomID\":14,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"2\",\"energy\":\"29.15\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":" +
|
||||||
|
"\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"11.50\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":3},{\"id\":18,\"name\":\"Licht\",\"roomID\":16,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":15,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"2.70\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"4\",\"parametersTemplate\":\"781\",\"power\":\"0.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'00000000000044b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTempl" +
|
||||||
|
"ate\":\"true\",\"userDescription\":\"\",\"value\":\"false\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":4},{\"id\":26,\"name\":\"Licht\",\"roomID\":5,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":24,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"28.02\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"7\",\"parametersTemplate\":\"796\",\"power\":\"0.00\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"h'0000000000001fec\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":5},{\"id\":57,\"name\":\"Fenster rechts\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":56,\"remoteGatewayId\"" +
|
||||||
|
":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.78\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"19\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":12},{\"id\":60,\"name\":\"Fenster mitte\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":59,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlT" +
|
||||||
|
"ype\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.71\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"20\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"26\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":13},{\"id\":74,\"name\":\"Fenster links\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":73,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.64\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"21\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0" +
|
||||||
|
",25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":14},{\"id\":77,\"name\":\"Fenster Sideboard\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":76,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.63\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"22\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneAc" +
|
||||||
|
"tivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":15},{\"id\":112,\"name\":\"Stehlampe\",\"roomID\":12,\"type\":\"com.fibaro.multilevelSwitch\",\"baseType\":\"com.fibaro.binarySwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":111,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Domitech Products\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"5.14\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"5.14\\\"}\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"27\",\"parametersTemplate\":\"807\",\"productInfo\":\"2,14,76,66,49,52,5,14\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"retryUpdate\":1,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":6},{\"id\":114,\"name\":\"RGBW\",\"roomID\":12,\"type\":\"com.fibaro.FGRGBW441M\",\"baseType\":\"com.fibaro.colorController\",\"enabled\":true,\"visible\":tr" +
|
||||||
|
"ue,\"isPlugin\":false,\"parentId\":113,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"26.25\",\"associationMode\":\"0\",\"brightness\":\"0\",\"buttonType\":\"0\",\"color\":\"0,0,0,0\",\"configured\":true,\"currentProgram\":\"0\",\"currentProgramID\":\"0\",\"dead\":\"false\",\"deviceControlType\":\"50\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"1.72\",\"favoriteProgram\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"26.25\\\"}\",\"isLight\":\"true\",\"lastColorSet\":\"0,0,0,0\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"mode\":\"0\",\"model\":\"\",\"nodeId\":\"28\",\"parametersTemplate\":\"231\",\"power\":\"0.00\",\"productInfo\":\"1,15,9,0,16,0,26,25\",\"programsSortOrder\":\"1,2,3,4,5\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"rememberColor\":\"false\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"setB\":1,\"setBrightness\":1,\"setColor\":1,\"setFavoriteProgram\":2,\"setG\":1,\"setR\":1,\"setValue\":1,\"setW\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startProgram\":1,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":7},{\"id\":122,\"name\":\"Fenster\",\"roomID\":12,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":121,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"powe" +
|
||||||
|
"r\",\"zwave\",\"zwaveConfiguration\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"24.24\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.17\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"24.24\\\"}\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"29\",\"parametersTemplate\":\"249\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,1,16,1,24,24\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"abortUpdate\":1,\"close\":0,\"getParameter\":1,\"open\":0,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"sceneActivationSet\":0,\"setParameter\":2,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stop\":0,\"stopLevelChange\":0,\"updateFirmware\":1},\"created\":1516643108,\"modified\":1516643108,\"sortOrder\":16}]";
|
||||||
|
|
||||||
|
public final static String RoomTestData = "[{\"id\":4,\"name\":\"Dachboden\",\"sectionID\":4,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":1},{\"id\":5,\"name\":\"Badezimmer\",\"sectionID\":5,\"icon\":\"room_wanna\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":2},{\"id\":6,\"name\":\"Büro\",\"sectionID\":5,\"icon\":\"room_office\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":3},{\"id\":7,\"name\":\"Flur\",\"sectionID\":5,\"icon\":\"room_schody2\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":4},{\"id\":8,\"name\":\"Schlafzimmer\",\"sectionID\":5,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":5},{\"id\":9,\"name\":\"Emelie\",\"sectionID\":5,\"icon\":\"room_wardrobe\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":6},{\"id\":10,\"name\":\"Mino\",\"sectionID\":5,\"icon\":\"room_garage\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":7},{\"id\":11,\"name\":\"Flur\",\"sectionID\":6,\"icon\":\"room_drzwiwejsciowe\",\"defaultSensors\":{\"temperature\":181,\"humidity\":0,\"light\":182},\"defaultThermostat\":0,\"sortOrder\":8},{\"id\":12,\"name\":\"Wohnzimmer\",\"sectionID\":6,\"icon\":\"room_sofa\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":9},{\"id\":13,\"name\":\"Küche\",\"sectionID\":6,\"icon\":\"room_dining\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":10},{\"id\":14,\"name\":\"Esszimmer\",\"sectionID\":6,\"icon\":\"room_jadalnia\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":11},{\"id\":15,\"name\":\"HWR\",\"sectionID\":6,\"icon\":\"room_laundry\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":12},{\"id\":16,\"name\":\"Gäste WC\",\"sectionID\":6," +
|
||||||
|
"\"icon\":\"room_toilet\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":13},{\"id\":17,\"name\":\"Haus\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":14},{\"id\":18,\"name\":\"Terrasse\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":15}]";
|
||||||
|
|
||||||
|
public final static String SceneTestData = "[" +
|
||||||
|
"{\"id\":33,\"name\":\"Fernsehlicht aus\",\"type\":\"com.fibaro.luaScene\",\"roomID\":12,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":4,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":17}," +
|
||||||
|
"{\"id\":68,\"name\":\"Rollos runterfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":8}," +
|
||||||
|
"{\"id\":69,\"name\":\"Rollos hochfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":9}," +
|
||||||
|
"{\"id\":93,\"name\":\"Alles aus Haus\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent1HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 1 HeldDown\\\\n163 CentralSceneEvent 1 Released\\\",\\\"actionDeviceId\\\":92,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_92\\\",\\\"actionLua\\\":\\\"fibaro:startScene(92);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"1\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[92],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":18}," +
|
||||||
|
"{\"id\":94,\"name\":\"Fernsehlicht an\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":10}," +
|
||||||
|
"{\"id\":95,\"name\":\"Fernsehlicht + aus\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,57,60,74,77,97,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":19}," +
|
||||||
|
"{\"id\":96,\"name\":\"Fernsehlicht Wohnzim\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent2Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 2 Pressed\\\",\\\"actionDeviceId\\\":94,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_94\\\",\\\"actionLua\\\":\\\"fibaro:startScene(94);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"2\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[94],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":20}," +
|
||||||
|
"{\"id\":98,\"name\":\"Fersehlicht blau\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":11}," +
|
||||||
|
"{\"id\":99,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":21}," +
|
||||||
|
"{\"id\":100,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 HeldDown\\\\n163 CentralSceneEvent 3 Released\\\",\\\"actionDeviceId\\\":99,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_99\\\",\\\"actionLua\\\":\\\"fibaro:startScene(99);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[99],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":22}," +
|
||||||
|
"{\"id\":101,\"name\":\"Fersehlicht blau Woh\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 Pressed\\\",\\\"actionDeviceId\\\":98,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_98\\\",\\\"actionLua\\\":\\\"fibaro:startScene(98);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[98],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":23}" +
|
||||||
|
"]";
|
||||||
|
|
||||||
|
public final static String CallActionTestData = "Fiabro action received";
|
||||||
|
public final static String SceneControlTestData = "Fiabro scene control received";
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Device {
|
||||||
|
private String roomName;
|
||||||
|
|
||||||
|
@SerializedName("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName("roomID")
|
||||||
|
private int roomID;
|
||||||
|
|
||||||
|
@SerializedName("type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@SerializedName("properties")
|
||||||
|
private DeviceProperties properties;
|
||||||
|
|
||||||
|
public String getRoomName() {
|
||||||
|
return roomName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomName(String roomName) {
|
||||||
|
this.roomName = roomName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomID() {
|
||||||
|
return roomID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceProperties getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isThermostat() {
|
||||||
|
return type.equals("com.fibaro.setPoint") || type.equals("com.fibaro.thermostatDanfoss")
|
||||||
|
|| type.equals("com.fibaro.thermostatHorstmann");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + id + ", " + name + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fibaroaddress;
|
||||||
|
public String fibaroport;
|
||||||
|
public String fibaroAuth;
|
||||||
|
public String fibaroname;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class DeviceProperties {
|
||||||
|
@SerializedName("value")
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@SerializedName("saveLogs")
|
||||||
|
private String saveLogs;
|
||||||
|
|
||||||
|
@SerializedName("userDescription")
|
||||||
|
private String userDescription;
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public String getSaveLogs() {
|
||||||
|
return saveLogs;
|
||||||
|
}
|
||||||
|
public String getUserDescription() {
|
||||||
|
return userDescription;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Room {
|
||||||
|
@SerializedName("id")
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
@SerializedName("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName("sectionID")
|
||||||
|
private int sectionID;
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSectionID()
|
||||||
|
{
|
||||||
|
return sectionID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Scene {
|
||||||
|
private String roomName;
|
||||||
|
|
||||||
|
@SerializedName("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName("type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@SerializedName("roomID")
|
||||||
|
private int roomID;
|
||||||
|
|
||||||
|
@SerializedName("liliStartCommand")
|
||||||
|
private String liliStartCommand;
|
||||||
|
|
||||||
|
public String getRoomName() {
|
||||||
|
return roomName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomName(String roomName) {
|
||||||
|
this.roomName = roomName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomID() {
|
||||||
|
return roomID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLiliStartCommand()
|
||||||
|
{
|
||||||
|
return liliStartCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + id + ", " + name + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fibaroaddress;
|
||||||
|
public String fibaroport;
|
||||||
|
public String fibaroAuth;
|
||||||
|
public String fibaroname;
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package com.bwssystems.HABridge.plugins.hal;
|
package com.bwssystems.HABridge.plugins.hal;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
|
||||||
public class HalDevice {
|
public class HalDevice {
|
||||||
private String haldevicetype;
|
private String haldevicetype;
|
||||||
private String haldevicename;
|
private String haldevicename;
|
||||||
private String haladdress;
|
private NamedIP haladdress;
|
||||||
private String halname;
|
|
||||||
private DeviceElements buttons;
|
private DeviceElements buttons;
|
||||||
public String getHaldevicetype() {
|
public String getHaldevicetype() {
|
||||||
return haldevicetype;
|
return haldevicetype;
|
||||||
@@ -18,18 +19,12 @@ public class HalDevice {
|
|||||||
public void setHaldevicename(String haldevicename) {
|
public void setHaldevicename(String haldevicename) {
|
||||||
this.haldevicename = haldevicename;
|
this.haldevicename = haldevicename;
|
||||||
}
|
}
|
||||||
public String getHaladdress() {
|
public NamedIP getHaladdress() {
|
||||||
return haladdress;
|
return haladdress;
|
||||||
}
|
}
|
||||||
public void setHaladdress(String haladdress) {
|
public void setHaladdress(NamedIP haladdress) {
|
||||||
this.haladdress = haladdress;
|
this.haladdress = haladdress;
|
||||||
}
|
}
|
||||||
public String getHalname() {
|
|
||||||
return halname;
|
|
||||||
}
|
|
||||||
public void setHalname(String halname) {
|
|
||||||
this.halname = halname;
|
|
||||||
}
|
|
||||||
public DeviceElements getButtons() {
|
public DeviceElements getButtons() {
|
||||||
return buttons;
|
return buttons;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,28 +9,38 @@ import java.util.Map;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
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.ColorData;
|
||||||
|
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.google.gson.Gson;
|
||||||
|
|
||||||
public class HalHome implements Home {
|
public class HalHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||||
private Map<String, HalInfo> hals;
|
private Map<String, HalInfo> hals;
|
||||||
private Boolean validHal;
|
private Boolean validHal;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
|
public HalHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItems(String type) {
|
public Object getItems(String type) {
|
||||||
if(!validHal)
|
if(!validHal)
|
||||||
return null;
|
return null;
|
||||||
log.debug("consolidating devices for hues");
|
log.debug("consolidating devices for HALs");
|
||||||
List<HalDevice> theResponse = null;
|
List<HalDevice> theResponse = null;
|
||||||
Iterator<String> keys = hals.keySet().iterator();
|
Iterator<String> keys = hals.keySet().iterator();
|
||||||
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||||
@@ -94,7 +104,7 @@ public class HalHome implements Home {
|
|||||||
|
|
||||||
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
||||||
if(!validHal)
|
if(!validHal)
|
||||||
return null;
|
return false;
|
||||||
Iterator<HalDevice> devices = theSourceList.iterator();
|
Iterator<HalDevice> devices = theSourceList.iterator();
|
||||||
while(devices.hasNext()) {
|
while(devices.hasNext()) {
|
||||||
HalDevice theDevice = devices.next();
|
HalDevice theDevice = devices.next();
|
||||||
@@ -104,24 +114,84 @@ public class HalHome implements Home {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
public void refresh() {
|
||||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
// noop
|
||||||
// Not a device handler
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
validHal = bridgeSettings.isValidHal();
|
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
|
boolean halFound = false;
|
||||||
|
String responseString = null;
|
||||||
|
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
|
if(theUrl != null && !theUrl.isEmpty () && theUrl.contains("http")) {
|
||||||
|
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||||
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
|
// String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||||
|
// String hostAddr = null;
|
||||||
|
// String port = null;
|
||||||
|
// if (hostPortion.contains(":")) {
|
||||||
|
// hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||||
|
// port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||||
|
// } else
|
||||||
|
// hostAddr = hostPortion;
|
||||||
|
log.debug("executing HUE api request to Http "
|
||||||
|
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
||||||
|
+ anItem.getItem().getAsString());
|
||||||
|
|
||||||
|
String anUrl = null;
|
||||||
|
|
||||||
|
anUrl = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
|
for (Map.Entry<String, HalInfo> entry : hals.entrySet())
|
||||||
|
{
|
||||||
|
if(entry.getValue().getHalAddress().getIp().equals(hostPortion)) {
|
||||||
|
halFound = true;
|
||||||
|
if(entry.getValue().getHalAddress().getSecure()!= null && entry.getValue().getHalAddress().getSecure())
|
||||||
|
anUrl = "https://" + anUrl;
|
||||||
|
else
|
||||||
|
anUrl = "http://" + anUrl;
|
||||||
|
|
||||||
|
if(!anUrl.contains("?Token="))
|
||||||
|
anUrl = anUrl + "?Token=" + entry.getValue().getHalAddress().getPassword();
|
||||||
|
|
||||||
|
log.debug("executing HUE api request to Http "
|
||||||
|
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
||||||
|
+ anUrl);
|
||||||
|
|
||||||
|
if (entry.getValue().deviceCommand(anUrl) == null) {
|
||||||
|
log.warn("Error on calling hal to change device state: " + anUrl);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!halFound) {
|
||||||
|
log.warn("No HAL found to call: " + theUrl);
|
||||||
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
|
"No HAL found.", "/lights/"
|
||||||
|
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||||
|
}
|
||||||
|
return responseString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
|
validHal = bridgeSettings.getBridgeSettingsDescriptor().isValidHal();
|
||||||
log.info("HAL Home created." + (validHal ? "" : " No HAL devices configured."));
|
log.info("HAL Home created." + (validHal ? "" : " No HAL devices configured."));
|
||||||
if(!validHal)
|
if(!validHal)
|
||||||
return null;
|
return null;
|
||||||
hals = new HashMap<String, HalInfo>();
|
hals = new HashMap<String, HalInfo>();
|
||||||
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHaladdress().getDevices().iterator();
|
||||||
while(theList.hasNext()) {
|
while(theList.hasNext()) {
|
||||||
NamedIP aHal = theList.next();
|
NamedIP aHal = theList.next();
|
||||||
try {
|
try {
|
||||||
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
|
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getBridgeSettingsDescriptor().getHaltoken()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Cannot get hal client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
log.error("Cannot get hal client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
@@ -132,7 +202,13 @@ public class HalHome implements Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
// noop
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hals = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
import com.bwssystems.HABridge.util.TextStringFormatter;
|
import com.bwssystems.HABridge.util.TextStringFormatter;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@@ -35,13 +36,13 @@ public class HalInfo {
|
|||||||
private static final String IRDATA_TYPE = "IrData";
|
private static final String IRDATA_TYPE = "IrData";
|
||||||
private HTTPHandler httpClient;
|
private HTTPHandler httpClient;
|
||||||
private NamedIP halAddress;
|
private NamedIP halAddress;
|
||||||
private String theToken;
|
|
||||||
|
|
||||||
public HalInfo(NamedIP addressName, String aGivenToken) {
|
public HalInfo(NamedIP addressName, String aGivenToken) {
|
||||||
super();
|
super();
|
||||||
httpClient = new HTTPHandler();
|
httpClient = HTTPHome.getHandler();
|
||||||
halAddress = addressName;
|
halAddress = addressName;
|
||||||
theToken = aGivenToken;
|
if(halAddress.getPassword() == null || halAddress.getPassword().trim().isEmpty())
|
||||||
|
halAddress.setPassword(aGivenToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<HalDevice> getLights() {
|
public List<HalDevice> getLights() {
|
||||||
@@ -98,12 +99,16 @@ public class HalInfo {
|
|||||||
|
|
||||||
String theUrl = null;
|
String theUrl = null;
|
||||||
String theData;
|
String theData;
|
||||||
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
if(halAddress.getSecure()!= null && halAddress.getSecure())
|
||||||
|
theUrl = "https://";
|
||||||
|
else
|
||||||
|
theUrl = "http://";
|
||||||
|
theUrl = theUrl + halAddress.getIp() + apiType + halAddress.getPassword();
|
||||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||||
if(theData != null) {
|
if(theData != null) {
|
||||||
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||||
if(theHalApiResponse.getDeviceElements() == null) {
|
if(theHalApiResponse == null || theHalApiResponse.getDeviceElements() == null) {
|
||||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||||
if(theStatus.getStatus() == null) {
|
if(theStatus.getStatus() == null) {
|
||||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
||||||
@@ -121,8 +126,10 @@ public class HalInfo {
|
|||||||
HalDevice aNewHalDevice = new HalDevice();
|
HalDevice aNewHalDevice = new HalDevice();
|
||||||
aNewHalDevice.setHaldevicetype(deviceType);
|
aNewHalDevice.setHaldevicetype(deviceType);
|
||||||
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||||
aNewHalDevice.setHaladdress(halAddress.getIp());
|
NamedIP theaddress = new NamedIP();
|
||||||
aNewHalDevice.setHalname(halAddress.getName());
|
theaddress.setIp(halAddress.getIp());
|
||||||
|
theaddress.setName(halAddress.getName());
|
||||||
|
aNewHalDevice.setHaladdress(theaddress);
|
||||||
deviceList.add(aNewHalDevice);
|
deviceList.add(aNewHalDevice);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -145,7 +152,11 @@ public class HalInfo {
|
|||||||
deviceList = new ArrayList<HalDevice>();
|
deviceList = new ArrayList<HalDevice>();
|
||||||
while (theHalDevices.hasNext()) {
|
while (theHalDevices.hasNext()) {
|
||||||
HalDevice theHalDevice = theHalDevices.next();
|
HalDevice theHalDevice = theHalDevices.next();
|
||||||
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
if(halAddress.getSecure()!= null && halAddress.getSecure())
|
||||||
|
theUrl = "https://";
|
||||||
|
else
|
||||||
|
theUrl = "http://";
|
||||||
|
theUrl = theUrl + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + halAddress.getPassword();
|
||||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||||
if (theData != null) {
|
if (theData != null) {
|
||||||
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||||
@@ -177,6 +188,12 @@ public class HalInfo {
|
|||||||
return deviceList;
|
return deviceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String deviceCommand(String theUrl) {
|
||||||
|
String theData = null;
|
||||||
|
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||||
|
return theData;
|
||||||
|
}
|
||||||
|
|
||||||
public NamedIP getHalAddress() {
|
public NamedIP getHalAddress() {
|
||||||
return halAddress;
|
return halAddress;
|
||||||
}
|
}
|
||||||
@@ -190,6 +207,5 @@ public class HalInfo {
|
|||||||
httpClient.closeHandler();
|
httpClient.closeHandler();
|
||||||
httpClient = null;
|
httpClient = null;
|
||||||
halAddress = null;
|
halAddress = null;
|
||||||
theToken = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ public class ButtonPress {
|
|||||||
private Integer delay;
|
private Integer delay;
|
||||||
private Integer count;
|
private Integer count;
|
||||||
private String hub;
|
private String hub;
|
||||||
|
private Integer pressTime;
|
||||||
public String getDevice() {
|
public String getDevice() {
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
@@ -43,4 +44,10 @@ public class ButtonPress {
|
|||||||
public void setHub(String hub) {
|
public void setHub(String hub) {
|
||||||
this.hub = hub;
|
this.hub = hub;
|
||||||
}
|
}
|
||||||
|
public Integer getPressTime() {
|
||||||
|
return pressTime;
|
||||||
|
}
|
||||||
|
public void setPressTime(Integer pressTime) {
|
||||||
|
this.pressTime = pressTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import net.whistlingfish.harmony.HarmonyClient;
|
|||||||
import net.whistlingfish.harmony.config.Activity;
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
import net.whistlingfish.harmony.config.Device;
|
import net.whistlingfish.harmony.config.Device;
|
||||||
import net.whistlingfish.harmony.config.HarmonyConfig;
|
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
|
||||||
public class HarmonyHandler {
|
public class HarmonyHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||||
@@ -16,8 +17,9 @@ public class HarmonyHandler {
|
|||||||
private Boolean noopCalls;
|
private Boolean noopCalls;
|
||||||
private Boolean devMode;
|
private Boolean devMode;
|
||||||
private DevModeResponse devResponse;
|
private DevModeResponse devResponse;
|
||||||
|
private NamedIP myNameAndIP;
|
||||||
|
|
||||||
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
|
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting, NamedIP aNameAndIP) {
|
||||||
super();
|
super();
|
||||||
noopCalls = noopCallsSetting;
|
noopCalls = noopCallsSetting;
|
||||||
devMode = Boolean.TRUE;
|
devMode = Boolean.TRUE;
|
||||||
@@ -27,6 +29,7 @@ public class HarmonyHandler {
|
|||||||
else
|
else
|
||||||
devResponse = devResponseSetting;
|
devResponse = devResponseSetting;
|
||||||
harmonyClient = theClient;
|
harmonyClient = theClient;
|
||||||
|
myNameAndIP = aNameAndIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Activity> getActivities() {
|
public List<Activity> getActivities() {
|
||||||
@@ -34,7 +37,16 @@ public class HarmonyHandler {
|
|||||||
if(devMode)
|
if(devMode)
|
||||||
return devResponse.getActivities();
|
return devResponse.getActivities();
|
||||||
|
|
||||||
return harmonyClient.getConfig().getActivities();
|
List<Activity> listOfActivities = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
listOfActivities = harmonyClient.getConfig().getActivities();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
handleExceptionError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOfActivities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Device> getDevices() {
|
public List<Device> getDevices() {
|
||||||
@@ -42,7 +54,15 @@ public class HarmonyHandler {
|
|||||||
if(devMode)
|
if(devMode)
|
||||||
return devResponse.getDevices();
|
return devResponse.getDevices();
|
||||||
|
|
||||||
return harmonyClient.getConfig().getDevices();
|
List<Device> listOfDevices = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
listOfDevices = harmonyClient.getConfig().getDevices();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
handleExceptionError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return listOfDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HarmonyConfig getConfig() {
|
public HarmonyConfig getConfig() {
|
||||||
@@ -50,7 +70,14 @@ public class HarmonyHandler {
|
|||||||
if(devMode)
|
if(devMode)
|
||||||
return devResponse.getConfig();
|
return devResponse.getConfig();
|
||||||
|
|
||||||
return harmonyClient.getConfig();
|
HarmonyConfig aConfig = null;
|
||||||
|
try {
|
||||||
|
aConfig = harmonyClient.getConfig();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
handleExceptionError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Activity getCurrentActivity() {
|
public Activity getCurrentActivity() {
|
||||||
@@ -58,11 +85,18 @@ public class HarmonyHandler {
|
|||||||
if(devMode)
|
if(devMode)
|
||||||
return devResponse.getCurrentActivity();
|
return devResponse.getCurrentActivity();
|
||||||
|
|
||||||
return harmonyClient.getCurrentActivity();
|
Activity anActivity = null;
|
||||||
|
try {
|
||||||
|
anActivity = harmonyClient.getCurrentActivity();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
handleExceptionError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return anActivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean startActivity(RunActivity anActivity) {
|
public Boolean startActivity(RunActivity anActivity) {
|
||||||
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls);
|
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub() + " noop mode: " + noopCalls);
|
||||||
if (anActivity.isValid()) {
|
if (anActivity.isValid()) {
|
||||||
try {
|
try {
|
||||||
if (noopCalls || devMode) {
|
if (noopCalls || devMode) {
|
||||||
@@ -72,7 +106,7 @@ public class HarmonyHandler {
|
|||||||
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName());
|
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
||||||
@@ -81,39 +115,56 @@ public class HarmonyHandler {
|
|||||||
if (!noopCalls)
|
if (!noopCalls)
|
||||||
harmonyClient.startActivityByName(anActivity.getName());
|
harmonyClient.startActivityByName(anActivity.getName());
|
||||||
} catch (IllegalArgumentException ei) {
|
} catch (IllegalArgumentException ei) {
|
||||||
log.error("Error in finding activity: " + anActivity.getName());
|
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||||
return false;
|
} catch (RuntimeException e1) {
|
||||||
|
return handleExceptionError(e1);
|
||||||
}
|
}
|
||||||
|
} catch (RuntimeException e1) {
|
||||||
|
return handleExceptionError(e1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("Error in finding activity: " + anActivity.getName());
|
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean pressButton(ButtonPress aDeviceButton) {
|
public Boolean pressButton(ButtonPress aDeviceButton) {
|
||||||
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls);
|
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " with pressTime of: " + aDeviceButton.getPressTime() + " for a hub: " + aDeviceButton.getHub() + " noop mode: " + noopCalls);
|
||||||
if (aDeviceButton.isValid()) {
|
if (aDeviceButton.isValid()) {
|
||||||
try {
|
try {
|
||||||
if (noopCalls || devMode) {
|
if (noopCalls || devMode) {
|
||||||
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton());
|
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() +
|
||||||
|
" with a pressTime of: " + aDeviceButton.getPressTime() + " for a hub: " + aDeviceButton.getHub());
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
if(aDeviceButton.getPressTime() != null && aDeviceButton.getPressTime() > 0)
|
||||||
|
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton(), aDeviceButton.getPressTime());
|
||||||
|
else
|
||||||
|
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
try {
|
try {
|
||||||
if (!noopCalls)
|
if (!noopCalls)
|
||||||
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||||
} catch (IllegalArgumentException ei) {
|
} catch (IllegalArgumentException ei) {
|
||||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
|
||||||
return false;
|
} catch (RuntimeException e1) {
|
||||||
|
return handleExceptionError(e1);
|
||||||
}
|
}
|
||||||
|
} catch (RuntimeException e1) {
|
||||||
|
return handleExceptionError(e1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean handleExceptionError(Exception e) {
|
||||||
|
if(e.getMessage().contains("Failed communicating with Harmony Hub") || e.getMessage().contains("Send heartbeat failed")) {
|
||||||
|
log.warn("Issue in communcicating with Harmony Hub, retrying connect....");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,9 +175,19 @@ public class HarmonyHandler {
|
|||||||
log.debug("Harmony api shutdown requested.");
|
log.debug("Harmony api shutdown requested.");
|
||||||
if(devMode)
|
if(devMode)
|
||||||
return;
|
return;
|
||||||
|
try {
|
||||||
harmonyClient.disconnect();
|
harmonyClient.disconnect();
|
||||||
|
} catch(Exception e)
|
||||||
|
{
|
||||||
|
// noop
|
||||||
|
}
|
||||||
harmonyClient = null;
|
harmonyClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the myNameAndIP
|
||||||
|
*/
|
||||||
|
public NamedIP getMyNameAndIP() {
|
||||||
|
return myNameAndIP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
import com.bwssystems.HABridge.Home;
|
import com.bwssystems.HABridge.Home;
|
||||||
import com.bwssystems.HABridge.IpList;
|
import com.bwssystems.HABridge.IpList;
|
||||||
@@ -18,6 +18,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.ColorData;
|
||||||
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;
|
||||||
@@ -26,49 +27,56 @@ import net.whistlingfish.harmony.config.Activity;
|
|||||||
import net.whistlingfish.harmony.config.Device;
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
|
||||||
public class HarmonyHome implements Home {
|
public class HarmonyHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||||
private Map<String, HarmonyServer> hubs;
|
private Map<String, HarmonyServer> hubs;
|
||||||
private Boolean isDevMode;
|
private Boolean isDevMode;
|
||||||
private Boolean validHarmony;
|
private Boolean validHarmony;
|
||||||
private Gson aGsonHandler;
|
private Gson aGsonHandler;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public HarmonyHome(BridgeSettingsDescriptor bridgeSettings) {
|
public HarmonyHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
if(!validHarmony)
|
if (!validHarmony)
|
||||||
return;
|
return;
|
||||||
if(isDevMode || hubs == null)
|
log.debug("Closing Home.");
|
||||||
|
if (closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isDevMode || hubs == null)
|
||||||
return;
|
return;
|
||||||
Iterator<String> keys = hubs.keySet().iterator();
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
while(keys.hasNext()) {
|
while (keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
hubs.get(key).getMyHarmony().shutdown();
|
hubs.get(key).getMyHarmony().shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
hubs = null;
|
hubs = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HarmonyHandler getHarmonyHandler(String aName) {
|
public HarmonyHandler getHarmonyHandler(String aName) {
|
||||||
if(!validHarmony)
|
if (!validHarmony)
|
||||||
return null;
|
return null;
|
||||||
HarmonyHandler aHandler = null;
|
HarmonyHandler aHandler = null;
|
||||||
if(aName == null || aName.equals("")) {
|
if (aName == null || aName.equals("")) {
|
||||||
aName = "default";
|
aName = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hubs.get(aName) == null) {
|
if (hubs.get(aName) == null) {
|
||||||
Set<String> keys = hubs.keySet();
|
Set<String> keys = hubs.keySet();
|
||||||
if(!keys.isEmpty()) {
|
if (!keys.isEmpty()) {
|
||||||
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
aHandler = null;
|
aHandler = null;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
aHandler = hubs.get(aName).getMyHarmony();
|
aHandler = hubs.get(aName).getMyHarmony();
|
||||||
return aHandler;
|
return aHandler;
|
||||||
}
|
}
|
||||||
@@ -76,48 +84,95 @@ public class HarmonyHome implements Home {
|
|||||||
public List<HarmonyActivity> getActivities() {
|
public List<HarmonyActivity> getActivities() {
|
||||||
Iterator<String> keys = hubs.keySet().iterator();
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||||
if(!validHarmony)
|
if (!validHarmony)
|
||||||
return null;
|
return null;
|
||||||
while(keys.hasNext()) {
|
while (keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
while(activities.hasNext()) {
|
if (activities == null) {
|
||||||
|
resetHub(hubs.get(key).getMyHarmony());
|
||||||
|
activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
if (activities == null) {
|
||||||
|
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||||
|
activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
if (activities == null) {
|
||||||
|
log.error("Could not get communication restored with hub: " + key
|
||||||
|
+ ", please restart...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (activities != null) {
|
||||||
|
while (activities.hasNext()) {
|
||||||
|
HarmonyActivity anActivity = new HarmonyActivity();
|
||||||
|
anActivity.setActivity(activities.next());
|
||||||
|
anActivity.setHub(key);
|
||||||
|
activityList.add(anActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activityList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HarmonyActivity> getCurrentActivities() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||||
|
if (!validHarmony)
|
||||||
|
return null;
|
||||||
|
while (keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Activity theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||||
|
if (theActivity == null) {
|
||||||
|
resetHub(hubs.get(key).getMyHarmony());
|
||||||
|
theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||||
|
if (theActivity == null) {
|
||||||
|
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||||
|
theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||||
|
if (theActivity == null) {
|
||||||
|
log.error("Could not get communication restored with hub: " + key
|
||||||
|
+ ", please restart...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (theActivity != null) {
|
||||||
HarmonyActivity anActivity = new HarmonyActivity();
|
HarmonyActivity anActivity = new HarmonyActivity();
|
||||||
anActivity.setActivity(activities.next());
|
anActivity.setActivity(theActivity);
|
||||||
anActivity.setHub(key);
|
anActivity.setHub(key);
|
||||||
activityList.add(anActivity);
|
activityList.add(anActivity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return activityList;
|
return activityList;
|
||||||
}
|
}
|
||||||
public List<HarmonyActivity> getCurrentActivities() {
|
|
||||||
Iterator<String> keys = hubs.keySet().iterator();
|
|
||||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
|
||||||
if(!validHarmony)
|
|
||||||
return null;
|
|
||||||
while(keys.hasNext()) {
|
|
||||||
String key = keys.next();
|
|
||||||
Activity theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
|
||||||
HarmonyActivity anActivity = new HarmonyActivity();
|
|
||||||
anActivity.setActivity(theActivity);
|
|
||||||
anActivity.setHub(key);
|
|
||||||
activityList.add(anActivity);
|
|
||||||
}
|
|
||||||
return activityList;
|
|
||||||
}
|
|
||||||
public List<HarmonyDevice> getDevices() {
|
public List<HarmonyDevice> getDevices() {
|
||||||
Iterator<String> keys = hubs.keySet().iterator();
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
||||||
if(!validHarmony)
|
if (!validHarmony)
|
||||||
return null;
|
return null;
|
||||||
while(keys.hasNext()) {
|
while (keys.hasNext()) {
|
||||||
String key = keys.next();
|
String key = keys.next();
|
||||||
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||||
while(devices.hasNext()) {
|
if (devices == null) {
|
||||||
HarmonyDevice aDevice = new HarmonyDevice();
|
resetHub(hubs.get(key).getMyHarmony());
|
||||||
aDevice.setDevice(devices.next());
|
devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||||
aDevice.setHub(key);
|
if (devices == null) {
|
||||||
deviceList.add(aDevice);
|
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||||
|
devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||||
|
if (devices == null) {
|
||||||
|
log.error("Could not get communication restored with hub: " + key
|
||||||
|
+ ", please restart...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (devices != null) {
|
||||||
|
while (devices.hasNext()) {
|
||||||
|
HarmonyDevice aDevice = new HarmonyDevice();
|
||||||
|
aDevice.setDevice(devices.next());
|
||||||
|
aDevice.setHub(key);
|
||||||
|
deviceList.add(aDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return deviceList;
|
return deviceList;
|
||||||
@@ -125,36 +180,47 @@ public class HarmonyHome 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, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
log.debug("executing HUE api request to change " + anItem.getType() + " to Harmony: " + device.getName());
|
log.debug("executing HUE api request to change " + anItem.getType() + " to Harmony: " + device.getName());
|
||||||
if(!validHarmony) {
|
if (!validHarmony) {
|
||||||
log.warn("Should not get here, no harmony configured");
|
log.warn("Should not get here, no harmony configured");
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
} else {
|
} else {
|
||||||
if(anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
|
if (anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex])) {
|
||||||
{
|
|
||||||
RunActivity anActivity = null;
|
RunActivity anActivity = null;
|
||||||
if(anItem.getItem().isJsonObject())
|
if (anItem.getItem().isJsonObject())
|
||||||
anActivity = aGsonHandler.fromJson(anItem.getItem(), RunActivity.class);
|
anActivity = aGsonHandler.fromJson(anItem.getItem(), RunActivity.class);
|
||||||
else
|
else
|
||||||
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString(), RunActivity.class);
|
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), RunActivity.class);
|
||||||
if(anActivity.getHub() == null || anActivity.getHub().isEmpty())
|
if (anActivity.getHub() == null || anActivity.getHub().isEmpty())
|
||||||
anActivity.setHub(device.getTargetDevice());
|
anActivity.setHub(device.getTargetDevice());
|
||||||
HarmonyHandler myHarmony = getHarmonyHandler(anActivity.getHub());
|
HarmonyHandler myHarmony = getHarmonyHandler(anActivity.getHub());
|
||||||
if (myHarmony == null) {
|
if (myHarmony == null) {
|
||||||
log.warn("Should not get here, no harmony hub available");
|
log.warn("Should not get here, no harmony hub available");
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
} else {
|
} else {
|
||||||
myHarmony.startActivity(anActivity);
|
if (!myHarmony.startActivity(anActivity)) {
|
||||||
|
if (resetHub(myHarmony)) {
|
||||||
|
myHarmony = getHarmonyHandler(anActivity.getHub());
|
||||||
|
if (!myHarmony.startActivity(anActivity)) {
|
||||||
|
log.error("Could not get communication restored with hub: " + anActivity.getHub()
|
||||||
|
+ ", please restart...");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Could not communicate with harmony\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if(anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex])) {
|
} else if (anItem.getType().trim()
|
||||||
|
.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex])) {
|
||||||
String url = null;
|
String url = null;
|
||||||
if(anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
|
if (anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
|
||||||
url = aGsonHandler.toJson(anItem.getItem());
|
url = aGsonHandler.toJson(anItem.getItem());
|
||||||
} else
|
} else
|
||||||
url = anItem.getItem().getAsString();
|
url = anItem.getItem().getAsString();
|
||||||
@@ -165,48 +231,62 @@ public class HarmonyHome implements Home {
|
|||||||
|
|
||||||
url = BrightnessDecode.calculateReplaceIntensityValue(url, intensity, targetBri, targetBriInc, false);
|
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++) {
|
||||||
if(deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
|
if (deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
|
||||||
theCount = deviceButtons[z].getCount();
|
theCount = deviceButtons[z].getCount();
|
||||||
for(int y = 0; y < theCount; y++) {
|
for (int y = 0; y < theCount; y++) {
|
||||||
if( y > 0 || z > 0) {
|
if (y > 0 || z > 0) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(aMultiUtil.getTheDelay());
|
Thread.sleep(aMultiUtil.getTheDelay());
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anItem.getDelay() != null && anItem.getDelay() > 0)
|
||||||
|
aMultiUtil.setTheDelay(anItem.getDelay());
|
||||||
|
else
|
||||||
|
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
|
||||||
|
log.debug("pressing button: " + deviceButtons[z].getDevice() + " - "
|
||||||
|
+ deviceButtons[z].getButton() + " with pressTime of: "
|
||||||
|
+ deviceButtons[z].getPressTime() + " - iteration: " + String.valueOf(z) + " - count: "
|
||||||
|
+ String.valueOf(y));
|
||||||
|
if (deviceButtons[z].getHub() == null || deviceButtons[z].getHub().isEmpty())
|
||||||
|
deviceButtons[z].setHub(device.getTargetDevice());
|
||||||
|
HarmonyHandler myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
||||||
|
if (myHarmony == null)
|
||||||
|
log.warn("Button Press - Should not get here, no harmony hub available");
|
||||||
|
else{
|
||||||
|
if (!myHarmony.pressButton(deviceButtons[z])) {
|
||||||
|
if (resetHub(myHarmony)) {
|
||||||
|
myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
||||||
|
if (!myHarmony.pressButton(deviceButtons[z])) {
|
||||||
|
log.error("Could not get communication restored with hub: " + deviceButtons[z].getHub()
|
||||||
|
+ ", please restart...");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Could not communicate with harmony\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anItem.getDelay() != null && anItem.getDelay() > 0)
|
}
|
||||||
aMultiUtil.setTheDelay(anItem.getDelay());
|
}
|
||||||
else
|
}
|
||||||
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
|
|
||||||
log.debug("pressing button: " + deviceButtons[z].getDevice() + " - " + deviceButtons[z].getButton() + " - iteration: " + String.valueOf(z) + " - count: " + String.valueOf(y));
|
|
||||||
if(deviceButtons[z].getHub() == null || deviceButtons[z].getHub().isEmpty())
|
|
||||||
deviceButtons[z].setHub(device.getTargetDevice());
|
|
||||||
HarmonyHandler myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
|
||||||
if (myHarmony == null)
|
|
||||||
log.warn("Button Press - Should not get here, no harmony hub available");
|
|
||||||
else
|
|
||||||
myHarmony.pressButton(deviceButtons[z]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
validHarmony = bridgeSettings.isValidHarmony();
|
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
|
||||||
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.") + (isDevMode ? " DevMode is set." : ""));
|
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.")
|
||||||
if(validHarmony || isDevMode) {
|
+ (isDevMode ? " DevMode is set." : ""));
|
||||||
|
if (validHarmony || isDevMode) {
|
||||||
hubs = new HashMap<String, HarmonyServer>();
|
hubs = new HashMap<String, HarmonyServer>();
|
||||||
aGsonHandler =
|
aGsonHandler = new GsonBuilder().create();
|
||||||
new GsonBuilder()
|
if (isDevMode) {
|
||||||
.create();
|
|
||||||
if(isDevMode) {
|
|
||||||
NamedIP devModeIp = new NamedIP();
|
NamedIP devModeIp = new NamedIP();
|
||||||
devModeIp.setIp("10.10.10.10");
|
devModeIp.setIp("10.10.10.10");
|
||||||
devModeIp.setName("devMode");
|
devModeIp.setName("devMode");
|
||||||
@@ -214,21 +294,23 @@ public class HarmonyHome implements Home {
|
|||||||
theList.add(devModeIp);
|
theList.add(devModeIp);
|
||||||
IpList thedevList = new IpList();
|
IpList thedevList = new IpList();
|
||||||
thedevList.setDevices(theList);
|
thedevList.setDevices(theList);
|
||||||
bridgeSettings.setHarmonyAddress(thedevList);
|
bridgeSettings.getBridgeSettingsDescriptor().setHarmonyAddress(thedevList);
|
||||||
}
|
}
|
||||||
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices()
|
||||||
while(theList.hasNext() && validHarmony) {
|
.iterator();
|
||||||
|
while (theList.hasNext() && validHarmony) {
|
||||||
NamedIP aHub = theList.next();
|
NamedIP aHub = theList.next();
|
||||||
boolean loopControl = true;
|
boolean loopControl = true;
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
while(loopControl) {
|
while (loopControl) {
|
||||||
try {
|
try {
|
||||||
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, isDevMode, aHub));
|
hubs.put(aHub.getName(), HarmonyServer.setup(isDevMode, aHub));
|
||||||
loopControl = false;
|
loopControl = false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if(retryCount > 3) {
|
if (retryCount > 3) {
|
||||||
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: "
|
||||||
loopControl = false;
|
+ e.getMessage(), e);
|
||||||
|
loopControl = false;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(2000);
|
Thread.sleep(2000);
|
||||||
@@ -241,22 +323,47 @@ public class HarmonyHome implements Home {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(hubs.isEmpty())
|
if (hubs.isEmpty())
|
||||||
validHarmony = false;
|
validHarmony = false;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean resetHub(HarmonyHandler aHarmony) {
|
||||||
|
boolean resetSuccess = false;
|
||||||
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
|
NamedIP resetIp = aHarmony.getMyNameAndIP();
|
||||||
|
log.info("Resetting harmony hub due to communication errror: " + resetIp.getName());
|
||||||
|
if (!isDevMode) {
|
||||||
|
try {
|
||||||
|
hubs.remove(resetIp.getName());
|
||||||
|
aHarmony.shutdown();
|
||||||
|
hubs.put(resetIp.getName(), HarmonyServer.setup(isDevMode, resetIp));
|
||||||
|
resetSuccess = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot reset harmony client (" + resetIp.getName() + "), Exiting with message: "
|
||||||
|
+ e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resetSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItems(String type) {
|
public Object getItems(String type) {
|
||||||
if(validHarmony) {
|
if (validHarmony) {
|
||||||
if(type.equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
|
if (type.equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
|
||||||
return getActivities();
|
return getActivities();
|
||||||
if(type.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex]))
|
if (type.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex]))
|
||||||
return getDevices();
|
return getDevices();
|
||||||
if(type.equalsIgnoreCase("current_activity"))
|
if (type.equalsIgnoreCase("current_activity"))
|
||||||
return getCurrentActivities();
|
return getCurrentActivities();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ import static java.lang.String.format;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
|
||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
@@ -44,15 +45,14 @@ public class HarmonyServer {
|
|||||||
dummyProvider = null;
|
dummyProvider = null;
|
||||||
myNameAndIP = theHarmonyAddress;
|
myNameAndIP = theHarmonyAddress;
|
||||||
isDevMode = false;
|
isDevMode = false;
|
||||||
httpClient = new HTTPHandler();
|
httpClient = HTTPHome.getHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HarmonyServer setup(
|
public static HarmonyServer setup(
|
||||||
BridgeSettingsDescriptor bridgeSettings,
|
|
||||||
Boolean harmonyDevMode,
|
Boolean harmonyDevMode,
|
||||||
NamedIP theHarmonyAddress
|
NamedIP theHarmonyAddress
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
|
if (harmonyDevMode) {
|
||||||
return new HarmonyServer(theHarmonyAddress);
|
return new HarmonyServer(theHarmonyAddress);
|
||||||
}
|
}
|
||||||
Injector injector = null;
|
Injector injector = null;
|
||||||
@@ -63,11 +63,11 @@ public class HarmonyServer {
|
|||||||
if (!harmonyDevMode) {
|
if (!harmonyDevMode) {
|
||||||
injector.injectMembers(mainObject);
|
injector.injectMembers(mainObject);
|
||||||
}
|
}
|
||||||
mainObject.execute(bridgeSettings, harmonyDevMode);
|
mainObject.execute(harmonyDevMode);
|
||||||
return mainObject;
|
return mainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
|
private void execute(Boolean harmonyDevMode) throws Exception {
|
||||||
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 = "";
|
||||||
@@ -108,7 +108,7 @@ public class HarmonyServer {
|
|||||||
});
|
});
|
||||||
harmonyClient.connect(myNameAndIP.getIp());
|
harmonyClient.connect(myNameAndIP.getIp());
|
||||||
}
|
}
|
||||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse, myNameAndIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HarmonyHandler getMyHarmony() {
|
public HarmonyHandler getMyHarmony() {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.hass;
|
||||||
|
|
||||||
|
public class HassAuth {
|
||||||
|
boolean legacyauth;
|
||||||
|
|
||||||
|
public boolean isLegacyauth() {
|
||||||
|
return legacyauth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLegacyauth(boolean legacyauth) {
|
||||||
|
this.legacyauth = legacyauth;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,13 @@ import java.util.Map;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
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.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.ColorData;
|
||||||
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;
|
||||||
@@ -25,24 +26,27 @@ public class HassHome implements Home {
|
|||||||
private Map<String, HomeAssistant> hassMap;
|
private Map<String, HomeAssistant> hassMap;
|
||||||
private Boolean validHass;
|
private Boolean validHass;
|
||||||
private Gson aGsonHandler;
|
private Gson aGsonHandler;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public HassHome(BridgeSettingsDescriptor bridgeSettings) {
|
public HassHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
hassMap = null;
|
hassMap = null;
|
||||||
aGsonHandler = null;
|
aGsonHandler = null;
|
||||||
validHass = bridgeSettings.isValidHass();
|
validHass = bridgeSettings.getBridgeSettingsDescriptor().isValidHass();
|
||||||
log.info("HomeAssistant Home created." + (validHass ? "" : " No HomeAssistants configured."));
|
log.info("HomeAssistant Home created." + (validHass ? "" : " No HomeAssistants configured."));
|
||||||
if(validHass) {
|
if(validHass) {
|
||||||
hassMap = new HashMap<String,HomeAssistant>();
|
hassMap = new HashMap<String,HomeAssistant>();
|
||||||
aGsonHandler =
|
aGsonHandler =
|
||||||
new GsonBuilder()
|
new GsonBuilder()
|
||||||
.create();
|
.create();
|
||||||
Iterator<NamedIP> theList = bridgeSettings.getHassaddress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHassaddress().getDevices().iterator();
|
||||||
while(theList.hasNext() && validHass) {
|
while(theList.hasNext() && validHass) {
|
||||||
NamedIP aHass = theList.next();
|
NamedIP aHass = theList.next();
|
||||||
try {
|
try {
|
||||||
@@ -94,7 +98,7 @@ public class HassHome implements Home {
|
|||||||
|
|
||||||
private Boolean addHassDevices(List<HassDevice> theDeviceList, List<State> theSourceList, String theKey) {
|
private Boolean addHassDevices(List<HassDevice> theDeviceList, List<State> theSourceList, String theKey) {
|
||||||
if(!validHass)
|
if(!validHass)
|
||||||
return null;
|
return false;
|
||||||
Iterator<State> devices = theSourceList.iterator();
|
Iterator<State> devices = theSourceList.iterator();
|
||||||
while(devices.hasNext()) {
|
while(devices.hasNext()) {
|
||||||
State theDevice = devices.next();
|
State theDevice = devices.next();
|
||||||
@@ -113,23 +117,28 @@ public class HassHome implements Home {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
@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, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
String theReturn = null;
|
String theReturn = null;
|
||||||
log.debug("executing HUE api request to send message to HomeAssistant: " + anItem.getItem().toString());
|
log.debug("executing HUE api request to send message to HomeAssistant: " + anItem.getItem().toString());
|
||||||
if(!validHass) {
|
if(!validHass) {
|
||||||
log.warn("Should not get here, no HomeAssistant clients configured");
|
log.warn("Should not get here, no HomeAssistant clients configured");
|
||||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Should not get here, no HomeAssistants configured\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"Should not get here, no HomeAssistants configured\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
HassCommand hassCommand = null;
|
HassCommand hassCommand = null;
|
||||||
if(anItem.getItem().isJsonObject())
|
if(anItem.getItem().isJsonObject())
|
||||||
hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class);
|
hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class);
|
||||||
else
|
else
|
||||||
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), HassCommand.class);
|
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class);
|
||||||
hassCommand.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(),
|
hassCommand.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(),
|
||||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
|
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
|
||||||
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
|
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
|
||||||
@@ -137,7 +146,7 @@ public class HassHome implements Home {
|
|||||||
log.warn("Should not get here, no HomeAssistants available");
|
log.warn("Should not get here, no HomeAssistants available");
|
||||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
+ "\",\"description\": \"Should not get here, no HiomeAssistant clients available\", \"parameter\": \"/lights/"
|
+ "\",\"description\": \"Should not get here, no HiomeAssistant clients available\", \"parameter\": \"/lights/"
|
||||||
+ lightId + "state\"}}]";
|
+ lightId + "/state\"}}]";
|
||||||
} else {
|
} else {
|
||||||
log.debug("calling HomeAssistant: " + hassCommand.getHassName() + " - "
|
log.debug("calling HomeAssistant: " + hassCommand.getHassName() + " - "
|
||||||
+ hassCommand.getEntityId() + " - " + hassCommand.getState() + " - " + hassCommand.getBri());
|
+ hassCommand.getEntityId() + " - " + hassCommand.getState() + " - " + hassCommand.getBri());
|
||||||
@@ -151,6 +160,11 @@ public class HassHome implements Home {
|
|||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
if(!validHass)
|
if(!validHass)
|
||||||
return;
|
return;
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(hassMap == null)
|
if(hassMap == null)
|
||||||
return;
|
return;
|
||||||
Iterator<String> keys = hassMap.keySet().iterator();
|
Iterator<String> keys = hassMap.keySet().iterator();
|
||||||
@@ -160,5 +174,6 @@ public class HassHome implements Home {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hassMap = null;
|
hassMap = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,23 @@ import org.slf4j.LoggerFactory;
|
|||||||
import com.bwssystems.HABridge.NamedIP;
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.HABridge.api.NameValue;
|
import com.bwssystems.HABridge.api.NameValue;
|
||||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class HomeAssistant {
|
public class HomeAssistant {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
|
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
|
||||||
private NamedIP hassAddress;
|
private NamedIP hassAddress;
|
||||||
private HTTPHandler anHttpHandler;
|
private HTTPHandler anHttpHandler;
|
||||||
|
private HassAuth theAuthType;
|
||||||
|
private NameValue[] headers;
|
||||||
|
|
||||||
public HomeAssistant(NamedIP addressName) {
|
public HomeAssistant(NamedIP addressName) {
|
||||||
super();
|
super();
|
||||||
anHttpHandler = new HTTPHandler();
|
anHttpHandler = HTTPHome.getHandler();
|
||||||
hassAddress = addressName;
|
hassAddress = addressName;
|
||||||
|
theAuthType = null;
|
||||||
|
headers = null;
|
||||||
|
isLegacyAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NamedIP getHassAddress() {
|
public NamedIP getHassAddress() {
|
||||||
@@ -34,42 +40,30 @@ public class HomeAssistant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Boolean callCommand(HassCommand aCommand) {
|
public Boolean callCommand(HassCommand aCommand) {
|
||||||
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - "
|
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - " + aCommand.getEntityId() + " - "
|
||||||
+ aCommand.getEntityId() + " - " + aCommand.getState() + " - " + aCommand.getBri());
|
+ aCommand.getState() + " - " + aCommand.getBri());
|
||||||
String aUrl = null;
|
String aUrl = null;
|
||||||
if(hassAddress.getSecure() != null && hassAddress.getSecure())
|
|
||||||
aUrl = "https";
|
|
||||||
else
|
|
||||||
aUrl = "http";
|
|
||||||
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
|
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
|
||||||
aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
|
aUrl = hassAddress.getHttpPreamble() + "/api/services/";
|
||||||
if(domain.equals("group"))
|
if (domain.equals("group"))
|
||||||
aUrl = aUrl + "homeassistant";
|
aUrl = aUrl + "homeassistant";
|
||||||
else
|
else
|
||||||
aUrl = aUrl + domain;
|
aUrl = aUrl + domain;
|
||||||
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
|
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
|
||||||
NameValue[] headers = null;
|
headers = getAuthHeader();
|
||||||
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
if (aCommand.getState().equalsIgnoreCase("on")) {
|
||||||
NameValue password = new NameValue();
|
|
||||||
password.setName("x-ha-access");
|
|
||||||
password.setValue(hassAddress.getPassword());
|
|
||||||
headers = new NameValue[1];
|
|
||||||
headers[0] = password;
|
|
||||||
}
|
|
||||||
if(aCommand.getState().equalsIgnoreCase("on")) {
|
|
||||||
aUrl = aUrl + "/turn_on";
|
aUrl = aUrl + "/turn_on";
|
||||||
if(aCommand.getBri() != null)
|
if (aCommand.getBri() != null)
|
||||||
aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}";
|
aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}";
|
||||||
else
|
else
|
||||||
aBody = aBody + "}";
|
aBody = aBody + "}";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
aUrl = aUrl + "/turn_off";
|
aUrl = aUrl + "/turn_off";
|
||||||
aBody = aBody + "}";
|
aBody = aBody + "}";
|
||||||
}
|
}
|
||||||
log.debug("Calling HomeAssistant with url: " + aUrl);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,39 +71,62 @@ public class HomeAssistant {
|
|||||||
List<State> theDeviceStates = null;
|
List<State> theDeviceStates = null;
|
||||||
State[] theHassStates;
|
State[] theHassStates;
|
||||||
String theUrl = null;
|
String theUrl = null;
|
||||||
String theData;
|
String theData;
|
||||||
NameValue[] headers = null;
|
headers = getAuthHeader();
|
||||||
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
if (hassAddress.getSecure() != null && hassAddress.getSecure())
|
||||||
NameValue password = new NameValue();
|
|
||||||
password.setName("x-ha-access");
|
|
||||||
password.setValue(hassAddress.getPassword());
|
|
||||||
headers = new NameValue[1];
|
|
||||||
headers[0] = password;
|
|
||||||
}
|
|
||||||
if(hassAddress.getSecure() != null && hassAddress.getSecure())
|
|
||||||
theUrl = "https";
|
theUrl = "https";
|
||||||
else
|
else
|
||||||
theUrl = "http";
|
theUrl = "http";
|
||||||
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
|
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
|
||||||
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||||
if(theData != null) {
|
if (theData != null) {
|
||||||
log.debug("GET Hass States - data: " + theData);
|
log.debug("GET Hass States - data: " + theData);
|
||||||
theHassStates = new Gson().fromJson(theData, State[].class);
|
theHassStates = new Gson().fromJson(theData, State[].class);
|
||||||
if(theHassStates == null) {
|
if (theHassStates == null) {
|
||||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " as response is not parsable.");
|
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName()
|
||||||
}
|
+ " as response is not parsable.");
|
||||||
else {
|
} else {
|
||||||
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
|
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
|
||||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
|
|
||||||
return theDeviceStates;
|
return theDeviceStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void closeClient() {
|
protected void closeClient() {
|
||||||
anHttpHandler.closeHandler();
|
anHttpHandler.closeHandler();
|
||||||
anHttpHandler = null;
|
anHttpHandler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isLegacyAuth() {
|
||||||
|
if (theAuthType == null) {
|
||||||
|
try {
|
||||||
|
theAuthType = new Gson().fromJson(hassAddress.getExtensions(), HassAuth.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Could not read hass auth - continuing with defaults.");
|
||||||
|
theAuthType = new HassAuth();
|
||||||
|
theAuthType.setLegacyauth(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theAuthType.isLegacyauth();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NameValue[] getAuthHeader() {
|
||||||
|
if (headers == null) {
|
||||||
|
if (hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
||||||
|
headers = new NameValue[1];
|
||||||
|
headers[0] = new NameValue();
|
||||||
|
if (isLegacyAuth()) {
|
||||||
|
headers[0].setName("x-ha-access");
|
||||||
|
headers[0].setValue(hassAddress.getPassword());
|
||||||
|
} else {
|
||||||
|
headers[0].setName("Authorization");
|
||||||
|
headers[0].setValue("Bearer " + hassAddress.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) {
|
||||||
|
headers = null;
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class HomeGenieCommand {
|
||||||
|
@SerializedName("moduleType")
|
||||||
|
@Expose
|
||||||
|
private String moduleType;
|
||||||
|
@SerializedName("deviceId")
|
||||||
|
@Expose
|
||||||
|
private String deviceId;
|
||||||
|
@SerializedName("command")
|
||||||
|
@Expose
|
||||||
|
private HomeGenieCommandDetail command;
|
||||||
|
|
||||||
|
public String getModuleType() {
|
||||||
|
return moduleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleType(String moduleType) {
|
||||||
|
this.moduleType = moduleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HomeGenieCommandDetail getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommand(HomeGenieCommandDetail command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class HomeGenieCommandDetail {
|
||||||
|
@SerializedName("command")
|
||||||
|
@Expose
|
||||||
|
private String command;
|
||||||
|
@SerializedName("level")
|
||||||
|
@Expose
|
||||||
|
private String level;
|
||||||
|
@SerializedName("color")
|
||||||
|
@Expose
|
||||||
|
private String color;
|
||||||
|
|
||||||
|
public String getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(String level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(String color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class HomeGenieDevice {
|
||||||
|
@SerializedName("gatewayName")
|
||||||
|
@Expose
|
||||||
|
private String gatewayName;
|
||||||
|
@SerializedName("deviceDetail")
|
||||||
|
@Expose
|
||||||
|
private Module deviceDetail;
|
||||||
|
|
||||||
|
public String getGatewayName() {
|
||||||
|
return gatewayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGatewayName(String gatewayName) {
|
||||||
|
this.gatewayName = gatewayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Module getDeviceDetail() {
|
||||||
|
return deviceDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceDetail(Module deviceDetail) {
|
||||||
|
this.deviceDetail = deviceDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
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.BridgeSettings;
|
||||||
|
import com.bwssystems.HABridge.Home;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
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.hue.BrightnessDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class HomeGenieHome implements Home {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeGenieHome.class);
|
||||||
|
private Map<String, HomeGenieInstance> homegenieMap;
|
||||||
|
private Boolean validHomeGenie;
|
||||||
|
private HTTPHandler httpClient;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
|
public HomeGenieHome(BridgeSettings bridgeSettings) {
|
||||||
|
super();
|
||||||
|
closed = true;
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
|
|
||||||
|
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
|
String responseString = null;
|
||||||
|
|
||||||
|
if (theUrl != null && !theUrl.isEmpty()) {
|
||||||
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl, intensity, targetBri, targetBriInc,
|
||||||
|
false);
|
||||||
|
if (colorData != null) {
|
||||||
|
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||||
|
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||||
|
}
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
|
anUrl = BrightnessDecode.calculateReplaceIntensityValue(anUrl, intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||||
|
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
|
HomeGenieCommand theCommand = null;
|
||||||
|
try {
|
||||||
|
theCommand = new Gson().fromJson(anUrl, HomeGenieCommand.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Cannot parse command to HomeGenie <<<" + theUrl + ">>>", e);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeGenieInstance theHandler = homegenieMap.get(device.getTargetDevice());
|
||||||
|
if (theHandler != null) {
|
||||||
|
try {
|
||||||
|
boolean success = theHandler.callCommand(theCommand.getDeviceId(), theCommand.getModuleType(), theCommand.getCommand(), httpClient);
|
||||||
|
if (!success) {
|
||||||
|
log.warn("Comand had error to HomeGenie");
|
||||||
|
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 send comand to HomeGenie", e);
|
||||||
|
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("HomeGenie 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(
|
||||||
|
"HomeGenie 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
|
||||||
|
public Object getItems(String type) {
|
||||||
|
|
||||||
|
if (!validHomeGenie)
|
||||||
|
return null;
|
||||||
|
log.debug("consolidating devices for HomeGenie");
|
||||||
|
List<Module> theResponse = null;
|
||||||
|
Iterator<String> keys = homegenieMap.keySet().iterator();
|
||||||
|
List<HomeGenieDevice> deviceList = new ArrayList<HomeGenieDevice>();
|
||||||
|
while (keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
theResponse = homegenieMap.get(key).getDevices(httpClient);
|
||||||
|
if (theResponse != null)
|
||||||
|
addHomeGenieDevices(deviceList, theResponse, key);
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get devices for HomeGenie with name: " + key + ", skipping this HomeGenie.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean addHomeGenieDevices(List<HomeGenieDevice> theDeviceList, List<Module> theSourceList,
|
||||||
|
String theKey) {
|
||||||
|
Iterator<Module> hgModules = theSourceList.iterator();
|
||||||
|
while (hgModules.hasNext()) {
|
||||||
|
Module aModule = hgModules.next();
|
||||||
|
HomeGenieDevice theDevice = new HomeGenieDevice();
|
||||||
|
theDevice.setDeviceDetail(aModule);
|
||||||
|
theDevice.setGatewayName(theKey);
|
||||||
|
theDeviceList.add(theDevice);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
|
homegenieMap = null;
|
||||||
|
validHomeGenie = bridgeSettings.getBridgeSettingsDescriptor().isValidHomeGenie();
|
||||||
|
log.info("HomeGenie Home created." + (validHomeGenie ? "" : " No HomeGenies configured."));
|
||||||
|
if (validHomeGenie) {
|
||||||
|
homegenieMap = new HashMap<String, HomeGenieInstance>();
|
||||||
|
httpClient = HTTPHome.getHandler();
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHomegenieaddress().getDevices()
|
||||||
|
.iterator();
|
||||||
|
while (theList.hasNext() && validHomeGenie) {
|
||||||
|
NamedIP aHomeGenie = theList.next();
|
||||||
|
try {
|
||||||
|
homegenieMap.put(aHomeGenie.getName(), new HomeGenieInstance(aHomeGenie, httpClient));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get HomeGenie (" + aHomeGenie.getName() + ") setup, Exiting with message: "
|
||||||
|
+ e.getMessage(), e);
|
||||||
|
validHomeGenie = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if (!closed && validHomeGenie) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpClient != null)
|
||||||
|
httpClient.closeHandler();
|
||||||
|
|
||||||
|
homegenieMap = null;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class HomeGenieInstance {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeGenieInstance.class);
|
||||||
|
private NamedIP homegenieIP;
|
||||||
|
|
||||||
|
public HomeGenieInstance(NamedIP theNamedIp, HTTPHandler httpClient) {
|
||||||
|
homegenieIP = theNamedIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean callCommand(String deviceId, String moduleType, HomeGenieCommandDetail commandData,
|
||||||
|
HTTPHandler httpClient) {
|
||||||
|
log.debug("calling HomeGenie: {}:{}{}{}", homegenieIP.getIp(), homegenieIP.getPort(), moduleType,
|
||||||
|
commandData.getCommand());
|
||||||
|
String aUrl = null;
|
||||||
|
|
||||||
|
aUrl = homegenieIP.getHttpPreamble() + "/api/" + moduleType + "/" + deviceId + "/" + commandData.getCommand();
|
||||||
|
|
||||||
|
String theLevel = commandData.getLevel();
|
||||||
|
if (commandData.getCommand().contains("Level")) {
|
||||||
|
if (theLevel != null && theLevel.length() > 0)
|
||||||
|
aUrl = aUrl + "/" + theLevel;
|
||||||
|
else
|
||||||
|
aUrl = aUrl + "100";
|
||||||
|
}
|
||||||
|
|
||||||
|
String theData = httpClient.doHttpRequest(aUrl, HttpPut.METHOD_NAME, "application/json", null, httpClient.addBasicAuthHeader(null, homegenieIP));
|
||||||
|
log.debug("call Command return is: <<<{}>>>", theData);
|
||||||
|
if (theData.toLowerCase().contains("error"))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Module> getDevices(HTTPHandler httpClient) {
|
||||||
|
log.debug("calling HomeGenie: " + homegenieIP.getIp() + ":" + homegenieIP.getPort());
|
||||||
|
List<Module> deviceList = null;
|
||||||
|
Module[] hgModules;
|
||||||
|
String theUrl = null;
|
||||||
|
String theData;
|
||||||
|
|
||||||
|
theUrl = homegenieIP.getHttpPreamble() + "/api/HomeAutomation.HomeGenie/Config/Modules.List";
|
||||||
|
|
||||||
|
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, httpClient.addBasicAuthHeader(null, homegenieIP));
|
||||||
|
if (theData != null) {
|
||||||
|
log.debug("GET HomeGenie Devices - data: " + theData);
|
||||||
|
try {
|
||||||
|
hgModules = new Gson().fromJson(theData, Module[].class);
|
||||||
|
if (hgModules != null && hgModules.length > 0) {
|
||||||
|
deviceList = new ArrayList<Module>();
|
||||||
|
for (int i = 0; i < hgModules.length; i++) {
|
||||||
|
if (hgModules[i].isModuleValid(homegenieIP.getExtensions()))
|
||||||
|
deviceList.add(hgModules[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Cannot get devices for Homegenie {} Gson Parse Error.", homegenieIP.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedIP getHomegenieIP() {
|
||||||
|
return homegenieIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHomegenieIP(NamedIP homegenieIP) {
|
||||||
|
this.homegenieIP = homegenieIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void closeClient() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
// import java.util.List;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class Module {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeGenieInstance.class);
|
||||||
|
|
||||||
|
@SerializedName("Name")
|
||||||
|
@Expose
|
||||||
|
private String name;
|
||||||
|
@SerializedName("Description")
|
||||||
|
@Expose
|
||||||
|
private String description;
|
||||||
|
@SerializedName("DeviceType")
|
||||||
|
@Expose
|
||||||
|
private String deviceType;
|
||||||
|
@SerializedName("Domain")
|
||||||
|
@Expose
|
||||||
|
private String domain;
|
||||||
|
@SerializedName("Address")
|
||||||
|
@Expose
|
||||||
|
private String address;
|
||||||
|
/*
|
||||||
|
* @SerializedName("Properties")
|
||||||
|
*
|
||||||
|
* @Expose private List<Property> properties = null;
|
||||||
|
*/
|
||||||
|
@SerializedName("RoutingNode")
|
||||||
|
@Expose
|
||||||
|
private String routingNode;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceType() {
|
||||||
|
return deviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceType(String deviceType) {
|
||||||
|
this.deviceType = deviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDomain(String domain) {
|
||||||
|
this.domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public List<Property> getProperties() { return properties; }
|
||||||
|
*
|
||||||
|
* public void setProperties(List<Property> properties) { this.properties =
|
||||||
|
* properties; }
|
||||||
|
*/
|
||||||
|
public String getRoutingNode() {
|
||||||
|
return routingNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoutingNode(String routingNode) {
|
||||||
|
this.routingNode = routingNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSwitch() {
|
||||||
|
return isDeviceType("Switch");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDimmer() {
|
||||||
|
return isDeviceType("Dimmer");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLight() {
|
||||||
|
return isDeviceType("Light");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDeviceType(String theType) {
|
||||||
|
if (deviceType.equals(theType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModuleValid(JsonObject theExtensions) {
|
||||||
|
ModuleTypes moduleTypes = null;
|
||||||
|
if (this.name == null || this.name.trim().isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isSwitch())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isDimmer())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isLight())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (theExtensions != null && theExtensions.isJsonObject() && theExtensions.get("moduleTypes").isJsonArray()) {
|
||||||
|
try {
|
||||||
|
moduleTypes = new Gson().fromJson(theExtensions, ModuleTypes.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Could not parse extensions for {} with {}", this.name, theExtensions);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleTypes == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (ModuleType moduleType : moduleTypes.getModuleTypes()) {
|
||||||
|
if (isDeviceType(moduleType.getModuleType()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class ModuleType {
|
||||||
|
|
||||||
|
@SerializedName("moduleType")
|
||||||
|
@Expose
|
||||||
|
private String moduleType;
|
||||||
|
|
||||||
|
public String getModuleType() {
|
||||||
|
return moduleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleType(String moduleType) {
|
||||||
|
this.moduleType = moduleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class ModuleTypes {
|
||||||
|
|
||||||
|
@SerializedName("moduleTypes")
|
||||||
|
@Expose
|
||||||
|
private List<ModuleType> moduleTypes = null;
|
||||||
|
|
||||||
|
public List<ModuleType> getModuleTypes() {
|
||||||
|
return moduleTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleTypes(List<ModuleType> moduleTypes) {
|
||||||
|
this.moduleTypes = moduleTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
package com.bwssystems.HABridge.plugins.homegenie;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Property {
|
||||||
|
|
||||||
|
@SerializedName("Name")
|
||||||
|
@Expose
|
||||||
|
private String name;
|
||||||
|
@SerializedName("Value")
|
||||||
|
@Expose
|
||||||
|
private String value;
|
||||||
|
@SerializedName("Description")
|
||||||
|
@Expose
|
||||||
|
private String description;
|
||||||
|
@SerializedName("FieldType")
|
||||||
|
@Expose
|
||||||
|
private String fieldType;
|
||||||
|
@SerializedName("UpdateTime")
|
||||||
|
@Expose
|
||||||
|
private String updateTime;
|
||||||
|
@SerializedName("NeedsUpdate")
|
||||||
|
@Expose
|
||||||
|
private Boolean needsUpdate;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldType() {
|
||||||
|
return fieldType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldType(String fieldType) {
|
||||||
|
this.fieldType = fieldType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdateTime() {
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateTime(String updateTime) {
|
||||||
|
this.updateTime = updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getNeedsUpdate() {
|
||||||
|
return needsUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNeedsUpdate(Boolean needsUpdate) {
|
||||||
|
this.needsUpdate = needsUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homewizard;
|
||||||
|
|
||||||
|
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.BridgeSettings;
|
||||||
|
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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control HomeWizard devices over HomeWizard Cloud
|
||||||
|
*
|
||||||
|
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HomeWizardHome implements Home {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeWizardHome.class);
|
||||||
|
|
||||||
|
private Map<String, HomeWizzardSmartPlugInfo> plugGateways;
|
||||||
|
private Boolean validHomeWizard;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
|
public HomeWizardHome(BridgeSettings bridgeSettings) {
|
||||||
|
super();
|
||||||
|
closed = true;
|
||||||
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||||
|
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
|
|
||||||
|
String responseString = null;
|
||||||
|
if (!validHomeWizard) {
|
||||||
|
|
||||||
|
log.warn("Should not get here, no HomeWizard smart plug available");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug available\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||||
|
|
||||||
|
String jsonToPost = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
|
log.debug("Executing HUE api request to change activity to HomeWizard smart plug: {}", jsonToPost);
|
||||||
|
|
||||||
|
HomeWizzardSmartPlugInfo homeWizzardHandler = getHomeWizzardHandler(device.getTargetDevice());
|
||||||
|
if(homeWizzardHandler == null) {
|
||||||
|
log.warn("Should not get here, no HomeWizard smart plug configured");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug configured\", \"parameter\": \"/lights/"
|
||||||
|
+ lightId + "/state\"}}]";
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
homeWizzardHandler.execApply(jsonToPost);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
log.warn("Error posting request to HomeWizard smart plug");
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||||
|
+ "\",\"description\": \"Error posting request to HomeWizard smart plug\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HomeWizzardSmartPlugInfo getHomeWizzardHandler(String plugName) {
|
||||||
|
return plugGateways.get(plugName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HomeWizardSmartPlugDevice> getDevices() {
|
||||||
|
|
||||||
|
log.debug("consolidating devices for HomeWizard plug gateways");
|
||||||
|
Iterator<String> keys = plugGateways.keySet().iterator();
|
||||||
|
ArrayList<HomeWizardSmartPlugDevice> deviceList = new ArrayList<>();
|
||||||
|
|
||||||
|
while(keys.hasNext())
|
||||||
|
{
|
||||||
|
String key = keys.next();
|
||||||
|
for(HomeWizardSmartPlugDevice device : plugGateways.get(key).getDevices())
|
||||||
|
deviceList.add(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItems(String type) {
|
||||||
|
|
||||||
|
if (validHomeWizard)
|
||||||
|
{
|
||||||
|
if (type.equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]))
|
||||||
|
{
|
||||||
|
return getDevices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
|
|
||||||
|
validHomeWizard = bridgeSettings.getBridgeSettingsDescriptor().isValidHomeWizard();
|
||||||
|
log.info("HomeWizard Home created. " + (validHomeWizard ? "" : "No HomeWizard gateways configured."));
|
||||||
|
|
||||||
|
if (validHomeWizard)
|
||||||
|
{
|
||||||
|
plugGateways = new HashMap<>();
|
||||||
|
Iterator<NamedIP> gatewaysList = bridgeSettings.getBridgeSettingsDescriptor().getHomeWizardAddress().getDevices().iterator();
|
||||||
|
|
||||||
|
while(gatewaysList.hasNext()) {
|
||||||
|
|
||||||
|
NamedIP gateway = gatewaysList.next();
|
||||||
|
plugGateways.put(gateway.getName(), new HomeWizzardSmartPlugInfo(gateway, gateway.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeHome() {
|
||||||
|
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugGateways = null;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homewizard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control HomeWizard devices over HomeWizard Cloud
|
||||||
|
*
|
||||||
|
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HomeWizardSmartPlugDevice {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String gateway;
|
||||||
|
private String id;
|
||||||
|
private String typeName;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGateway() {
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGateway(String gateway) {
|
||||||
|
this.gateway = gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeName() {
|
||||||
|
return this.typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeName(String typeName) {
|
||||||
|
this.typeName = typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homewizard;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.plugins.homewizard.json.Device;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control HomeWizard devices over HomeWizard Cloud
|
||||||
|
*
|
||||||
|
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HomeWizzardSmartPlugInfo {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HomeWizardHome.class);
|
||||||
|
|
||||||
|
private static final String HOMEWIZARD_LOGIN_URL = "https://cloud.homewizard.com/account/login";
|
||||||
|
private static final String HOMEWIZARD_API_URL = "https://plug.homewizard.com/plugs";
|
||||||
|
private static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
|
private final String cloudAuth;
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
|
private String cloudSessionId;
|
||||||
|
private String cloudPlugName;
|
||||||
|
private String cloudPlugId;
|
||||||
|
|
||||||
|
public HomeWizzardSmartPlugInfo(NamedIP gateway, String name) {
|
||||||
|
|
||||||
|
super();
|
||||||
|
|
||||||
|
cloudAuth = "Basic " + gateway.getUserPass64();
|
||||||
|
cloudPlugName = name;
|
||||||
|
gson = new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean login()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = new URL(HOMEWIZARD_LOGIN_URL);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setRequestProperty("Authorization", cloudAuth);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
buffer.append(line).append("\n");
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
// Get session id from result JSON
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
JsonObject json = parser.parse(buffer.toString()).getAsJsonObject();
|
||||||
|
|
||||||
|
cloudSessionId = json.get("session").getAsString();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
log.warn("Error while login to cloud service ", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requestJson(String request)
|
||||||
|
{
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
// Check login was successful
|
||||||
|
if (login()) {
|
||||||
|
|
||||||
|
// Request JSON from Cloud service
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = new URL(HOMEWIZARD_API_URL + request);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setRequestProperty("X-Session-Token", cloudSessionId);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
buffer.append(line).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
result = buffer.toString();
|
||||||
|
result = StringUtils.strip(result, "[]");
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
log.warn("Error while get json request: {} ", request, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sendAction(String request, String action)
|
||||||
|
{
|
||||||
|
boolean result = true;
|
||||||
|
|
||||||
|
// Check login was successful
|
||||||
|
if (login()) {
|
||||||
|
|
||||||
|
// Post action into Cloud service
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = new URL(HOMEWIZARD_API_URL + request);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
JsonObject actionJson = new JsonObject();
|
||||||
|
actionJson.addProperty("action", StringUtils.capitalize(action));
|
||||||
|
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setRequestProperty("X-Session-Token", cloudSessionId);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
|
||||||
|
|
||||||
|
OutputStream os = connection.getOutputStream();
|
||||||
|
os.write(actionJson.toString().getBytes("UTF-8"));
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
buffer.append(line).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
br.close();
|
||||||
|
connection.disconnect();
|
||||||
|
|
||||||
|
// Check if request was Ok
|
||||||
|
if (!buffer.toString().contains("Success"))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
log.warn("Error while post json action: {} ", request, e);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HomeWizardSmartPlugDevice> getDevices()
|
||||||
|
{
|
||||||
|
List<HomeWizardSmartPlugDevice> homewizardDevices = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
String result = requestJson(EMPTY_STRING);
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
JsonObject resultJson = parser.parse(result).getAsJsonObject();
|
||||||
|
cloudPlugId = resultJson.get("id").getAsString();
|
||||||
|
|
||||||
|
String all_devices_json = resultJson.get("devices").toString();
|
||||||
|
Device[] devices = gson.fromJson(all_devices_json, Device[].class);
|
||||||
|
|
||||||
|
// Fix names from JSON
|
||||||
|
for (Device device : devices) {
|
||||||
|
device.setTypeName(StringUtils.capitalize(device.getTypeName().replace("_", " ")));
|
||||||
|
homewizardDevices.add(mapDeviceToHomeWizardSmartPlugDevice(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
log.warn("Error while get devices from cloud service ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Found: " + homewizardDevices.size() + " devices");
|
||||||
|
return homewizardDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execApply(String jsonToPost) throws Exception {
|
||||||
|
|
||||||
|
// Extract
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
JsonObject resultJson = parser.parse(jsonToPost).getAsJsonObject();
|
||||||
|
String deviceId = resultJson.get("deviceid").getAsString();
|
||||||
|
String action = resultJson.get("action").getAsString();
|
||||||
|
|
||||||
|
// Check if we have an plug id stored
|
||||||
|
if (StringUtils.isBlank(cloudPlugId)) {
|
||||||
|
getDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send request to HomeWizard cloud
|
||||||
|
if (!sendAction("/" + cloudPlugId + "/devices/" + deviceId + "/action", action))
|
||||||
|
{
|
||||||
|
throw new IOException("Send action to HomeWizard Cloud failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HomeWizardSmartPlugDevice mapDeviceToHomeWizardSmartPlugDevice(Device device) {
|
||||||
|
HomeWizardSmartPlugDevice homewizardDevice = new HomeWizardSmartPlugDevice();
|
||||||
|
homewizardDevice.setId(device.getId());
|
||||||
|
homewizardDevice.setGateway(cloudPlugName);
|
||||||
|
homewizardDevice.setName(device.getName());
|
||||||
|
homewizardDevice.setTypeName(device.getTypeName());
|
||||||
|
|
||||||
|
return homewizardDevice;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.bwssystems.HABridge.plugins.homewizard.json;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control HomeWizard devices over HomeWizard Cloud
|
||||||
|
*
|
||||||
|
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Device {
|
||||||
|
|
||||||
|
@SerializedName("id")
|
||||||
|
@Expose
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName("name")
|
||||||
|
@Expose
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName("typeName")
|
||||||
|
@Expose
|
||||||
|
private String typeName;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeName() {
|
||||||
|
return this.typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeName(String typeName) {
|
||||||
|
this.typeName = typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,55 +5,72 @@ import java.net.URI;
|
|||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.client.ClientProtocolException;
|
||||||
import org.apache.http.client.config.CookieSpecs;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
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.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.HttpClients;
|
|
||||||
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;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.HABridge.api.NameValue;
|
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 CloseableHttpClient httpClient;
|
private String callType;
|
||||||
private RequestConfig globalConfig;
|
|
||||||
|
|
||||||
|
|
||||||
public HTTPHandler() {
|
public HTTPHandler() {
|
||||||
globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
super();
|
||||||
httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
|
callType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HTTPHandler(String type) {
|
||||||
|
super();
|
||||||
|
callType = type;
|
||||||
|
}
|
||||||
|
|
||||||
// This function executes the url from the device repository against the
|
// This function executes the url from the device repository against the
|
||||||
// target as http or https as defined
|
// target as http or https as defined
|
||||||
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
|
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
|
||||||
log.debug("doHttpRequest with url: " + url + " with http command: " + httpVerb + " with body: " + body);
|
|
||||||
HttpUriRequest request = null;
|
HttpUriRequest request = null;
|
||||||
String theContent = null;
|
String theContent = null;
|
||||||
URI theURI = null;
|
URI theURI = null;
|
||||||
|
boolean usingSSL = false;
|
||||||
ContentType parsedContentType = null;
|
ContentType parsedContentType = null;
|
||||||
StringEntity requestBody = null;
|
StringEntity requestBody = null;
|
||||||
|
|
||||||
|
log.debug("doHttpRequest with url <<<" + url + ">>>, verb: " + httpVerb + ", contentType: " + contentType
|
||||||
|
+ ", body <<<" + body + ">>>");
|
||||||
|
if (headers != null && headers.length > 0) {
|
||||||
|
for (int i = 0; i < headers.length; i++) {
|
||||||
|
log.debug("header index " + i + " name: <<<" + headers[i].getName() + ">>>, value: <<<"
|
||||||
|
+ headers[i].getValue() + ">>>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (contentType != null && !contentType.trim().isEmpty()) {
|
if (contentType != null && !contentType.trim().isEmpty()) {
|
||||||
parsedContentType = ContentType.parse(contentType);
|
parsedContentType = ContentType.parse(contentType);
|
||||||
if (body != null && body.length() > 0)
|
if (body != null && body.length() > 0)
|
||||||
requestBody = new StringEntity(body, parsedContentType);
|
requestBody = new StringEntity(body, parsedContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (url.startsWith("https:")) {
|
||||||
|
usingSSL = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
theURI = new URI(url);
|
theURI = new URI(url);
|
||||||
} catch (URISyntaxException e1) {
|
} catch (URISyntaxException e1) {
|
||||||
log.warn("Error creating URI http request: " + url + " with message: " + e1.getMessage());
|
log.warn("Error creating URI http request: " + url + " with message: " + e1.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (httpVerb == null || httpVerb.trim().isEmpty() || HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb)) {
|
if (httpVerb == null || httpVerb.trim().isEmpty() || HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb)) {
|
||||||
request = new HttpGet(theURI);
|
request = new HttpGet(theURI);
|
||||||
@@ -67,93 +84,124 @@ public class HTTPHandler {
|
|||||||
if (requestBody != null)
|
if (requestBody != null)
|
||||||
putRequest.setEntity(requestBody);
|
putRequest.setEntity(requestBody);
|
||||||
request = putRequest;
|
request = putRequest;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
request = new HttpGet(theURI);
|
request = new HttpGet(theURI);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
log.warn("Error creating outbound http request: IllegalArgumentException in log", e);
|
log.warn("Error creating outbound http request: IllegalArgumentException in log", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
log.debug("Making outbound call in doHttpRequest: " + request);
|
log.debug("Making outbound call in doHttpRequest: <<<" + request.toString() + ">>>");
|
||||||
if (headers != null && headers.length > 0) {
|
if (headers != null && headers.length > 0) {
|
||||||
for (int i = 0; i < headers.length; i++) {
|
for (int i = 0; i < headers.length; i++) {
|
||||||
request.setHeader(headers[i].getName(), headers[i].getValue());
|
request.setHeader(headers[i].getName(), headers[i].getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HttpResponse response;
|
CloseableHttpResponse response = null;
|
||||||
try {
|
for (int retryCount = 0; retryCount < 2; retryCount++) {
|
||||||
for(int retryCount = 0; retryCount < 2; retryCount++) {
|
try {
|
||||||
response = httpClient.execute(request);
|
if (usingSSL) {
|
||||||
|
response = HttpClientPool.getSSLClient().execute(request);
|
||||||
|
} else {
|
||||||
|
response = HttpClientPool.getClient().execute(request);
|
||||||
|
}
|
||||||
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") 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 != null && response.getEntity() != null) {
|
||||||
if (response.getEntity() != null) {
|
|
||||||
try {
|
|
||||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
|
||||||
// content
|
|
||||||
// for
|
|
||||||
// data
|
|
||||||
EntityUtils.consume(response.getEntity()); // close out
|
|
||||||
// inputstream
|
|
||||||
// ignore
|
|
||||||
// content
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
|
|
||||||
+ e.getMessage(), e);
|
|
||||||
}
|
|
||||||
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
|
||||||
}
|
|
||||||
retryCount = 2;
|
|
||||||
} else {
|
|
||||||
log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
|
|
||||||
try {
|
try {
|
||||||
String someContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
|
||||||
// content
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
||||||
// for
|
// content
|
||||||
// data
|
// for
|
||||||
|
// data
|
||||||
|
|
||||||
EntityUtils.consume(response.getEntity()); // close out
|
EntityUtils.consume(response.getEntity()); // close out
|
||||||
// inputstream
|
// inputstream
|
||||||
// ignore
|
// ignore
|
||||||
// content
|
// content
|
||||||
log.debug("Unsuccessfull response - The http response is <<<" + someContent + ">>>");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//noop
|
log.debug(
|
||||||
|
"Error ocurred in handling response entity after successful call, still responding success. "
|
||||||
|
+ e.getMessage(),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (response != null && response.getStatusLine().getStatusCode() >= 200
|
||||||
|
&& response.getStatusLine().getStatusCode() < 300) {
|
||||||
|
if (theContent == null)
|
||||||
|
theContent = "";
|
||||||
|
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||||
|
retryCount = 2;
|
||||||
|
} else if (DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex].equals(callType)
|
||||||
|
&& response.getStatusLine().getStatusCode() == 302) {
|
||||||
|
if (theContent == null)
|
||||||
|
theContent = "";
|
||||||
|
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||||
|
retryCount = 2;
|
||||||
|
} else if (response != null) {
|
||||||
|
log.warn(
|
||||||
|
"HTTP response code was not an expected successful response of between 200 - 299, the code was: "
|
||||||
|
+ response.getStatusLine() + " with the content of <<<" + theContent + ">>>");
|
||||||
if (response.getStatusLine().getStatusCode() == 504) {
|
if (response.getStatusLine().getStatusCode() == 504) {
|
||||||
log.warn("HTTP response code was 504, retrying...");
|
log.warn("HTTP response code was 504, retrying...");
|
||||||
try {
|
log.debug("The 504 error content is <<<" + theContent + ">>>");
|
||||||
Thread.sleep(1000);
|
theContent = null;
|
||||||
} catch (InterruptedException e1) {
|
} else
|
||||||
// noop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
retryCount = 2;
|
retryCount = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (ClientProtocolException e) {
|
||||||
|
log.warn("Client Protocol Exception received, retyring....");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage(), e);
|
||||||
|
retryCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retryCount < 2) {
|
||||||
|
theContent = null;
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e1) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
|
||||||
}
|
}
|
||||||
return theContent;
|
return theContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public HttpClient getHttpClient() {
|
public NameValue[] addBasicAuthHeader(NameValue[] theHeaders, NamedIP theTarget) {
|
||||||
// return httpClient;
|
NameValue[] headers = null;
|
||||||
// }
|
int index = 0;
|
||||||
|
String encodedLogin = theTarget.getUserPass64();
|
||||||
|
if (encodedLogin != null && !encodedLogin.trim().isEmpty()) {
|
||||||
|
if (theHeaders != null && theHeaders.length > 0) {
|
||||||
|
headers = new NameValue[theHeaders.length + 1];
|
||||||
|
for(int i = 0; i < theHeaders.length; i++) {
|
||||||
|
headers[i] = theHeaders[i];
|
||||||
|
}
|
||||||
|
index = theHeaders.length;
|
||||||
|
} else {
|
||||||
|
headers = new NameValue[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("creating login for {} with username {} password len {}", theTarget.getName(),
|
||||||
|
theTarget.getUsername(), theTarget.getPassword().length());
|
||||||
|
headers[index] = new NameValue();
|
||||||
|
headers[index].setName("Authorization");
|
||||||
|
// log.debug("Encoded login info {}", encodedLogin);
|
||||||
|
headers[index].setValue("Basic " + encodedLogin);
|
||||||
|
} else {
|
||||||
|
headers = theHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
|
||||||
public CloseableHttpClient getHttpClient() {
|
|
||||||
return httpClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCallType(String callType) {
|
||||||
|
this.callType = callType;
|
||||||
|
}
|
||||||
|
|
||||||
public void closeHandler() {
|
public void closeHandler() {
|
||||||
try {
|
|
||||||
httpClient.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
httpClient = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge.plugins.http;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettings;
|
||||||
import com.bwssystems.HABridge.Home;
|
import com.bwssystems.HABridge.Home;
|
||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
import com.bwssystems.HABridge.api.NameValue;
|
import com.bwssystems.HABridge.api.NameValue;
|
||||||
@@ -11,26 +11,40 @@ 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.ColorData;
|
||||||
|
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
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.plugins.fibaro.FibaroTestData;
|
||||||
|
import com.bwssystems.HABridge.plugins.vera.VeraTestData;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class HTTPHome implements Home {
|
public class HTTPHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HTTPHome.class);
|
private static final Logger log = LoggerFactory.getLogger(HTTPHome.class);
|
||||||
private HTTPHandler anHttpHandler;
|
private static HTTPHandler anHttpHandler = null;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public HTTPHome(BridgeSettingsDescriptor bridgeSettings) {
|
public HTTPHome(BridgeSettings bridgeSettings) {
|
||||||
super();
|
super();
|
||||||
|
closed = true;
|
||||||
createHome(bridgeSettings);
|
createHome(bridgeSettings);
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HTTPHandler getHandler() {
|
||||||
|
if(anHttpHandler == null)
|
||||||
|
anHttpHandler = new HTTPHandler();
|
||||||
|
return anHttpHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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, ColorData colorData, DeviceDescriptor device, String body) {
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
|
|
||||||
String theUrl = anItem.getItem().getAsString();
|
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||||
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
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())
|
||||||
@@ -50,6 +64,9 @@ public class HTTPHome implements Home {
|
|||||||
|
|
||||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
|
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
|
||||||
intensity, targetBri, targetBriInc, false);
|
intensity, targetBri, targetBriInc, false);
|
||||||
|
if (colorData != null) {
|
||||||
|
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||||
|
|
||||||
@@ -57,31 +74,50 @@ public class HTTPHome implements Home {
|
|||||||
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);
|
||||||
|
if (colorData != null) {
|
||||||
|
aBody = ColorDecode.replaceColorData(aBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||||
|
}
|
||||||
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
|
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
|
||||||
aBody = TimeDecode.replaceTimeValue(aBody);
|
aBody = TimeDecode.replaceTimeValue(aBody);
|
||||||
}
|
}
|
||||||
// make call
|
// make call
|
||||||
if (anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody,
|
String httpReply = anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody, new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class));
|
||||||
new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class)) == null) {
|
if (httpReply == null) {
|
||||||
log.warn("Error on calling url to change device state: " + anUrl);
|
log.warn("Error on calling url to change device state: " + anUrl);
|
||||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isDevMode)
|
||||||
|
log.info("Dev Mode response dump <<<" + httpReply +">>>");
|
||||||
} else {
|
} else {
|
||||||
log.warn("HTTP Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
|
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,
|
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||||
"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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettings bridgeSettings) {
|
||||||
anHttpHandler = new HTTPHandler();
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
log.info("Http Home created.");
|
log.info("HTTP Home created." + (isDevMode ? " DevMode is set." : ""));
|
||||||
|
if(isDevMode) {
|
||||||
|
anHttpHandler = new HttpTestHandler();
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("id=sdata", VeraTestData.SDataTestData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("action=SetLoadLevelTarget", VeraTestData.SetLoadLevelTargetData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("action=SetTarget", VeraTestData.SetTargetData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("action=RunScene", VeraTestData.RunSceneData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("/api/callAction", FibaroTestData.CallActionTestData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData("/api/sceneControl", FibaroTestData.SceneControlTestData);
|
||||||
|
((HttpTestHandler)anHttpHandler).setTheData(null, "generic treply - no match");
|
||||||
|
|
||||||
|
}
|
||||||
|
if(anHttpHandler == null)
|
||||||
|
anHttpHandler = new HTTPHandler();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,9 +129,19 @@ public class HTTPHome implements Home {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeHome() {
|
public void closeHome() {
|
||||||
|
log.debug("Closing Home.");
|
||||||
|
if(closed) {
|
||||||
|
log.debug("Home is already closed....");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(anHttpHandler != null)
|
if(anHttpHandler != null)
|
||||||
anHttpHandler.closeHandler();
|
anHttpHandler.closeHandler();
|
||||||
anHttpHandler = null;
|
anHttpHandler = null;
|
||||||
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user