mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
22 Commits
v4.5.0alph
...
v4.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
409c93bfb2 | ||
|
|
543a79bb66 | ||
|
|
16d1054b96 | ||
|
|
165b6ef9bb | ||
|
|
fb94b858f6 | ||
|
|
ea80925533 | ||
|
|
62b896ee07 | ||
|
|
8657ea6704 | ||
|
|
05bd6b6d77 | ||
|
|
19256e4eaa | ||
|
|
905f6aa9ec | ||
|
|
daa0dac5b9 | ||
|
|
0478fc69f4 | ||
|
|
b99e74823c | ||
|
|
ebeb6be7a7 | ||
|
|
d3979da2b4 | ||
|
|
f276f66991 | ||
|
|
3ac5c10f08 | ||
|
|
13c84ba174 | ||
|
|
b19fe5c86a | ||
|
|
ff9d0a5a77 | ||
|
|
50af884563 |
106
README.md
106
README.md
@@ -1,5 +1,5 @@
|
||||
# ha-bridge
|
||||
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo or Google Home. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
|
||||
Emulates Philips Hue API to other home automation gateways such as an Amazon Echo or other systems that support Philips Hue. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
|
||||
|
||||
Here are some diagrams to put this software in perspective.
|
||||
|
||||
@@ -35,9 +35,11 @@ THe Harmony Hub Path looks like this:
|
||||
|
||||
**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 now seems to 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**
|
||||
|
||||
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 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.
|
||||
|
||||
@@ -59,24 +61,19 @@ ATTENTION: This requires JDK 1.8 to run
|
||||
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
|
||||
|
||||
```
|
||||
java -jar ha-bridge-4.5.0.jar
|
||||
java -jar ha-bridge-4.5.1.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.5.0.jar is in your /home/pi/habridge directory.
|
||||
Create the directory and make sure that ha-bridge-4.5.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.5.0/ha-bridge-4.5.0.jar
|
||||
```
|
||||
Create the directory and make sure that ha-bridge-4.5.0.jar is in your /home/pi/habridge directory.
|
||||
```
|
||||
pi@raspberrypi:~ $ mkdir habridge
|
||||
pi@raspberrypi:~ $ cd habridge
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.0/ha-bridge-4.5.0.jar
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.1/ha-bridge-4.5.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
|
||||
|
||||
@@ -95,7 +92,7 @@ After=network.target
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/home/pi/habridge
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.0.jar
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.1.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -130,7 +127,7 @@ Then cut and past this, modify any locations that are not correct
|
||||
```
|
||||
cd /home/pi/habridge
|
||||
rm /home/pi/habridge/habridge-log.txt
|
||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.1.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
|
||||
chmod 777 /home/pi/habridge/habridge-log.txt
|
||||
```
|
||||
@@ -148,12 +145,14 @@ pi@raspberrypi:~/habridge $ tail -f habridge-log.txt
|
||||
```
|
||||
## Run ha-bridge alongside web server already on port 80
|
||||
These examples will help you proxy your current webserver requests to the ha-bridge running on a different port, such as 8080.
|
||||
|
||||
### Apache Example
|
||||
|
||||
Reverse proxy with Apache on Ubuntu linux:
|
||||
|
||||
a2enmod proxy
|
||||
a2enmod proxy_http
|
||||
a2enmod headers
|
||||
Enable the required Apache modules:
|
||||
|
||||
`a2enmod proxy proxy_http headers`
|
||||
|
||||
Added the following lines to my Apache config file “000-default”
|
||||
|
||||
@@ -175,7 +174,10 @@ Added the following lines to my Apache config file “000-default”
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
service apache2 restart
|
||||
Restart apache for the changes to take effect.
|
||||
|
||||
`service apache2 restart`
|
||||
|
||||
### lighthttpd Example
|
||||
```
|
||||
server.modules += ( "mod_proxy" )
|
||||
@@ -214,10 +216,15 @@ 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
|
||||
```
|
||||
### -Dsecurity.key=`<Your Key To Encrypt Security Data>`
|
||||
The default security key is encoded into the Java code. This should not be used as anyone with access to the code can decode your passworsd. To override what 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 haced. The command line example:
|
||||
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
|
||||
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.
|
||||
@@ -225,6 +232,10 @@ favorite web interface by going to the http://<my ip address>:<port> or http://l
|
||||
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.
|
||||
|
||||
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.
|
||||
#### Renumber Devices
|
||||
This changes the numbering of the added devices to start at 1 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 ue 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 doign a discovery.
|
||||
### 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.
|
||||
#### Bridge server
|
||||
@@ -232,7 +243,7 @@ This field is used to test the bridge server with the UPNP IP Address and to mak
|
||||
#### 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.
|
||||
#### The Security Dialog
|
||||
This is where you can set the different security settings for the ha-bridge.
|
||||
This is where you can set the different security settings for the ha-bridge. There are two settings, one for enabling Hue like operation to secure the Hue API with the internally generated user for the calls that are done after the link button. The other is to secure the hue API with a username/password that is created as well. 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.
|
||||
#### 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.
|
||||
#### Device DB Path and File
|
||||
@@ -410,7 +421,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
|
||||
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.
|
||||
|
||||
@@ -420,16 +431,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...
|
||||
--------------|------------
|
||||
ON Commands |
|
||||
| Alexa, turn on `<Device Name>`
|
||||
OFF Commands |
|
||||
| Alexa, turn off `<Device Name>`
|
||||
DIM Commands |
|
||||
| Alexa, brighten `<Device Name>` to `<Position>`
|
||||
| Alexa, dim `<Device Name>` to `<Position>`
|
||||
| Alexa, brighten `<Device Name>`
|
||||
| Alexa, dim `<Device Name>`
|
||||
| Alexa, set `<Device Name>` to `<Position>`
|
||||
ON Commands | Alexa, turn on `<Device Name>`
|
||||
OFF Commands | Alexa, turn off `<Device Name>`
|
||||
DIM Commands | Alexa, brighten `<Device Name>` to `<Position>`
|
||||
DIM Commands| Alexa, dim `<Device Name>` to `<Position>`
|
||||
DIM Commands| Alexa, brighten `<Device Name>`
|
||||
DIM Commands| Alexa, dim `<Device Name>`
|
||||
DIM Commands| Alexa, set `<Device Name>` to `<Position>`
|
||||
|
||||
To see what Alexa thinks you said, you can check in the home page for your Alexa.
|
||||
|
||||
@@ -438,6 +446,8 @@ To view or remove devices that Alexa knows about, you can use the mobile app `Me
|
||||
## Google Assistant
|
||||
Google Home is supported as of v3.2.0 and forward, but only if the bridge is running on port 80.
|
||||
|
||||
**ISSUE: Google Home now seems to 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 / +`
|
||||
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
|
||||
@@ -468,7 +478,7 @@ New or removed devices are picked up automatically as soon as they are added/rem
|
||||
No re-discovery step is necessary.
|
||||
|
||||
## Configuration REST API Usage
|
||||
This section will describe the REST api available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this:
|
||||
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"}
|
||||
```
|
||||
@@ -500,8 +510,8 @@ contentBodyOff | string | This is the content body that you would like to send w
|
||||
{
|
||||
"name" : "bedroom light",
|
||||
"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"}],
|
||||
"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"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
#### Dimming Control Example
|
||||
@@ -511,8 +521,8 @@ e.g.
|
||||
{
|
||||
"name": "entry light",
|
||||
"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"}],
|
||||
"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"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
See the echo's documentation for the dimming phrase.
|
||||
@@ -524,8 +534,8 @@ e.g.
|
||||
{
|
||||
"name": "Thermostat,
|
||||
"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"}],
|
||||
"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"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
See the echo's documentation for the dimming phrase.
|
||||
@@ -537,8 +547,8 @@ e.g:
|
||||
{
|
||||
"name": "test device",
|
||||
"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\"}],
|
||||
"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\"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
#### Custom Usage URLs Example
|
||||
@@ -547,8 +557,8 @@ Anything that takes an action as a result of an HTTP request will probably work
|
||||
{
|
||||
"name": "night mode",
|
||||
"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"}],
|
||||
"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"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
Here is a UDP example that can send binary data.
|
||||
@@ -556,8 +566,8 @@ Here is a UDP example that can send binary data.
|
||||
{
|
||||
"name": "UDPPacket",
|
||||
"deviceType": "custom",
|
||||
"offUrl": [{"item":"udp://192.168.1.1:8899/0x460055","type":"udpDevice"}],
|
||||
"onUrl": [{"item":"udp://192.168.1.1:8899/0x450055","type":"udpDevice"}]
|
||||
"offUrl": "[{\"item\":\"udp://192.168.1.1:8899/0x460055\",\"type\":\"udpDevice\"}]",
|
||||
"onUrl": "[{\"item\":\"udp://192.168.1.1:8899/0x450055\",\"type\":\"udpDevice\"}]"
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
@@ -616,8 +626,8 @@ contentBodyOff | string | This is the content body that you would like to send w
|
||||
"id" : "6789",
|
||||
"name" : "table light",
|
||||
"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"}],
|
||||
"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"}]
|
||||
"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\"}]"
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
@@ -870,7 +880,7 @@ The example below is representative of some HUE device responses.
|
||||
|
||||
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.
|
||||
hueaddress | string | The address of the target HUE bridge.
|
||||
huename | string | A name given to the target HUE bridge.
|
||||
@@ -879,7 +889,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"}]
|
||||
```
|
||||
## 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"}
|
||||
```
|
||||
@@ -988,7 +998,7 @@ A response to a successful PUT request contains confirmation of the arguments pa
|
||||
]
|
||||
```
|
||||
### 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
|
||||
```
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>4.5.0alpha-3</version>
|
||||
<version>4.5.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -5,6 +5,12 @@ 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;
|
||||
@@ -15,6 +21,9 @@ 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;
|
||||
|
||||
@@ -23,16 +32,20 @@ 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 char[] habridgeKey;
|
||||
private String execGarden;
|
||||
private BridgeSecurityDescriptor securityDescriptor;
|
||||
private boolean settingsChanged;
|
||||
|
||||
public BridgeSecurity(char[] theKey) {
|
||||
public BridgeSecurity(char[] theKey, String theExecGarden) {
|
||||
habridgeKey = theKey;
|
||||
execGarden = theExecGarden;
|
||||
securityDescriptor = null;
|
||||
settingsChanged = false;
|
||||
}
|
||||
@@ -49,7 +62,8 @@ public class BridgeSecurity {
|
||||
} catch (IOException e) {
|
||||
anError = e.getMessage();
|
||||
}
|
||||
log.warn("Cound not get security data, using default security (none): " + anError);
|
||||
if(anError != null)
|
||||
log.warn("Cound not get security data, using default security (none): " + anError);
|
||||
}
|
||||
|
||||
if(theData == null || anError != null) {
|
||||
@@ -129,13 +143,8 @@ public class BridgeSecurity {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setExecGarden(String theGarden) {
|
||||
securityDescriptor.setExecGarden(theGarden);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
public String getExecGarden() {
|
||||
return securityDescriptor.getExecGarden();
|
||||
return execGarden;
|
||||
}
|
||||
public void setUseLinkButton(boolean useThis) {
|
||||
securityDescriptor.setUseLinkButton(useThis);
|
||||
@@ -151,7 +160,6 @@ public class BridgeSecurity {
|
||||
}
|
||||
public SecurityInfo getSecurityInfo() {
|
||||
SecurityInfo theInfo = new SecurityInfo();
|
||||
theInfo.setExecGarden(getExecGarden());
|
||||
theInfo.setUseLinkButton(isUseLinkButton());
|
||||
theInfo.setSecureHueApi(isSecureHueApi());
|
||||
theInfo.setSecure(isSecure());
|
||||
@@ -194,6 +202,91 @@ public class BridgeSecurity {
|
||||
this.settingsChanged = settingsChanged;
|
||||
}
|
||||
|
||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
||||
&& !aUser.equalsIgnoreCase("")) {
|
||||
if (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 it is strict rules <" + aUser + ">");
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser == null ? "" : aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newWhitelistUser(String aUser, String userDescription) {
|
||||
if(aUser.equals(DEPRACATED_INTERNAL_USER))
|
||||
return;
|
||||
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 = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
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 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();
|
||||
it.remove(); // avoids a ConcurrentModificationException
|
||||
if(pair.getValue().getName().equals(TEST_USER_TYPE)) {
|
||||
securityDescriptor.getWhitelist().remove(pair.getKey());
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
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;
|
||||
|
||||
public BridgeSecurityDescriptor() {
|
||||
super();
|
||||
@@ -44,6 +46,12 @@ public class BridgeSecurityDescriptor {
|
||||
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;
|
||||
|
||||
@@ -12,6 +12,8 @@ import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -29,6 +31,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
private BridgeSettingsDescriptor theBridgeSettings;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private BridgeSecurity bridgeSecurity;
|
||||
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
||||
|
||||
public BridgeSettings() {
|
||||
super();
|
||||
@@ -38,7 +41,8 @@ public class BridgeSettings extends BackupHandler {
|
||||
String theKey = System.getProperty("security.key");
|
||||
if(theKey == null)
|
||||
theKey = "IWantMyPasswordsToBeAbleToBeDecodedPleaseSeeTheReadme";
|
||||
bridgeSecurity = new BridgeSecurity(theKey.toCharArray());
|
||||
String execGarden = System.getProperty("exec.garden");
|
||||
bridgeSecurity = new BridgeSecurity(theKey.toCharArray(), execGarden);
|
||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||
@@ -54,6 +58,10 @@ public class BridgeSettings extends BackupHandler {
|
||||
public BridgeSecurity getBridgeSecurity() {
|
||||
return bridgeSecurity;
|
||||
}
|
||||
public static String getCurrentDate() {
|
||||
return dateFormat.format(new Date());
|
||||
}
|
||||
|
||||
public void buildSettings() {
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
@@ -139,7 +147,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
|
||||
}
|
||||
|
||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().equals("")) {
|
||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().trim().equals("") || theBridgeSettings.getUpnpConfigAddress().trim().equals("0.0.0.0")) {
|
||||
addressString = checkIpAddress(null, true);
|
||||
if(addressString != null) {
|
||||
theBridgeSettings.setUpnpConfigAddress(addressString);
|
||||
@@ -185,9 +193,12 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setWebaddress(serverIpOverride);
|
||||
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() {
|
||||
@@ -220,11 +231,11 @@ public class BridgeSettings extends BackupHandler {
|
||||
try {
|
||||
newBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
bridgeSecurity.setSettingsChanged(false);
|
||||
}
|
||||
@@ -238,13 +249,25 @@ public class BridgeSettings extends BackupHandler {
|
||||
log.debug("Save HA Bridge settings.");
|
||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||
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);
|
||||
configWriter(jsonValue, 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)){
|
||||
log.error("Error file is not writable: " + filePath);
|
||||
return;
|
||||
@@ -261,7 +284,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
try {
|
||||
Path target = null;
|
||||
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.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||
@@ -311,6 +334,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
log.error("checkIpAddress cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
String addressString = null;
|
||||
InetAddress address = null;
|
||||
while (ifs.hasMoreElements() && addressString == null) {
|
||||
@@ -337,9 +361,4 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
return addressString;
|
||||
}
|
||||
private void setupInternalTestUser() {
|
||||
theBridgeSettings.setupInternalTestUser();
|
||||
if(theBridgeSettings.isSettingsChanged())
|
||||
this.updateConfigFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,105 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import com.bwssystems.HABridge.api.hue.HueConstants;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
|
||||
public class BridgeSettingsDescriptor {
|
||||
private static final String DEFAULT_INTERNAL_USER = "thehabridgeuser";
|
||||
private static final String DEFAULT_USER_DESCRIPTION = "default_test_user";
|
||||
@SerializedName("upnpconfigaddress")
|
||||
@Expose
|
||||
private String upnpconfigaddress;
|
||||
@SerializedName("serverport")
|
||||
@Expose
|
||||
private Integer serverport;
|
||||
@SerializedName("upnpresponseport")
|
||||
@Expose
|
||||
private Integer upnpresponseport;
|
||||
@SerializedName("upnpdevicedb")
|
||||
@Expose
|
||||
private String upnpdevicedb;
|
||||
@SerializedName("veraaddress")
|
||||
@Expose
|
||||
private IpList veraaddress;
|
||||
@SerializedName("harmonyaddress")
|
||||
@Expose
|
||||
private IpList harmonyaddress;
|
||||
@SerializedName("buttonsleep")
|
||||
@Expose
|
||||
private Integer buttonsleep;
|
||||
@SerializedName("upnpstrict")
|
||||
@Expose
|
||||
private boolean upnpstrict;
|
||||
@SerializedName("traceupnp")
|
||||
@Expose
|
||||
private boolean traceupnp;
|
||||
@SerializedName("nestuser")
|
||||
@Expose
|
||||
private String nestuser;
|
||||
@SerializedName("nestpwd")
|
||||
@Expose
|
||||
private String nestpwd;
|
||||
@SerializedName("farenheit")
|
||||
@Expose
|
||||
private boolean farenheit;
|
||||
@SerializedName("configfile")
|
||||
@Expose
|
||||
private String configfile;
|
||||
@SerializedName("numberoflogmessages")
|
||||
@Expose
|
||||
private Integer numberoflogmessages;
|
||||
@SerializedName("hueaddress")
|
||||
@Expose
|
||||
private IpList hueaddress;
|
||||
@SerializedName("haladdress")
|
||||
@Expose
|
||||
private IpList haladdress;
|
||||
@SerializedName("haltoken")
|
||||
@Expose
|
||||
private String haltoken;
|
||||
@SerializedName("whitelist")
|
||||
@Expose
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
@SerializedName("myechourl")
|
||||
@Expose
|
||||
private String myechourl;
|
||||
@SerializedName("webaddress")
|
||||
@Expose
|
||||
private String webaddress;
|
||||
@SerializedName("mqttaddress")
|
||||
@Expose
|
||||
private IpList mqttaddress;
|
||||
@SerializedName("hassaddress")
|
||||
@Expose
|
||||
private IpList hassaddress;
|
||||
@SerializedName("domoticzaddress")
|
||||
@Expose
|
||||
private IpList domoticzaddress;
|
||||
@SerializedName("somfyaddress")
|
||||
@Expose
|
||||
private IpList somfyaddress;
|
||||
@SerializedName("hubversion")
|
||||
@Expose
|
||||
private String hubversion;
|
||||
@SerializedName("securityData")
|
||||
@Expose
|
||||
private String securityData;
|
||||
|
||||
|
||||
private boolean settingsChanged;
|
||||
private boolean veraconfigured;
|
||||
private boolean harmonyconfigured;
|
||||
private boolean nestconfigured;
|
||||
private boolean farenheit;
|
||||
private String configfile;
|
||||
private Integer numberoflogmessages;
|
||||
private IpList hueaddress;
|
||||
private boolean hueconfigured;
|
||||
private IpList haladdress;
|
||||
private String haltoken;
|
||||
private boolean nestconfigured;
|
||||
private boolean halconfigured;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
private boolean settingsChanged;
|
||||
private String myechourl;
|
||||
private String webaddress;
|
||||
private IpList mqttaddress;
|
||||
private boolean mqttconfigured;
|
||||
private IpList hassaddress;
|
||||
private boolean hassconfigured;
|
||||
private String hubversion;
|
||||
private IpList domoticzaddress;
|
||||
private boolean domoticzconfigured;
|
||||
private IpList somfyaddress;
|
||||
private boolean somfyconfigured;
|
||||
private boolean lifxconfigured;
|
||||
private String securityData;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
@@ -226,8 +273,8 @@ public class BridgeSettingsDescriptor {
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
protected void removeWhitelist() {
|
||||
whitelist = null;
|
||||
}
|
||||
public boolean isSettingsChanged() {
|
||||
return settingsChanged;
|
||||
@@ -377,80 +424,4 @@ public class BridgeSettingsDescriptor {
|
||||
public Boolean isValidLifx() {
|
||||
return this.isLifxconfigured();
|
||||
}
|
||||
|
||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
||||
&& !aUser.equalsIgnoreCase("")) {
|
||||
if (whitelist != null) {
|
||||
Set<String> theUserIds = whitelist.keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while (userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
if (validUser.equals(aUser))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && !strict) {
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newWhitelistUser(String aUser, String userDescription) {
|
||||
if (whitelist == null) {
|
||||
whitelist = new HashMap<>();
|
||||
}
|
||||
if(userDescription == null)
|
||||
userDescription = "auto insert user";
|
||||
|
||||
whitelist.put(aUser, WhitelistEntry.createEntry(userDescription));
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
|
||||
public String createWhitelistUser(String userDescription) {
|
||||
String aUser = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
return aUser;
|
||||
}
|
||||
|
||||
private String getNewUserID() {
|
||||
UUID uid = UUID.randomUUID();
|
||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
||||
String newUser = "";
|
||||
while (st.hasMoreTokens()) {
|
||||
newUser = newUser + st.nextToken();
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public String getInternalTestUser() {
|
||||
return DEFAULT_INTERNAL_USER;
|
||||
}
|
||||
|
||||
public void setupInternalTestUser() {
|
||||
boolean found = false;
|
||||
if(whitelist != null) {
|
||||
for (String key : whitelist.keySet()) {
|
||||
if(key.equals(DEFAULT_INTERNAL_USER)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
newWhitelistUser(DEFAULT_INTERNAL_USER, DEFAULT_USER_DESCRIPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ public class HABridge {
|
||||
staticFileLocation("/public");
|
||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
bridgeSettings.buildSettings();
|
||||
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||
log.info("HA Bridge initializing....");
|
||||
// sparkjava config directive to set ip address for the web server to listen on
|
||||
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
||||
@@ -102,6 +103,9 @@ public class HABridge {
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||
if(bridgeSettings.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettings.updateConfigFile();
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.bwssystems.HABridge;
|
||||
|
||||
public class SecurityInfo {
|
||||
private boolean useLinkButton;
|
||||
private String execGarden;
|
||||
private boolean secureHueApi;
|
||||
private boolean isSecure;
|
||||
|
||||
@@ -12,12 +11,6 @@ public class SecurityInfo {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -78,14 +78,6 @@ public class SystemControl {
|
||||
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", (request, response) -> {
|
||||
log.debug("Get HA Bridge testuser: " + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return "{\"user\":\"" + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser() + "\"}";
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/logmsgs gets the log messages for the bridge
|
||||
get (SYSTEM_CONTEXT + "/logmsgs", (request, response) -> {
|
||||
log.debug("Get logmsgs.");
|
||||
@@ -283,8 +275,6 @@ public class SystemControl {
|
||||
post(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||
log.debug("changesecurityinfo....");
|
||||
SecurityInfo theInfo = new Gson().fromJson(request.body(), SecurityInfo.class);
|
||||
if(theInfo.getExecGarden() != null)
|
||||
bridgeSettings.getBridgeSecurity().setExecGarden(theInfo.getExecGarden());
|
||||
bridgeSettings.getBridgeSecurity().setUseLinkButton(theInfo.isUseLinkButton());
|
||||
bridgeSettings.getBridgeSecurity().setSecureHueApi(theInfo.isSecureHueApi());
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.hue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.Conversion;
|
||||
@@ -83,7 +84,7 @@ public class BrightnessDecode {
|
||||
replaceTarget = INTENSITY_PERCENT_HEX;
|
||||
notDone = true;
|
||||
} 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;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_MATH_CLOSE)) {
|
||||
|
||||
@@ -69,6 +69,7 @@ public class HueMulator {
|
||||
public void setupServer() {
|
||||
log.info("Hue emulator service started....");
|
||||
before(HUE_CONTEXT + "/*", (request, response) -> {
|
||||
log.debug("HueMulator GET called on api/* with request <" + request.pathInfo() + ">");
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSecure()) {
|
||||
String pathInfo = request.pathInfo();
|
||||
if(pathInfo != null && pathInfo.contains(HUE_CONTEXT + "/devices")) {
|
||||
@@ -118,6 +119,17 @@ public class HueMulator {
|
||||
log.debug("group add requested from " + request.ip() + " user " + request.params(":userid") + " with body " + request.body());
|
||||
return "[{\"success\":{\"id\":\"1\"}}]";
|
||||
});
|
||||
// http://ip_address:port/api/:userid/groups/<groupid>/action
|
||||
// Dummy handler
|
||||
// Error forces Logitech Pop to fall back to individual light control
|
||||
// instead of scene-based control.
|
||||
put(HUE_CONTEXT + "/:userid/groups/:groupid/action", "application/json", (request, response) -> {
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
log.debug("put action to groups API from " + request.ip() + " user " + request.params(":userid") + " with body " + request.body());
|
||||
return "[{\"error\":{\"address\": \"/groups/0/action/scene\", \"type\":7, \"description\": \"invalid value, dummy for parameter, scene\"}}]";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/scenes returns json objects of
|
||||
// all scenes configured
|
||||
get(HUE_CONTEXT + "/:userid/scenes", "application/json", (request, response) -> {
|
||||
@@ -595,9 +607,9 @@ public class HueMulator {
|
||||
|
||||
private String basicListHandler(String type, String userId, String requestIp) {
|
||||
log.debug("hue " + type + " list requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
@@ -609,9 +621,9 @@ public class HueMulator {
|
||||
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = null;
|
||||
Map<String, GroupResponse> groupResponseMap = null;
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
groupResponseMap = new HashMap<String, GroupResponse>();
|
||||
@@ -626,9 +638,9 @@ public class HueMulator {
|
||||
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
||||
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = null;
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
if (groupId.equalsIgnoreCase("0")) {
|
||||
@@ -651,9 +663,9 @@ public class HueMulator {
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
||||
log.debug("hue lights list requested: " + userId + " from " + requestIp);
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
List<DeviceDescriptor> deviceList = repository.findAllByRequester(requestIp);
|
||||
@@ -727,13 +739,13 @@ public class HueMulator {
|
||||
aDeviceType = "<not given>";
|
||||
|
||||
if (newUser == null) {
|
||||
newUser = bridgeSettings.createWhitelistUser(aDeviceType);
|
||||
newUser = bridgeSettingMaster.getBridgeSecurity().createWhitelistUser(aDeviceType);
|
||||
}
|
||||
else {
|
||||
bridgeSettings.validateWhitelistUser(newUser, aDeviceType, false);
|
||||
bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(newUser, aDeviceType, false);
|
||||
}
|
||||
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
@@ -749,7 +761,7 @@ public class HueMulator {
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress);
|
||||
log.debug("hue api config requested: " + userId + " from " + ipAddress);
|
||||
if (bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()) != null) {
|
||||
if (bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()) != null) {
|
||||
log.debug("hue api config requested, No User supplied, returning public config");
|
||||
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
|
||||
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
|
||||
@@ -765,7 +777,7 @@ public class HueMulator {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getFullState(String userId, String ipAddress) {
|
||||
log.debug("hue api full state requested: " + userId + " from " + ipAddress);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return theErrors;
|
||||
|
||||
@@ -779,7 +791,7 @@ public class HueMulator {
|
||||
|
||||
private Object getLight(String userId, String lightId, String ipAddress) {
|
||||
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + ipAddress);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return theErrors;
|
||||
|
||||
@@ -823,7 +835,7 @@ public class HueMulator {
|
||||
Integer targetBri = null;
|
||||
Integer targetBriInc = null;
|
||||
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
try {
|
||||
@@ -873,7 +885,7 @@ public class HueMulator {
|
||||
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
|
||||
aMultiUtil.setSetCount(1);
|
||||
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
try {
|
||||
|
||||
@@ -36,8 +36,7 @@ public class CommandHome implements Home {
|
||||
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
||||
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
||||
String execGarden = theSettings.getBridgeSecurity().getExecGarden();
|
||||
execGarden = execGarden.trim();
|
||||
if(execGarden != null && !execGarden.isEmpty()) {
|
||||
if(execGarden != null && !execGarden.trim().isEmpty()) {
|
||||
if(System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)
|
||||
intermediate = execGarden + "\\" + intermediate;
|
||||
else
|
||||
|
||||
@@ -5,6 +5,7 @@ public class HalDevice {
|
||||
private String haldevicename;
|
||||
private String haladdress;
|
||||
private String halname;
|
||||
private Boolean secure;
|
||||
private DeviceElements buttons;
|
||||
public String getHaldevicetype() {
|
||||
return haldevicetype;
|
||||
@@ -30,6 +31,12 @@ public class HalDevice {
|
||||
public void setHalname(String halname) {
|
||||
this.halname = halname;
|
||||
}
|
||||
public Boolean getSecure() {
|
||||
return secure;
|
||||
}
|
||||
public void setSecure(Boolean secure) {
|
||||
this.secure = secure;
|
||||
}
|
||||
public DeviceElements getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,14 @@ 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.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HalHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||
@@ -30,7 +36,7 @@ public class HalHome implements Home {
|
||||
public Object getItems(String type) {
|
||||
if(!validHal)
|
||||
return null;
|
||||
log.debug("consolidating devices for hues");
|
||||
log.debug("consolidating devices for HALs");
|
||||
List<HalDevice> theResponse = null;
|
||||
Iterator<String> keys = hals.keySet().iterator();
|
||||
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||
@@ -106,8 +112,41 @@ public class HalHome implements Home {
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
// Not a device handler
|
||||
return null;
|
||||
String responseString = null;
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
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 = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
|
||||
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(hostAddr)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -98,7 +98,11 @@ public class HalInfo {
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
||||
if(halAddress.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
theUrl = theUrl + halAddress.getIp() + apiType + theToken;
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
if(theData != null) {
|
||||
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||
@@ -123,6 +127,7 @@ public class HalInfo {
|
||||
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||
aNewHalDevice.setHaladdress(halAddress.getIp());
|
||||
aNewHalDevice.setHalname(halAddress.getName());
|
||||
aNewHalDevice.setSecure(halAddress.getSecure());
|
||||
deviceList.add(aNewHalDevice);
|
||||
|
||||
}
|
||||
@@ -145,7 +150,11 @@ public class HalInfo {
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
while (theHalDevices.hasNext()) {
|
||||
HalDevice theHalDevice = theHalDevices.next();
|
||||
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||
if(halAddress.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
theUrl = theUrl + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
if (theData != null) {
|
||||
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||
@@ -177,6 +186,12 @@ public class HalInfo {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public String deviceCommand(String theUrl) {
|
||||
String theData = null;
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
return theData;
|
||||
}
|
||||
|
||||
public NamedIP getHalAddress() {
|
||||
return halAddress;
|
||||
}
|
||||
|
||||
@@ -54,13 +54,6 @@ legend.form-label {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.password-count {
|
||||
float: right;
|
||||
position: relative;
|
||||
bottom: 24px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.msg-block {
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -77,14 +77,13 @@ app.config (function ($locationProvider, $routeProvider) {
|
||||
})
|
||||
});
|
||||
|
||||
app.run( async function ($rootScope, $location, Auth, bridgeService) {
|
||||
app.run(function ($rootScope, $location, Auth, bridgeService) {
|
||||
bridgeService.getHABridgeVersion();
|
||||
|
||||
$rootScope.$on('securitySetupReceived', function(event, data) {
|
||||
Auth.init();
|
||||
if(Auth.isLoggedIn()) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.getSecurityInfo();
|
||||
bridgeService.viewMapTypes();
|
||||
$location.path("/");
|
||||
@@ -94,13 +93,10 @@ app.run( async function ($rootScope, $location, Auth, bridgeService) {
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('securityReview', function(event, data) {
|
||||
if(Auth.isLoggedIn()) {
|
||||
$location.path("/");
|
||||
} else {
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
}
|
||||
$rootScope.$on('securityError', function(event, data) {
|
||||
Auth.logout();
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
});
|
||||
|
||||
$rootScope.$on('securityReinit', function(event, data) {
|
||||
@@ -194,7 +190,10 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.devices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
self.displayError("Cannot get devices from habridge: ", error);
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayError("Cannot get devices from habridge: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -205,6 +204,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewDevices();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayError("Cannot renumber devices from habridge: ", error);
|
||||
}
|
||||
);
|
||||
@@ -237,12 +239,31 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
};
|
||||
|
||||
this.getTestUser = function () {
|
||||
return $http.get(this.state.systemsbase + "/habridge/testuser").then(
|
||||
if(self.state.testuser === undefined || self.state.testuser === "") {
|
||||
return $http.put(this.state.systemsbase + "/presslinkbutton").then(
|
||||
function (response) {
|
||||
self.getAUser();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Cannot get testuser: ", error);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
this.getAUser = function () {
|
||||
return $http.post(this.state.huebase, "{\"devicetype\":\"test_ha_bridge\"}").then(
|
||||
function (response) {
|
||||
self.state.testuser = response.data.user;
|
||||
self.state.testuser = response.data[0].success.username;
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Cannot get testuser: ", error);
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Cannot get a user: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -251,8 +272,12 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
return $http.get(this.state.systemsbase + "/securityinfo").then(
|
||||
function (response) {
|
||||
self.state.securityInfo = response.data;
|
||||
self.getTestUser();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Cannot get security info: ", error);
|
||||
}
|
||||
);
|
||||
@@ -271,6 +296,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("Updated security settings.")
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Update ecurity settings Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -298,6 +326,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("Password updated")
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Update password Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -319,6 +350,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
}
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("User add Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -335,6 +369,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("User deleted")
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("User add Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -346,6 +383,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displayTimer("Link your device", 30000);
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Cannot get security info: ", error);
|
||||
}
|
||||
);
|
||||
@@ -477,6 +517,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.updateShowLifx();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Load Bridge Settings Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -488,6 +531,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.backups = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Backups Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -499,6 +545,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.configs = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Configs Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -510,6 +559,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.logMsgs = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get log messages Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -521,6 +573,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.loggerInfo = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get logger info Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -534,6 +589,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.nestitems = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Nest Items Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -547,6 +605,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.huedevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Hue Items Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -560,6 +621,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.veradevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Vera Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -573,6 +637,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.verascenes = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Vera Scenes Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -586,6 +653,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.harmonyactivities = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Harmony Activities Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -599,6 +669,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.harmonydevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Harmony Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -612,6 +685,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.haldevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Hal Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -625,6 +701,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.mqttbrokers = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get MQTT Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -638,6 +717,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.hassdevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Hass Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -651,6 +733,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.domoticzdevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Domoticz Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -664,6 +749,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.somfydevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Somfy Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -678,6 +766,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.lifxdevices = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get Lifx Devices Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -750,6 +841,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.state.mapTypes = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Get mapTypes Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -773,6 +867,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("Updated " + logComponents.length + " loggers for log levels.")
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Update Log components Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -801,6 +898,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("Bulk device add successful.");
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Bulk Add new Device Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -819,6 +919,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
function (response) {
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Edit Device Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -829,6 +932,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
function (response) {
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Add new Device Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -843,6 +949,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewBackups();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Backup Device Db Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -857,6 +966,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewDevices();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Backup Db Restore Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -870,6 +982,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewBackups();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Delete Backup Db File Error:", error);
|
||||
}
|
||||
);
|
||||
@@ -899,6 +1014,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displayError("HABridge is now stopped. Restart must occur from the server.", null);
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayError("HABRidge Stop Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -918,6 +1036,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
}, 2000);
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("HABRidge Reinit Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -929,6 +1050,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.reinit();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Save Settings Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -943,6 +1067,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewConfigs();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Backup Settings Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -958,6 +1085,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewDevices();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Backup Settings Restore Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -971,6 +1101,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewConfigs();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Delete Backup Settings File Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -982,6 +1115,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.viewDevices();
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Delete Device Error: ", error);
|
||||
}
|
||||
);
|
||||
@@ -1023,6 +1159,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
self.displaySuccess("Request Executed: " + msgDescription);
|
||||
},
|
||||
function (error) {
|
||||
if (error.status === 401)
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
else
|
||||
self.displayWarn("Request Error, Pleae look in your habridge log: ", error);
|
||||
}
|
||||
);
|
||||
@@ -1146,11 +1285,11 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
|
||||
}
|
||||
}
|
||||
};
|
||||
$scope.addHarmonytoSettings = function (newharmonyname, newharmonyip) {
|
||||
$scope.addHarmonytoSettings = function (newharmonyname, newharmonyip, newharmonywebhook) {
|
||||
if($scope.bridge.settings.harmonyaddress === undefined || $scope.bridge.settings.harmonyaddress === null) {
|
||||
$scope.bridge.settings.harmonyaddress = { devices: [] };
|
||||
}
|
||||
var newharmony = {name: newharmonyname, ip: newharmonyip }
|
||||
var newharmony = {name: newharmonyname, ip: newharmonyip, webhook: newharmonywebhook}
|
||||
$scope.bridge.settings.harmonyaddress.devices.push(newharmony);
|
||||
$scope.newharmonyname = null;
|
||||
$scope.newharmonyip = null;
|
||||
@@ -1306,6 +1445,17 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
|
||||
};
|
||||
});
|
||||
|
||||
app.directive('autofocus', ['$timeout', function($timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link : function($scope, $element) {
|
||||
$timeout(function() {
|
||||
$element[0].focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.directive('nuCheck', [function () {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
@@ -3298,7 +3448,6 @@ app.factory('Auth', function($resource, $rootScope, $sessionStorage, $http, $bas
|
||||
delete $sessionStorage.user;
|
||||
delete $rootScope.user;
|
||||
delete bridgeService.state.loggedInUser;
|
||||
bridgeService.displaySuccess("User Logged Out");
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
<div class="panel-body">
|
||||
<div ng-if="!loggedIn" class="form-container">
|
||||
|
||||
<form name="loginForm" role="form">
|
||||
<form name="loginForm" role="form" ng-submit="login(username, password)">
|
||||
<legend class="form-label">Enter Credentials</legend>
|
||||
<div class="form-group">
|
||||
<label>User</label> <input id="username" name="username"
|
||||
class="form-control" type="text" ng-model="username"
|
||||
placeholder="someone" />
|
||||
placeholder="someone" autofocus/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label> <input id="password" name="password"
|
||||
class="form-control" type="password" ng-model="password" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-success" ng-click="login(username, password)">Submit</button>
|
||||
<button type="submit" class="btn btn-success" value="Submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -6,19 +6,13 @@
|
||||
<label>Use Link Button</label>
|
||||
<input type="checkbox"
|
||||
ng-model="useLinkButton" ng-true-value=true
|
||||
ng-false-value=false> {{useLinkButton}}
|
||||
ng-false-value=false /> {{useLinkButton}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Use username/password for HUE Api</label>
|
||||
<input type="checkbox"
|
||||
ng-model="secureHueApi" ng-true-value=true
|
||||
ng-false-value=false> {{secureHueApi}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Secure Folder for scripts/executables</label>
|
||||
<input id="exec-garden" class="form-control"
|
||||
type="text" ng-model="execGarden"
|
||||
placeholder="/home/pi/protectedscripts">
|
||||
ng-false-value=false /> {{secureHueApi}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-primary" ng-click="setSecurityInfo()">Update</button>
|
||||
@@ -27,9 +21,9 @@
|
||||
<label>Add/Delete User</label>
|
||||
<input id="new-user" name="new-user" class="form-control"
|
||||
type="text" ng-model="newUser"
|
||||
placeholder="someone" nu-check="new-user">
|
||||
placeholder="someone" nu-check="new-user" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div ng-if="isSecure" class="form-group">
|
||||
<button type="button" class="btn btn-danger" ng-click="delUser(newUser)">Delete</button>
|
||||
</div>
|
||||
<div ng-if="showPassword" postrender-action="setBlankPassword('password-1')">
|
||||
@@ -50,7 +44,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-success" ng-click="dismissDialog()">Dismiss</button>
|
||||
<button type="button" class="btn btn-success" ng-click="dismissDialog()" autofocus>Dismiss</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
<td>{{harmony.ip}}</td>
|
||||
<td>{{harmony.webhook}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip, harmony.webhook)">Del</button></td>
|
||||
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="bridge-settings-next-harmony-name"
|
||||
@@ -201,12 +201,14 @@
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>IP</th>
|
||||
<th>Use SSL</th>
|
||||
<th>Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="hal in bridge.settings.haladdress.devices">
|
||||
<td>{{hal.name}}</td>
|
||||
<td>{{hal.ip}}</td>
|
||||
<td>{{hal.secure}}</td>
|
||||
<td><button class="btn btn-danger" type="submit"
|
||||
ng-click="removeHaltoSettings(hal.name, hal.ip)">Del</button></td>
|
||||
</tr>
|
||||
@@ -217,8 +219,11 @@
|
||||
<td><input id="bridge-settings-next-hal-ip"
|
||||
class="form-control" type="text" ng-model="newhalip"
|
||||
placeholder="192.168.1.3:82"></td>
|
||||
<td><input type="checkbox"
|
||||
ng-model="newhalsecure" ng-true-value=true
|
||||
ng-false-value=false></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addHaltoSettings(newhalname, newhalip)">Add</button></td>
|
||||
ng-click="addHaltoSettings(newhalname, newhalip, newhalsecure)">Add</button></td>
|
||||
</tr>
|
||||
</table></td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user