Compare commits

...

103 Commits

Author SHA1 Message Date
BWS Systems
46ad4489ad Finish HomeAssistant auth changes and implement no scroll for pages 2019-06-14 10:32:15 -05:00
BWS Systems
bfd1b94473 Start adding new Bearer Token for Home Assistant 2019-06-13 15:51:49 -05:00
BWS Systems
7d920d3885 Update pom.xml for build instructions for java 1.8 and raspberry pi 2019-06-13 10:11:24 -05:00
BWS Systems
2dbf4c96c4 Finished config up/down load impl and Finished startup action implementation 2019-06-12 16:05:29 -05:00
BWS Systems
69b510ae18 Finished upload portion of device db 2019-06-11 15:28:54 -05:00
BWS Systems
e86b700e93 Add lock id to device, adding download of backups 2019-06-10 16:35:10 -05:00
BWS Systems
a05b933e43 Completed HomeGenie implementation 2019-06-05 16:08:11 -05:00
BWS Systems
fe0b072b4e Add renumbering and HomeGenie Helper 2019-06-04 16:36:21 -05:00
BWS Systems
3e76e6298a tested moziot and working 2019-06-03 16:06:03 -05:00
BWS Systems
f266945b7e working on ssl calls 2019-05-31 15:19:24 -05:00
BWS Systems
2d3fac691b Update state error messages Homes, update gateway login 2019-05-30 15:45:35 -05:00
BWS Systems
5f6bfae41a Debugging MOzilla IOT impl 2019-05-24 15:22:34 -05:00
BWS Systems
79d5b5da28 Fixed color handling, starter Mozilla IOT integration 2019-05-22 15:30:50 -05:00
BWS Systems
45e2b63f98 Updating color handling 2019-05-21 16:44:38 -05:00
BWS Systems
b6b9089ec4 Merge pull request #1028 from 20goto10/feature/hsl-support
HSL color integration merge to target_5_2_next
2019-05-21 09:57:43 -05:00
BWS Systems
063055f5c8 Merge pull request #1045 from gaudryc/master
Logout request and Shutdown hook merge to target_5_2_next
2019-05-21 09:56:57 -05:00
BWS Systems
c1dc89704d Merge pull request #1085 from bwssytems/FixesTarget5.2.2
Fixes target5.2.2 completed and ready for release
2019-05-03 13:04:53 -05:00
BWS Systems
f97c718568 Update a few fixes
Fixed items for FHEM and Domoticz
2019-05-03 12:57:56 -05:00
BWS Systems
d05b6bea5c moved java target back to 1.8 2019-04-23 09:59:04 -05:00
BWS Systems
2f567cd604 remove JAXB dependency and update harmony disconnect detection 2019-04-23 09:56:49 -05:00
gaudryc
3971c81449 Bug: Comparison of String objects using == or != in
com.bwssystems.HABridge.plugins.http.HTTPHandler.doHttpRequest(String,
String, String, String, NameValue[])
2019-01-06 22:01:39 +01:00
gaudryc
e1b5aede66 Bug: Possible null pointer dereference in
com.bwssystems.HABridge.hue.HueMulator.formatSuccessHueResponse(StateChangeBody,
String, String, DeviceState, Integer, Integer, ColorData, boolean)
2019-01-06 21:58:01 +01:00
gaudryc
14c3614856 Bug: Possible null pointer dereference in
com.bwssystems.HABridge.hue.HueMulator.callUrl(String, DeviceDescriptor,
String, String, String, String, boolean, Integer, Integer, ColorData)
2019-01-06 21:54:23 +01:00
gaudryc
1311d4a68d Bug: Possible null pointer dereference in method
com.bwssystems.HABridge.plugins.broadlink.BroadlinkHome.deviceHandler(CallItem,
MultiCommandUtil, String, int, Integer, Integer, ColorData,
DeviceDescriptor, String) on exception path
2019-01-06 21:43:39 +01:00
gaudryc
9cbc290768 Bug: com.bwssystems.HABridge.plugins.hass.HassHome.addHassDevices(List,
List, String) has Boolean return type and returns explicit null
2019-01-06 20:09:49 +01:00
gaudryc
f90f39e5f1 Bug: com.bwssystems.HABridge.plugins.hal.HalHome.addHalDevices(List,
List, String) has Boolean return type and returns explicit null
2019-01-06 20:08:38 +01:00
gaudryc
07fa11b9ff Bug: com.bwssystems.HABridge.plugins.domoticz.DomoticzHome.addDomoticzDevices(List,
List, String) has Boolean return type and returns explicit null
2019-01-06 20:07:10 +01:00
gaudryc
df04d542db Bug: The method
com.bwssystems.HABridge.plugins.hue.HueInfo.changeState(HueDeviceIdentifier,
String, String) ignores the return value of
String.contains(CharSequence)
2019-01-06 20:03:24 +01:00
gaudryc
92ab02145e Bug: Non-transient non-serializable instance fields in serializable
class com.bwssystems.logservices.LoggingForm
2019-01-06 19:52:55 +01:00
gaudryc
d9916b7662 Bug: Useless control flow to next line in
com.bwssystems.HABridge.plugins.http.HttpTestHandler.updateTheData(String,
String)

This method contains a useless control flow statement in which control
flow follows to the same or following line regardless of whether or not
the branch is taken. Often, this is caused by inadvertently using an
empty statement as the body of an if statement, e.g.:
2019-01-06 19:18:27 +01:00
gaudryc
f8349f12bc Bug: Call to method of static java.text.DateFormat in
com.bwssystems.HABridge.api.hue.WhitelistEntry.getCurrentDate()

As the JavaDoc states, DateFormats are inherently unsafe for
multithreaded use. The detector has found a call to an instance of
DateFormat that has been obtained via a static field. This looks
suspicious.
2019-01-06 18:59:14 +01:00
gaudryc
12823704f3 Bug: Call to method of static java.text.DateFormat in
com.bwssystems.HABridge.BridgeSettings.getCurrentDate().

As the JavaDoc states, DateFormats are inherently unsafe for
multithreaded use. The detector has found a call to an instance of
DateFormat that has been obtained via a static field. This looks
suspicious.
2019-01-06 16:21:07 +01:00
gaudryc
7490cf72a3 Add shutdown hook before starting web server to be able to stop
HA-Bridge from the command line (using SIGTERM signal).
2019-01-03 18:39:01 +01:00
gaudryc
ce220d999a Invalidate authenticated user session. 2019-01-03 18:23:12 +01:00
gaudryc
9a438abf79 Add /system/logout request to remove current authenticated user and
invalidate his session.
2019-01-03 18:20:42 +01:00
BWS Systems
ce97e928ad Updated harmony hub disconnect handling 2018-12-31 14:06:48 -06:00
Ben Chadwick
56481f3f72 indentation and typo correction 2018-12-10 11:08:53 -05:00
Ben Chadwick
55ed9ba4c2 initial HSL replacement code 2018-12-10 11:03:53 -05:00
BWS Systems
df67980bd6 Fix compile error in bridghtnessdecode class. 2018-11-15 09:46:56 -06:00
BWS Systems
b6b78c4849 Update v to v5.2.2 2018-11-14 11:29:45 -06:00
BWS Systems
b1d1f2ac46 changes for dfim at 1percent and domoticz https usage 2018-11-14 11:25:54 -06:00
BWS Systems
750056df06 add new device param for on with dim and changed behavior for onFirstDim 2018-11-13 14:09:53 -06:00
BWS Systems
3f13e957ad update handling for upnp response with ip path 2018-11-12 16:25:15 -06:00
BWS Systems
afc254720c Update for parse default route 2018-11-06 16:11:42 -06:00
BWS Systems
943e4420e6 update .gitignore 2018-11-06 15:52:34 -06:00
BWS Systems
c9e6cd079f Update Harmonhy connection handling on disconnect. Add Route Parse 2018-11-06 15:46:45 -06:00
bsamuels
faae6aa31f Updating upnp address corrections 2018-08-07 16:20:48 -05:00
BWS Systems
c25f08f142 Merge pull request #927 from nel-stefan/master
Added quotes around strings in json response for huemulator
2018-08-07 13:42:23 -05:00
audiofreak9
d6ad9d288e Updated README Alexa device list
Updated README Alexa device list to include all names of physical Amazon devices for clarity.
2018-07-10 17:01:42 -04:00
BWS Systems
3400c4d43a Fix habridge directory to be ha-bridge
Fixes #947
2018-04-10 13:15:30 -05:00
BWS Systems
ddcbea001c add dash in path 2018-03-28 08:39:27 -05:00
Stefan Marchal
9a35e47c27 Added quotes around strings in json response for huemulator
Bumped version number
2018-03-19 22:44:53 +01:00
BWS Systems
199fcce549 Merge pull request #883 from escalate/master
Update README.md with better instructions for running created by @escalate
2018-03-16 09:17:38 -05:00
BWS Systems
bfeb382d1f Merge branch 'master' into master 2018-03-16 09:16:49 -05:00
bsamuels
3a93d9e98f Updated version for release and linked in the mob41 master branch for
broadlink api
2018-03-16 08:31:45 -05:00
bsamuels
3b22e3f711 Start bug fixing, update FHEM bulk add issue 2018-03-09 09:18:23 -06:00
BWS Systems
5c1f1f5b96 Merge pull request #914 from bwssytems/NewFeaturesfor5.1
New featuresfor5.1

Fixes #896 Incorrect examples in documentation for color. enhancement

Fixes #910 Order of data description fields seems to be hard-coded bug question

Fixes #891 Color replacement control in MQTT bug

Fixes #886 Exception every minute after linking harmony hub enhancement question

Fixes #879 Intensity.math(x).hex does not deliver hex values bug question

Fixes #809 Scanning Fibaro devices or scenes not working with 5.0.0 Informational bug

Fixes #236 Support for Broadlink Rm2/pro enhancement question

Fixes #874 Error on calling URL - Nanoleaf Aurora bug question

Fixes #808 In 5.0.0, colour UDP URLs not issued to milight hub enhancement question

Fixes #846 [5.1.0] Harmony commands not being split into on/dim enhancement question

Fixes #851 non-dimmable device enhancement question

Fixes #853 Turn Logging off enhancement question

Fixes #850 HB[5.1.0] Fibaro HomeCenter2: Devices "Build Item" not working bug question

Fixes #860 Discovery issues from Echo Dot 2nd Gen - potential fix enhancement

Fixes #675 FHEM home automation integration enhancement question

Fixes #516 OpenHAB integration enhancement
2018-03-08 14:00:27 -06:00
bsamuels
82788f1ecd Final fixes and ready for release 2018-03-08 13:17:26 -06:00
bsamuels
d5920e1454 Updated BL api lib 2018-03-07 11:35:40 -06:00
bsamuels
b26a63bb7a updated to new BL api lib added debug and fixed device build for BL in
app.js
2018-03-07 11:07:44 -06:00
bsamuels
f17cea3c9d Finished debugging broadlink implementation 2018-03-06 16:05:27 -06:00
bsamuels
7f68285a43 Updated broadlink api lib version 2018-03-05 15:34:35 -06:00
bsamuels
cb46a13802 Updating broadlink library 2018-03-01 16:23:02 -06:00
bsamuels
de07393e6e Update for broadlink api lib change 2018-02-16 11:32:52 -06:00
bsamuels
4b40b03da4 updated debugging and included new Broadlink api build 2018-02-15 13:31:04 -06:00
bsamuels
4f5d4acf56 updated broadlink api version 2018-02-14 09:17:17 -06:00
bsamuels
271bd3913c Check broadlink map before finding device to call for null. Initialize
broadlink Map on discover.
2018-02-13 16:12:05 -06:00
bsamuels
869ffaaf36 Updated broadlink discover and fixed list mapping issue. Added refresh
to ResourceHAndlers so Broadlink and Lifx can be refreshed from the tab.
2018-02-08 15:30:21 -06:00
bsamuels
5a73cc20a9 Fixed color for MQTT and TCP 2018-02-06 16:10:11 -06:00
bsamuels
1a936c631c Updated with debug info. 2018-02-05 15:14:40 -06:00
bsamuels
1a8a6f7a6f Added Tests for broadlink ircmomand conversion. Added checks for
successful auth with broadlink devices. Updated broadlink API CmdPacket
build.
2018-02-02 16:30:44 -06:00
bsamuels
879d3b5326 Fixed broadlink discover loop 2018-01-31 12:19:06 -06:00
bsamuels
3313548ec2 Updated Broadlink for port binding, added debug for RM2 Device ir call
data return, updated Harmony library to be the latest version.
2018-01-30 16:30:55 -06:00
bsamuels
e6db6e11e5 Update broadlinnk to dump clients when discovered in debug and to drop
clients when re-init.
2018-01-29 16:44:12 -06:00
Felix Boerner
dc28eb2984 docs: refine Docker container usage instructions 2018-01-29 08:15:34 +01:00
Felix Boerner
b8acb4a52c feat: add minus in ha-bridge names for consistency 2018-01-27 13:07:37 +01:00
bsamuels
c843e8d1ac Fix small issues and add pct check for FHEM 2018-01-26 13:41:57 -06:00
Felix Boerner
21fdaf4545 docs: remove trailing whitespaces 2018-01-26 13:42:49 +01:00
Felix Boerner
db192df2c6 docs: add section how to run docker container 2018-01-26 13:42:00 +01:00
Felix Boerner
4a24d263c1 docs: rewrite manual installation section 2018-01-26 13:02:59 +01:00
Felix Boerner
3394559539 docs: remove basic script setup section
It is not best practice to run an application this way.
2018-01-26 10:54:31 +01:00
bsamuels
47074ff60f Update Fibaro and Fhem for small changes. 2018-01-23 14:34:49 -06:00
bsamuels
047a7de612 deleted json 2018-01-22 16:27:26 -06:00
bsamuels
7fc7f00308 Updated FHEM call issues for success of 302
Streamlined Fibaro Json Decoding
2018-01-22 16:26:31 -06:00
bsamuels
14e940134c Fixed openhab build screen and openhab invalid responses.
Completed Broadlink impl

Testing
2018-01-19 14:46:45 -06:00
bsamuels
1897633e75 Forget new file 2018-01-18 16:54:44 -06:00
bsamuels
5a052d9374 Updated FHEM for command
Started Broadlink implementation
2018-01-18 16:54:21 -06:00
bsamuels
4b048c2a7f Updated with fixes for FHEM 2018-01-16 16:18:53 -06:00
bsamuels
27f77b9caa update 2018-01-16 16:14:11 -06:00
bsamuels
18c47ee5e4 update for changes 2018-01-16 16:13:24 -06:00
bsamuels
27dd8475e9 Huemulator state fixes
draft active logger control
2018-01-16 13:20:49 -06:00
bsamuels
37b381085c Fixed RC test issues for:
FHEM device decode
on for first dim
default OpoenHab Port
Fibaro request debugging enhancement
2018-01-12 15:44:10 -06:00
bsamuels
b2a30f5771 Remove test call for FHEM devices 2018-01-05 16:19:18 -06:00
bsamuels
b88b3fa245 Fininshed Testing color RGB to int for LIFX 2018-01-05 15:29:41 -06:00
bsamuels
52aac32474 Update color setting for LIFX 2018-01-05 15:15:22 -06:00
bsamuels
037b151729 Updates for RC2 fixing FHEM issues, Fiabaro Issues, adding functionality
for color tests, and sending multiple requests based on the Hue API
body.
2018-01-05 14:48:20 -06:00
bsamuels
3f3d643053 Update pom version 2018-01-02 16:22:39 -06:00
bsamuels
f27d905869 Updated FHEM integration for testing 2018-01-02 16:20:51 -06:00
bsamuels
4c694cb285 Updated description xml to remove null service list. Most likely culprit
of /null calls to spark.

Started adding FHEM integration
2017-12-29 15:57:37 -06:00
bwssystems
ca2c5f7b04 Finished OpenHAB integration.... 2017-12-20 15:36:08 -06:00
bwssystems
0c49df1473 Updated system.html with opnhab ports 2017-12-19 16:45:51 -06:00
Admin
fe613f7688 Basic OpenHAB functionality added. Need to add String selection
functionality.
2017-12-15 16:34:58 -06:00
Admin
4b247557d4 Start adding OpenHAB to the bridge. 2017-12-14 14:54:50 -06:00
160 changed files with 13258 additions and 4500 deletions

9
.gitignore vendored
View File

@@ -14,3 +14,12 @@ data
/.classpath
sftp-config\.json
/bin/
.vscode/launch.json
.vscode/launch.test.json
.vscode/settings.json
.vscode/tasks.json
# dependencies
/node_modules
package-lock.json

246
README.md

File diff suppressed because one or more lines are too long

258
pom.xml
View File

@@ -1,160 +1,203 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
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>
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>5.1.0</version>
<version>5.3.0RC3</version>
<packaging>jar</packaging>
<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>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>Eclipse Paho Repo</id>
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
</repository>
<repository>
<id>Eclipse Paho Repo</id>
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>harmony-java-client</artifactId>
<version>1.1.5</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
<groupId>com.github.bwssytems</groupId>
<artifactId>harmony-java-client</artifactId>
<version>master-SNAPSHOT</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>
<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>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
<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>
<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>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.5</version>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>net.java.dev.eval</groupId>
<artifactId>eval</artifactId>
<version>0.5</version>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>net.java.dev.eval</groupId>
<artifactId>eval</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0-beta4</version>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.0.7</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>lifx-sdk-java</artifactId>
<version>2.1.6</version>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</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>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>version.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>version.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<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>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
@@ -216,8 +259,7 @@
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.bwssystems.HABridge.HABridge</mainClass>
</transformer>
</transformers>

View File

@@ -355,7 +355,7 @@ public class BridgeSecurity {
public void removeAuthenticatedUser(Request request) {
request.session().removeAttribute(USER_SESSION_ID);
request.session().invalidate();
}
public User getAuthenticatedUser(Request request) {

View File

@@ -12,8 +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.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
@@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.util.BackupHandler;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.bwssystems.HABridge.util.ParseRoute;
import com.google.gson.Gson;
public class BridgeSettings extends BackupHandler {
@@ -31,7 +32,7 @@ public class BridgeSettings extends BackupHandler {
private BridgeSettingsDescriptor theBridgeSettings;
private BridgeControlDescriptor bridgeControl;
private BridgeSecurity bridgeSecurity;
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss");
public BridgeSettings() {
super();
@@ -58,10 +59,10 @@ public class BridgeSettings extends BackupHandler {
public BridgeSecurity getBridgeSecurity() {
return bridgeSecurity;
}
public static String getCurrentDate() {
return dateFormat.format(new Date());
}
public String getCurrentDate() {
return LocalDateTime.now().format(dateTimeFormat);
}
public void buildSettings() {
String addressString = null;
String theVeraAddress = null;
@@ -76,7 +77,6 @@ public class BridgeSettings extends BackupHandler {
}
String serverPortOverride = System.getProperty("server.port");
String serverIpOverride = System.getProperty("server.ip");
String upnpStrictOverride = System.getProperty("upnp.strict", "true");
if(configFileProperty != null)
{
log.info("reading from config file: " + configFileProperty);
@@ -159,15 +159,16 @@ public class BridgeSettings extends BackupHandler {
}
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.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DEFAULT_BUTTON_SLEEP)));
theBridgeSettings.setNestuser(System.getProperty("nest.user"));
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
}
ParseRoute aDefaultRoute = ParseRoute.getInstance();
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().trim().equals("") || theBridgeSettings.getUpnpConfigAddress().trim().equals("0.0.0.0")) {
addressString = checkIpAddress(null, true);
addressString = aDefaultRoute.getLocalIPAddress();
if(addressString != null) {
theBridgeSettings.setUpnpConfigAddress(addressString);
log.info("Adding " + addressString + " as our default upnp config address.");
@@ -177,8 +178,10 @@ public class BridgeSettings extends BackupHandler {
}
else {
addressString = checkIpAddress(theBridgeSettings.getUpnpConfigAddress(), false);
if(addressString == null)
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host.");
if(addressString == null) {
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)
@@ -194,7 +197,7 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setUpnpGroupDb(Configuration.GROUP_DB_DIRECTORY);
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)
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
@@ -210,13 +213,18 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
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.
if(serverPortOverride != null)
theBridgeSettings.setServerPort(serverPortOverride);
if(serverIpOverride != null)
if(serverIpOverride != null) {
theBridgeSettings.setWebaddress(serverIpOverride);
if(upnpStrictOverride != null)
theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(upnpStrictOverride));
theBridgeSettings.setUpnpConfigAddress(serverIpOverride);
}
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());

View File

@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Map;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
//import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
@@ -87,6 +87,12 @@ public class BridgeSettingsDescriptor {
@SerializedName("somfyaddress")
@Expose
private IpList somfyaddress;
@SerializedName("openhabaddress")
@Expose
private IpList openhabaddress;
@SerializedName("moziotaddress")
@Expose
private IpList moziotaddress;
@SerializedName("hubversion")
@Expose
private String hubversion;
@@ -99,7 +105,34 @@ public class BridgeSettingsDescriptor {
@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;
@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("activeloggers")
// @Expose
// private List<NameValue> activeloggers;
private boolean settingsChanged;
private boolean veraconfigured;
private boolean fibaroconfigured;
@@ -111,16 +144,19 @@ public class BridgeSettingsDescriptor {
private boolean hassconfigured;
private boolean domoticzconfigured;
private boolean somfyconfigured;
private boolean lifxconfigured;
private boolean homewizardconfigured;
private boolean openhabconfigured;
private boolean fhemconfigured;
private boolean moziotconfigured;
private boolean homegenieconfigured;
// Deprecated settings
private String haltoken;
private boolean upnpstrict;
// private boolean upnpstrict;
public BridgeSettingsDescriptor() {
super();
this.upnpstrict = true;
// this.upnpstrict = true;
this.useupnpiface = false;
this.userooms = false;
this.traceupnp = false;
@@ -136,6 +172,9 @@ public class BridgeSettingsDescriptor {
this.domoticzconfigured = false;
this.homewizardconfigured = false;
this.lifxconfigured = false;
this.openhabconfigured = false;
this.moziotconfigured = false;
this.homegenieconfigured = false;
this.farenheit = true;
this.securityData = null;
this.settingsChanged = false;
@@ -143,388 +182,657 @@ public class BridgeSettingsDescriptor {
this.webaddress = "0.0.0.0";
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;
}
public String getUpnpConfigAddress() {
return upnpconfigaddress;
}
public void setUpnpConfigAddress(String upnpConfigAddress) {
this.upnpconfigaddress = upnpConfigAddress;
}
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() {
public Integer getServerPort() {
return serverport;
}
public void setServerPort(Integer serverPort) {
this.serverport = serverPort;
}
public void setServerPort(String serverPort) {
this.serverport = Integer.valueOf(serverPort);
}
public Integer getUpnpResponsePort() {
return upnpresponseport;
}
public void setUpnpResponsePort(Integer upnpResponsePort) {
this.upnpresponseport = upnpResponsePort;
}
public void setUpnpResponsePort(String upnpResponsePort) {
this.upnpresponseport = Integer.valueOf(upnpResponsePort);
}
public String getUpnpDeviceDb() {
return upnpdevicedb;
}
public void setUpnpDeviceDb(String upnpDeviceDb) {
this.upnpdevicedb = upnpDeviceDb;
}
public String getUpnpGroupDb() {
return upnpgroupdb;
}
public void setUpnpGroupDb(String upnpGroupDb) {
this.upnpgroupdb = upnpGroupDb;
}
public IpList getVeraAddress() {
return veraaddress;
}
public IpList getFibaroAddress() {
return fibaroaddress;
}
public IpList getSomfyAddress() {
return somfyaddress;
}
public IpList getHomeWizardAddress() {
return homewizardaddress;
}
}
public void setVeraAddress(IpList veraAddress) {
this.veraaddress = veraAddress;
}
public void setFibaroAddress(IpList fibaroAddress) {
this.fibaroaddress = fibaroAddress;
}
public void setSomfyAddress(IpList somfyAddress) {
this.somfyaddress = somfyAddress;
}
public void setHomeWizardAddress(IpList homewizardaddress) {
this.homewizardaddress = homewizardaddress;
}
public IpList getHarmonyAddress() {
return harmonyaddress;
}
public void setHarmonyAddress(IpList harmonyaddress) {
this.harmonyaddress = harmonyaddress;
}
/*
public boolean isUpnpStrict() {
return upnpstrict;
}
public void setUpnpStrict(boolean upnpStrict) {
this.upnpstrict = upnpStrict;
}
*/
public boolean isTraceupnp() {
return traceupnp;
}
public void setTraceupnp(boolean traceupnp) {
this.traceupnp = traceupnp;
}
public String getNestuser() {
return nestuser;
}
public void setNestuser(String nestuser) {
this.nestuser = nestuser;
}
public String getNestpwd() {
return nestpwd;
}
public void setNestpwd(String nestpwd) {
this.nestpwd = nestpwd;
}
public boolean isVeraconfigured() {
return veraconfigured;
}
public boolean isFibaroconfigured() {
return fibaroconfigured;
}
public boolean isSomfyconfigured() {
return somfyconfigured;
}
public boolean isHomeWizardConfigured() {
return homewizardconfigured;
}
}
public void setVeraconfigured(boolean veraconfigured) {
this.veraconfigured = veraconfigured;
}
public void setFibaroconfigured(boolean fibaroconfigured) {
this.fibaroconfigured = fibaroconfigured;
}
public void setSomfyconfigured(boolean somfyconfigured) {
this.somfyconfigured = somfyconfigured;
}
public void setHomeWizardConfigured(boolean homewizardconfigured) {
this.homewizardconfigured = homewizardconfigured;
}
public boolean isHarmonyconfigured() {
return harmonyconfigured;
}
public void setHarmonyconfigured(boolean harmonyconfigured) {
this.harmonyconfigured = harmonyconfigured;
}
public boolean isNestConfigured() {
return nestconfigured;
}
public void setNestConfigured(boolean isNestConfigured) {
this.nestconfigured = isNestConfigured;
}
public Integer getButtonsleep() {
return buttonsleep;
}
public void setButtonsleep(Integer buttonsleep) {
this.buttonsleep = buttonsleep;
}
public String getConfigfile() {
return configfile;
}
public void setConfigfile(String configfile) {
this.configfile = configfile;
}
public Integer getNumberoflogmessages() {
return numberoflogmessages;
}
public void setNumberoflogmessages(Integer numberoflogmessages) {
this.numberoflogmessages = numberoflogmessages;
}
public boolean isFarenheit() {
return farenheit;
}
public void setFarenheit(boolean farenheit) {
this.farenheit = farenheit;
}
public IpList getHueaddress() {
return hueaddress;
}
public void setHueaddress(IpList hueaddress) {
this.hueaddress = hueaddress;
}
public boolean isHueconfigured() {
return hueconfigured;
}
public void setHueconfigured(boolean hueconfigured) {
this.hueconfigured = hueconfigured;
}
public IpList getHaladdress() {
return haladdress;
}
public void setHaladdress(IpList haladdress) {
this.haladdress = haladdress;
}
public String getHaltoken() {
return haltoken;
}
public void setHaltoken(String haltoken) {
this.haltoken = haltoken;
}
public boolean isHalconfigured() {
return halconfigured;
}
public void setHalconfigured(boolean halconfigured) {
this.halconfigured = halconfigured;
}
public Map<String, WhitelistEntry> getWhitelist() {
return whitelist;
}
protected void removeWhitelist() {
whitelist = null;
}
public boolean isSettingsChanged() {
return settingsChanged;
}
public void setSettingsChanged(boolean settingsChanged) {
this.settingsChanged = settingsChanged;
}
public String getMyechourl() {
return myechourl;
}
public void setMyechourl(String myechourl) {
this.myechourl = myechourl;
}
public String getWebaddress() {
return webaddress;
}
public void setWebaddress(String webaddress) {
this.webaddress = webaddress;
}
public IpList getMqttaddress() {
return mqttaddress;
}
public void setMqttaddress(IpList mqttaddress) {
this.mqttaddress = mqttaddress;
}
public boolean isMqttconfigured() {
return mqttconfigured;
}
public void setMqttconfigured(boolean mqttconfigured) {
this.mqttconfigured = mqttconfigured;
}
public IpList getHassaddress() {
return hassaddress;
}
public void setHassaddress(IpList hassaddress) {
this.hassaddress = hassaddress;
}
public boolean isHassconfigured() {
return hassconfigured;
}
public void setHassconfigured(boolean 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() {
return hubversion;
}
public void setHubversion(String hubversion) {
this.hubversion = hubversion;
}
public String getHubmac() {
return hubmac;
}
public void setHubmac(String hubmac) {
this.hubmac = hubmac;
}
public IpList getDomoticzaddress() {
return domoticzaddress;
}
public void setDomoticzaddress(IpList domoticzaddress) {
this.domoticzaddress = domoticzaddress;
}
public boolean isDomoticzconfigured() {
return domoticzconfigured;
}
public void setDomoticzconfigured(boolean domoticzconfigured) {
this.domoticzconfigured = domoticzconfigured;
}
public boolean isLifxconfigured() {
return lifxconfigured;
}
public void setLifxconfigured(boolean 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() {
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
if (this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
return false;
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 true;
}
public Boolean isValidFibaro() {
if(this.getFibaroAddress() == null || this.getFibaroAddress().getDevices().size() <= 0)
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))
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidHarmony() {
if(this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
return false;
if (this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
return false;
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 true;
}
public Boolean isValidNest() {
if(this.getNestpwd() == null || this.getNestpwd().equals(""))
if (this.getNestpwd() == null || this.getNestpwd().equals(""))
return false;
if(this.getNestuser() == null || this.getNestuser().equals(""))
if (this.getNestuser() == null || this.getNestuser().equals(""))
return false;
return true;
}
public Boolean isValidHue() {
if(this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
if (this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
return false;
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 true;
}
public Boolean isValidHal() {
if(this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getHaladdress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
if (this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
return false;
if(devicesList.get(0).getPassword() == null || devicesList.get(0).getPassword().trim().isEmpty()) {
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
List<NamedIP> devicesList = this.getHaladdress().getDevices();
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
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;
}
public Boolean isValidMQTT() {
if(this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
return false;
if (this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getMqttaddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidHass() {
if(this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
return false;
if (this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
return false;
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 true;
}
public Boolean isValidDomoticz() {
if(this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
return false;
if (this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
return false;
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 true;
}
public Boolean isValidSomfy() {
if(this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
if (this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getSomfyAddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidLifx() {
return this.isLifxconfigured();
}
public void updateHue(NamedIP aHue) {
int indexHue = -1;
for( int i = 0; i < hueaddress.getDevices().size(); i++) {
if(hueaddress.getDevices().get(i).getName().equals(aHue.getName()))
for (int i = 0; i < hueaddress.getDevices().size(); i++) {
if (hueaddress.getDevices().get(i).getName().equals(aHue.getName()))
indexHue = i;
}
if(indexHue >= 0) {
if (indexHue >= 0) {
hueaddress.getDevices().set(indexHue, aHue);
this.setSettingsChanged(true);
}
}
public Boolean isValidHomeWizard() {
if(this.getHomeWizardAddress() == null || this.getHomeWizardAddress().getDevices().size() <= 0)
if (this.getHomeWizardAddress() == null || this.getHomeWizardAddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getHomeWizardAddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidOpenhab() {
if (this.getOpenhabaddress() == null || this.getOpenhabaddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getOpenhabaddress().getDevices();
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidFhem() {
if (this.getFhemaddress() == null || this.getFhemaddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getFhemaddress().getDevices();
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidBroadlink() {
return this.isBroadlinkconfigured();
}
public boolean isTracestate() {
return tracestate;
}
public void setTracestate(boolean tracestate) {
this.tracestate = tracestate;
}
public IpList getMoziotaddress() {
return moziotaddress;
}
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;
}
}

View File

@@ -14,4 +14,7 @@ public class Configuration {
public static final String CONFIG_FILE = "data/habridge.config";
public static final int NUMBER_OF_LOG_MESSAGES = 512;
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;
}

View File

@@ -31,6 +31,11 @@ public class DeviceMapTypes {
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz Device"};
public final static String[] SOMFY_DEVICE = { "somfyDevice", "Somfy Device"};
public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
public final static 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 displayIndex = 1;
@@ -56,7 +61,6 @@ public class DeviceMapTypes {
deviceMapTypes.add(MQTT_MESSAGE);
deviceMapTypes.add(NEST_HOMEAWAY);
deviceMapTypes.add(NEST_THERMO_SET);
deviceMapTypes.add(SOMFY_DEVICE);
deviceMapTypes.add(TCP_DEVICE);
deviceMapTypes.add(UDP_DEVICE);
deviceMapTypes.add(VERA_DEVICE);
@@ -64,6 +68,11 @@ public class DeviceMapTypes {
deviceMapTypes.add(FIBARO_DEVICE);
deviceMapTypes.add(FIBARO_SCENE);
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() {
return typeIndex;

View File

@@ -44,19 +44,19 @@ public class HABridge {
Version theVersion;
@SuppressWarnings("unused")
HttpClientPool thePool;
ShutdownHook shutdownHook = null;
log.info("HA Bridge startup sequence...");
theVersion = new Version();
// Singleton initialization
thePool = new HttpClientPool();
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
bridgeSettings = new BridgeSettings();
// sparkjava config directive to set html static file location for Jetty
while(!bridgeSettings.getBridgeControl().isStop()) {
bridgeSettings.buildSettings();
bridgeSettings.getBridgeSecurity().removeTestUsers();
log.info("HA Bridge initializing....");
log.info("HA Bridge (v{}) initializing....", theVersion.getVersion() );
// sparkjava config directive to set ip address for the web server to listen on
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
// sparkjava config directive to set port for the web server to listen on
@@ -69,6 +69,14 @@ public class HABridge {
// setup system control api first
theSystem = new SystemControl(bridgeSettings, theVersion);
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
udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort());
if(udpSender == null) {
@@ -86,12 +94,15 @@ public class HABridge {
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();
if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp())
log.info("Traceupnp: upnp config address: " + bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress() + "-useIface:" +
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface() + " on web server: " +
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress() + ":" + bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
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.getBridgeSettingsDescriptor());
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
theSettingResponder.setupServer();
// start the upnp ssdp discovery listener
@@ -103,7 +114,7 @@ public class HABridge {
theUpnpListener = null;
}
if(theUpnpListener != null && theUpnpListener.startListening())
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
log.info("HA Bridge (v{}) reinitialization requessted....", theVersion.getVersion());
else
bridgeSettings.getBridgeControl().setStop(true);
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
@@ -118,7 +129,7 @@ public class HABridge {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
log.error("Sleep error: " + e.getMessage());
log.error("Sleep error: {}", e.getMessage());
}
}
}
@@ -127,19 +138,19 @@ public class HABridge {
bridgeSettings.updateConfigFile();
try {
HttpClientPool.shutdown();
thePool = null;
} catch (InterruptedException e) {
log.warn("Error shutting down http pool: " + e.getMessage());;
log.warn("Error shutting down http pool: {}", e.getMessage());;
} catch (IOException e) {
log.warn("Error shutting down http pool: " + e.getMessage());;
log.warn("Error shutting down http pool: {}", e.getMessage());;
}
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
thePool = null;
log.info("HA Bridge (v{}) exiting....", theVersion.getVersion());
System.exit(0);
}
private static void theExceptionHandler(Exception e, Integer thePort) {
Logger log = LoggerFactory.getLogger(HABridge.class);
log.error("Could not start ha-bridge webservice on port [" + thePort + "] due to: " + e.getMessage());
log.error("Could not start ha-bridge webservice on port [{}] due to: {}", thePort, e.getMessage());
System.exit(0);
}
}

View File

@@ -9,8 +9,10 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
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.exec.CommandHome;
import com.bwssystems.HABridge.plugins.fhem.FHEMHome;
import com.bwssystems.HABridge.plugins.hal.HalHome;
import com.bwssystems.HABridge.plugins.harmony.HarmonyHome;
import com.bwssystems.HABridge.plugins.hass.HassHome;
@@ -18,12 +20,15 @@ import com.bwssystems.HABridge.plugins.homewizard.HomeWizardHome;
import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.plugins.lifx.LifxHome;
import com.bwssystems.HABridge.plugins.moziot.MozIotHome;
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.tcp.TCPHome;
import com.bwssystems.HABridge.plugins.udp.UDPHome;
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;
public class HomeManager {
@@ -39,6 +44,14 @@ public class HomeManager {
// factory method
public void buildHomes(BridgeSettings bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
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
aHome = new HarmonyHome(bridgeSettings);
resourceList.put(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex], aHome);
@@ -77,14 +90,6 @@ public class HomeManager {
aHome = new CommandHome(bridgeSettings);
homeList.put(DeviceMapTypes.EXEC_DEVICE_COMPAT[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);
homeList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
//setup the tcp handler Home
aHome = new TCPHome(bridgeSettings);
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
@@ -105,7 +110,7 @@ public class HomeManager {
aHome = new DomoticzHome(bridgeSettings);
homeList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the Somfy configuration if available
//setup the Somfy configuration if availableOPENHAB
aHome = new SomfyHome(bridgeSettings);
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
@@ -113,6 +118,26 @@ public class HomeManager {
aHome = new LifxHome(bridgeSettings);
resourceList.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) {

View File

@@ -1,5 +1,9 @@
package com.bwssystems.HABridge;
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
public class NamedIP {
private String name;
private String ip;
@@ -7,48 +11,103 @@ public class NamedIP {
private String port;
private String username;
private String password;
private JsonObject extensions;
private Boolean secure;
private String httpPreamble;
private String encodedLogin;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getWebhook() {
return webhook;
}
public void setWebhook(final String webhook) {
this.webhook = webhook;
}
public String getPort() {
public String getWebhook() {
return webhook;
}
public void setWebhook(final String webhook) {
this.webhook = webhook;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getSecure() {
return secure;
}
public void setSecure(Boolean 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;
}
}

View 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");
}
}
}
}

View File

@@ -14,15 +14,19 @@ import java.net.InetAddress;
import java.net.MulticastSocket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
//import java.util.ArrayList;
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.slf4j.Logger;
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.util.JsonTransformer;
@@ -36,6 +40,7 @@ import com.google.gson.reflect.TypeToken;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
//import ch.qos.logback.core.Appender;
import ch.qos.logback.core.read.CyclicBufferAppender;
public class SystemControl {
@@ -55,7 +60,7 @@ public class SystemControl {
this.version = theVersion;
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
reacquireCBA();
setupLoggerSettings();
theLogServiceMgr = new LoggingManager();
theLogServiceMgr.init();
}
@@ -88,7 +93,7 @@ public class SystemControl {
String logMsgs;
int count = -1;
if(cyclicBufferAppender == null)
reacquireCBA();
setupLoggerSettings();
if (cyclicBufferAppender != null) {
count = cyclicBufferAppender.getLength();
}
@@ -238,6 +243,24 @@ public class SystemControl {
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);
@@ -356,6 +379,8 @@ public class SystemControl {
log.debug("bridge settings requested from " + request.ip());
response.status(HttpStatus.SC_OK);
response.type("application/json");
// if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() == null)
// bridgeSettings.getBridgeSettingsDescriptor().setActiveloggers(getLogAppenders());
return bridgeSettings.getBridgeSettingsDescriptor();
}, new JsonTransformer());
@@ -372,6 +397,8 @@ public class SystemControl {
put(SYSTEM_CONTEXT + "/settings", (request, response) -> {
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
if(newBridgeSettings.getUpnpsenddelay() > 15000)
newBridgeSettings.setUpnpsenddelay(15000);
bridgeSettings.save(newBridgeSettings);
response.status(HttpStatus.SC_OK);
response.type("application/json");
@@ -410,6 +437,41 @@ public class SystemControl {
return stop();
});
// http://ip_address:port/system/devices/backup/download CORS request
options(SYSTEM_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 (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");
@@ -482,11 +544,42 @@ public class SystemControl {
}, new JsonTransformer());
}
void reacquireCBA() {
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
private void setupLoggerSettings() {
// 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);
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() {
try {
@@ -518,4 +611,5 @@ public class SystemControl {
pingListener();
return "{\"control\":\"stopping\"}";
}
}

View File

@@ -1,14 +1,14 @@
package com.bwssystems.HABridge.api.hue;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class WhitelistEntry
{
private String lastUseDate;
private String createDate;
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) {
WhitelistEntry anEntry = new WhitelistEntry();
@@ -18,9 +18,9 @@ public class WhitelistEntry
return anEntry;
}
public static String getCurrentDate() {
return dateFormat.format(new Date());
}
public static String getCurrentDate() {
return LocalDateTime.now().format(dateTimeFormat);
}
public String getLastUseDate() {
return lastUseDate;

View File

@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.dao;
public class BackupFilename {
private String filename;
private String file;
public String getFilename() {
return filename;
@@ -10,4 +11,13 @@ public class BackupFilename {
public void setFilename(String filename) {
this.filename = filename;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
}

View File

@@ -80,7 +80,19 @@ public class DeviceDescriptor{
@SerializedName("deviceState")
@Expose
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() {
return name;
}
@@ -275,6 +287,22 @@ public class DeviceDescriptor{
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) {
if(aType == null)
return false;
@@ -311,4 +339,20 @@ public class DeviceDescriptor{
}
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;
}
}

View File

@@ -1,8 +1,6 @@
package com.bwssystems.HABridge.dao;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -13,18 +11,18 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
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.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.BackupHandler;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.bwssystems.HABridge.util.HexLibrary;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
@@ -39,45 +37,47 @@ import java.util.Arrays;
*/
public class DeviceRepository extends BackupHandler {
private Map<String, DeviceDescriptor> devices;
private Path repositoryPath;
private Path repositoryPath;
private Gson gson;
private Integer nextId;
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
public DeviceRepository(String deviceDb) {
private Integer nextId;
private Integer seedId;
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
public DeviceRepository(String deviceDb, Integer seedid) {
super();
gson =
new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
repositoryPath = null;
repositoryPath = Paths.get(deviceDb);
setupParams(repositoryPath, ".bk", "device.db-");
nextId = 0;
nextId = seedid;
seedId = seedid;
_loadRepository(repositoryPath);
}
public void loadRepository() {
if(repositoryPath != null)
_loadRepository(repositoryPath);
}
private void _loadRepository(Path aPath){
public void loadRepository() {
if (repositoryPath != null)
_loadRepository(repositoryPath);
}
private void _loadRepository(Path aPath) {
String jsonContent = repositoryReader(aPath);
devices = new HashMap<String, DeviceDescriptor>();
if(jsonContent != null)
{
if (jsonContent != null) {
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
for(int i = 0; i < list.length; i++) {
list[i].setDeviceState(null);
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]);
if(Integer.decode(list[i].getId()) > nextId) {
if (Integer.decode(list[i].getId()) > nextId) {
nextId = Integer.decode(list[i].getId());
}
}
}
}
}
}
public List<DeviceDescriptor> findAll() {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
return list;
@@ -85,8 +85,8 @@ public class DeviceRepository extends BackupHandler {
public List<DeviceDescriptor> findActive() {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>();
for(DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
if(!aDevice.isInactive())
for (DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
if (!aDevice.isInactive())
list.add(aDevice);
}
return list;
@@ -103,12 +103,12 @@ public class DeviceRepository extends BackupHandler {
DeviceDescriptor theDevice;
String theRequesterAddress;
HashMap<String,String > addressMap;
HashMap<String, String> addressMap;
while (anIterator.hasNext()) {
theDevice = anIterator.next();
theRequesterAddress = theDevice.getRequesterAddress();
addressMap = new HashMap<String, String>();
if(theRequesterAddress != null) {
if (theRequesterAddress != null) {
if (theRequesterAddress.contains(",")) {
String[] theArray = theRequesterAddress.split(",");
for (String v : theArray) {
@@ -123,155 +123,185 @@ public class DeviceRepository extends BackupHandler {
return theReturnList;
}
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) {
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) {
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()))) {
for (DeviceDescriptor light : (ignoreAddress ? lights.values()
: findAllByRequester(anAddress, lights.values()))) {
DeviceResponse deviceResponse = null;
if(!light.isInactive()) {
if (!light.isInactive()) {
if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
CallItem[] callItems = null;
try {
if(light.getOnUrl() != null)
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());
} 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"))) {
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);
deviceResponseMap.put(light.getId(), deviceResponse);
}
}
return (deviceResponseMap.size() == 0) ? null : deviceResponseMap;
}
public DeviceDescriptor findOne(String id) {
return devices.get(id);
}
return devices.get(id);
}
private void put(String id, DeviceDescriptor aDescriptor) {
devices.put(id, aDescriptor);
}
devices.put(id, aDescriptor);
}
public void save(DeviceDescriptor[] descriptors) {
String theNames = "";
for(int i = 0; i < descriptors.length; i++) {
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
devices.remove(descriptors[i].getId());
else {
nextId++;
descriptors[i].setId(String.valueOf(nextId));
}
if(descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
BigInteger bigInt = BigInteger.valueOf(Integer.decode(descriptors[i].getId()));
byte[] theBytes = bigInt.toByteArray();
String hexValue = DatatypeConverter.printHexBinary(theBytes);
for (int i = 0; i < descriptors.length; i++) {
if (descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
devices.remove(descriptors[i].getId());
else {
descriptors[i].setId(String.valueOf(nextId));
nextId++;
}
if (descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
String hexValue = HexLibrary.encodeUsingBigIntegerToString(descriptors[i].getId());
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
}
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());
repositoryWriter(jsonValue, repositoryPath);
log.debug("Save device(s): " + theNames);
}
String jsonValue = gson.toJson(findAll());
repositoryWriter(jsonValue, repositoryPath);
log.debug("Save device(s): {}", theNames);
}
public void renumber() {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
Iterator<DeviceDescriptor> deviceIterator = list.iterator();
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();;
nextId = 0;
log.debug("Renumber devices.");
while(deviceIterator.hasNext()) {
nextId++;
DeviceDescriptor theDevice = deviceIterator.next();
theDevice.setId(String.valueOf(nextId));
BigInteger bigInt = BigInteger.valueOf(nextId);
byte[] theBytes = bigInt.toByteArray();
String hexValue = DatatypeConverter.printHexBinary(theBytes);
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
newdevices.put(theDevice.getId(), theDevice);
}
devices = newdevices;
String jsonValue = gson.toJson(findAll());
repositoryWriter(jsonValue, repositoryPath);
}
public String delete(DeviceDescriptor aDescriptor) {
if (aDescriptor != null) {
devices.remove(aDescriptor.getId());
JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(findAll());
repositoryWriter(jsonValue, repositoryPath);
return "Device with id '" + aDescriptor.getId() + "' deleted";
} else {
return "Device not found";
}
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();
List<String> lockedIds = new ArrayList<String>();
String hexValue;
Integer newValue;
DeviceDescriptor theDevice;
boolean findNext = true;
nextId = seedId;
while(deviceIterator.hasNext()) {
theDevice = deviceIterator.next();
if(theDevice.isLockDeviceId()) {
lockedIds.add(theDevice.getId());
}
}
log.debug("Renumber devices starting with: {}", nextId);
deviceIterator = list.iterator();
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));
newValue = nextId % 256;
if (newValue <= 0)
newValue = 1;
else if (newValue > 255)
newValue = 255;
hexValue = HexLibrary.encodeUsingBigIntegerToString(newValue.toString());
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
nextId++;
}
newdevices.put(theDevice.getId(), theDevice);
}
devices = newdevices;
String jsonValue = gson.toJson(findAll());
repositoryWriter(jsonValue, repositoryPath);
}
public String delete(DeviceDescriptor aDescriptor) {
if (aDescriptor != null) {
devices.remove(aDescriptor.getId());
JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(findAll());
repositoryWriter(jsonValue, repositoryPath);
return "Device with id '" + aDescriptor.getId() + "' deleted";
} else {
return "Device not found";
}
}
}
private void repositoryWriter(String content, Path filePath) {
if(Files.exists(filePath) && !Files.isWritable(filePath)){
log.error("Error file is not writable: " + filePath);
if (Files.exists(filePath) && !Files.isWritable(filePath)) {
log.error("Error file is not writable: {}", filePath);
return;
}
if(Files.notExists(filePath.getParent())) {
if (Files.notExists(filePath.getParent())) {
try {
Files.createDirectories(filePath.getParent());
} 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 {
Path target = null;
if(Files.exists(filePath)) {
if (Files.exists(filePath)) {
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
if(target != null)
if (target != null)
Files.delete(target);
} 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) {
String content = null;
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
if (Files.notExists(filePath) || !Files.isReadable(filePath)) {
log.warn("Error reading the file: {} - Does not exist or is not readable. continuing...", filePath);
return null;
}
try {
content = new String(Files.readAllBytes(filePath));
} 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;
}
}

View File

@@ -44,13 +44,15 @@ public class DeviceResource {
private BridgeSettings bridgeSettings;
private Gson aGsonHandler;
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
private String errorMessage;
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
bridgeSettings = theSettings;
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb());
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb(), bridgeSettings.getBridgeSettingsDescriptor().getSeedid());
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
homeManager = aHomeManager;
aGsonHandler = new GsonBuilder().create();
errorMessage = null;
setupEndpoints();
}
@@ -83,7 +85,7 @@ public class DeviceResource {
return "";
});
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[];
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
@@ -93,13 +95,12 @@ public class DeviceResource {
}
@SuppressWarnings("unused")
CallItem[] callItems = null;
String errorMessage = null;
for(int i = 0; i < devices.length; i++) {
if(devices[i].getContentBody() != null ) {
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
response.status(HttpStatus.SC_BAD_REQUEST);
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);
}
}
@@ -109,7 +110,7 @@ public class DeviceResource {
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
log.debug(errorMessage);
log.warn(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
@@ -118,7 +119,7 @@ public class DeviceResource {
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
log.debug(errorMessage);
log.warn(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
@@ -127,7 +128,7 @@ public class DeviceResource {
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
log.debug(errorMessage);
log.warn(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
@@ -136,13 +137,13 @@ public class DeviceResource {
} 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.debug(errorMessage);
log.warn(errorMessage);
return new ErrorMessage(errorMessage);
}
}
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.status(HttpStatus.SC_CREATED);
@@ -160,16 +161,17 @@ public class DeviceResource {
return "";
});
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);
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);
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
return new ErrorMessage(errorMessage);
}
else
{
log.debug("Saving an edited Device: " + device.getName());
log.debug("Saving an edited Device: {}", device.getName());
if (device.getDeviceType() != null)
device.setDeviceType(device.getDeviceType());
@@ -187,17 +189,19 @@ public class DeviceResource {
log.debug("Get all devices");
JsonTransformer aRenderer = new JsonTransformer();
String theStream = aRenderer.render(deviceList);
log.debug("The Device List: " + theStream);
log.debug("The Device List: {}", theStream);
response.status(HttpStatus.SC_OK);
return deviceList;
}, new JsonTransformer());
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"));
if(descriptor == null) {
errorMessage = "Could not find, id: " + request.params(":id");
log.warn(errorMessage);
response.status(HttpStatus.SC_NOT_FOUND);
return new ErrorMessage("Could not find, id: " + request.params(":id") + " ");
return new ErrorMessage(errorMessage);
}
else
response.status(HttpStatus.SC_OK);
@@ -206,11 +210,13 @@ public class DeviceResource {
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
String anId = request.params(":id");
log.debug("Delete a device: " + anId);
log.debug("Delete a device: {}", anId);
DeviceDescriptor deleted = deviceRepository.findOne(anId);
if(deleted == null) {
errorMessage = "Could not delete, id: " + anId + " not found. ";
log.warn(errorMessage);
response.status(HttpStatus.SC_NOT_FOUND);
return new ErrorMessage("Could not delete, id: " + anId + " not found. ");
return new ErrorMessage(errorMessage);
}
else
{
@@ -315,11 +321,49 @@ public class DeviceResource {
return homeManager.findResource(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]);
}, 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) -> {
log.debug("Get map types");
return new DeviceMapTypes().getDeviceMapTypes();
}, 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
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
@@ -336,11 +380,46 @@ public class DeviceResource {
}, new JsonTransformer());
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
log.debug("Get backup filenames");
log.debug("Get backup filenames.");
response.status(HttpStatus.SC_OK);
return deviceRepository.getBackups();
}, 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
options(API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
@@ -351,7 +430,7 @@ public class DeviceResource {
return "";
});
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 returnFilename = new BackupFilename();
returnFilename.setFilename(deviceRepository.backup(aFilename.getFilename()));
@@ -368,7 +447,7 @@ public class DeviceResource {
return "";
});
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);
if(aFilename != null)
deviceRepository.deleteBackup(aFilename.getFilename());
@@ -387,7 +466,7 @@ public class DeviceResource {
return "";
});
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);
if(aFilename != null) {
deviceRepository.restoreBackup(aFilename.getFilename());

View File

@@ -2,4 +2,5 @@ package com.bwssystems.HABridge.devicemanagmeent;
public interface ResourceHandler {
public Object getItems(String type);
public void refresh();
}

View File

@@ -52,11 +52,22 @@ public class BrightnessDecode {
boolean notDone = true;
String replaceValue = null;
String replaceTarget = null;
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
float decimalBrightness = (float) (intensity / 255.0);
int percentBrightness = 0;
float decimalBrightness = (float) 0.0;
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
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) 0.0;
percentBrightness = 0;
}
while(notDone) {
notDone = false;
if (request.contains(INTENSITY_BYTE)) {
@@ -111,11 +122,7 @@ public class BrightnessDecode {
Integer endResult = calculateMath(variables, mathDescriptor);
if(endResult != null) {
if (isHex) {
replaceValue = convertToHex(endResult);
} else {
replaceValue = endResult.toString();
}
replaceValue = convertToHex(endResult);
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE_HEX;
notDone = true;
}

View File

@@ -19,4 +19,10 @@ public class ColorData {
return mode;
}
public String toString() {
String formatString;
formatString = "Color Data mode: " + mode + ", data: " + data;
return formatString;
}
}

View File

@@ -4,7 +4,7 @@ import java.util.ArrayList;
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;
@@ -20,93 +20,184 @@ public class ColorDecode {
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_HSL = "${color.hsl}";
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
public static List<Integer> convertHSLtoRGB(HueSatBri hsl) {
List<Integer> rgb;
float decimalBrightness = (float) 0.0;
float var_1 = (float) 0.0;
float var_2 = (float) 0.0;
float h = (float) 0.0;
float h2 = (float) 0.0;
float s = (float) 0.0;
double r = 0.0;
double g = 0.0;
double b = 0.0;
if(hsl.getBri() > 0)
decimalBrightness = (float) (hsl.getBri() / 255.0);
if(hsl.getHue() > 0) {
h = ((float)hsl.getHue() / (float)65535.0);
h2 = h + (float)0.5;
if(h2 > 1.0) {
h2 = h2 - (float)1.0;
}
}
if(hsl.getSat() > 0) {
s = (float)(hsl.getSat() / 254.0);
}
if (s == 0)
{
r = decimalBrightness * (float)255;
g = decimalBrightness * (float)255;
b = decimalBrightness * (float)255;
}
else
{
if (decimalBrightness < 0.5)
{
var_2 = decimalBrightness * (1 + s);
}
else
{
var_2 = (decimalBrightness + s) - (s * decimalBrightness);
};
var_1 = 2 * decimalBrightness - var_2;
float onethird = (float)0.33333;
float h2Plus = (h2 + onethird);
float h2Minus = (h2 - onethird);
log.debug("calculate HSL vars - var1: " + var_1 + ", var_2: " + var_2 + ", h2: " + h2 + ", h2 + 1/3: " + h2Plus + ", h2 - 1/3: " + h2Minus);
r = 255 * hue_2_rgb(var_1, var_2, h2Plus);
g = 255 * hue_2_rgb(var_1, var_2, h2);
b = 255 * hue_2_rgb(var_1, var_2, h2Minus);
};
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 HSL: " + hsl + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2));
return rgb;
}
public static float hue_2_rgb(float v1, float v2, float vh) {
log.debug("hue_2_rgb vh: " + vh);
if (vh < 0.0)
{
vh = vh + (float)1;
};
if (vh > 1.0)
{
vh = vh - (float)1;
};
if (((float)6.0 * vh) < 1.0)
{
return (v1 + (v2 - v1) * (float)6.0 * vh);
};
if (((float)2.0 * vh) < 1.0)
{
return (v2);
};
if ((3.0 * vh) < 2.0)
{
return (v1 + (v2 - v1) * (((float)2.0 / (float)3.0 - vh) * (float)6.0));
};
return (v1);
}
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
List<Integer> rgb;
double x = xy.get(0); // the given x value
double y = xy.get(1); // the given y value
double z = 1.0 - x - y;
double Y = (double)brightness/(double)254.00; // The given brightness value
double Y = (double) brightness / (double) 254.00; // The given brightness value
double X = (Y / y) * x;
double Z = (Y / y) * z;
double r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
double r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
double g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
double b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;
double b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;
if (r > b && r > g && r > 1.0) {
g = g / r;
b = b / r;
r = 1.0;
}
else if (g > b && g > r && g > 1.0) {
} else if (g > b && g > r && g > 1.0) {
r = r / g;
b = b / g;
g = 1.0;
}
else if (b > r && b > g && b > 1.0) {
} else if (b > r && b > g && b > 1.0) {
r = r / b;
g = g / b;
b = 1.0;
}
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
if (r > b && r > g) {
// red is biggest
if (r > 1.0) {
g = g / r;
b = b / r;
r = 1.0;
}
}
else if (g > b && g > r) {
// green is biggest
if (g > 1.0) {
r = r / g;
b = b / g;
g = 1.0;
}
}
else if (b > r && b > g) {
// blue is biggest
if (b > 1.0) {
r = r / b;
g = g / b;
b = 1.0;
}
}
if(r < 0.0)
r = 0;
if(g < 0.0)
g = 0;
if(b < 0.0)
b = 0;
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 XY: " + x + " " + y + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
if (r > b && r > g) {
// red is biggest
if (r > 1.0) {
g = g / r;
b = b / r;
r = 1.0;
}
} else if (g > b && g > r) {
// green is biggest
if (g > 1.0) {
r = r / g;
b = b / g;
g = 1.0;
}
} else if (b > r && b > g) {
// blue is biggest
if (b > 1.0) {
r = r / b;
g = g / b;
b = 1.0;
}
}
if (r < 0.0)
r = 0;
if (g < 0.0)
g = 0;
if (b < 0.0)
b = 0;
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 XY: " + x + " " + y + " 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/
// 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;
double temperature = 1000000.0 / (double) ct;
temperature /= 100;
double r,g,b;
double r, g, b;
if (temperature <= 66) {
r = 255;
g = temperature;
g = 99.4708025861 * Math.log(g) - 161.1195681661;
g = 99.4708025861 * Math.log(g) - 161.1195681661;
} else {
r = temperature - 60;
r = 329.698727446 * (Math.pow(r, -0.1332047592));
@@ -124,25 +215,26 @@ public class ColorDecode {
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;
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;
value = 0;
}
if (value > 255.0) {
value = 255;
}
return value;
}
@SuppressWarnings("unchecked")
@@ -157,25 +249,30 @@ public class ColorDecode {
ColorData.ColorMode colorMode = colorData.getColorMode();
List<Integer> rgb = null;
if (colorMode == ColorData.ColorMode.XY) {
rgb = convertCIEtoRGB((List<Double>)colorData.getData(), setIntensity);
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
} else if (colorMode == ColorData.ColorMode.CT) {
rgb = convertCTtoRGB((Integer)colorData.getData());
rgb = convertCTtoRGB((Integer) colorData.getData());
} else if (colorMode == ColorData.ColorMode.HS) {
rgb = convertHSLtoRGB((HueSatBri) colorData.getData());
}
while(notDone) {
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)));
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)));
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)));
request = request.replace(COLOR_B,
isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
notDone = true;
}
@@ -195,64 +292,93 @@ public class ColorDecode {
}
if (request.contains(COLOR_RGBX)) {
request = request.replace(COLOR_RGBX, String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)));
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_HSL)) {
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_HSL, 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);
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;
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";
}
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;
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}

View File

@@ -119,13 +119,13 @@ public class NestHome implements com.bwssystems.HABridge.Home {
log.warn("Should not get here, no Nest available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"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])) {
NestInstruction homeAway = null;
if(anItem.getItem().isJsonObject())
homeAway = aGsonHandler.fromJson(anItem.getItem(), NestInstruction.class);
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());
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_THERMO_SET[DeviceMapTypes.typeIndex])) {
NestInstruction thermoSetting = null;
@@ -167,7 +167,7 @@ public class NestHome implements com.bwssystems.HABridge.Home {
log.warn("no valid Nest control info: " + thermoSetting.getControl());
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"no valid Nest control info\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
}
}
return responseString;
@@ -197,5 +197,10 @@ public class NestHome implements com.bwssystems.HABridge.Home {
}
return this;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -3,12 +3,10 @@ package com.bwssystems.HABridge.plugins.domoticz;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Base64;
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;
@@ -43,7 +41,7 @@ public class DomoticzHandler {
theUrl = buildUrl(rootRequest + type + postpend);
else
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) {
log.debug("GET " + type + " DomoticzApiResponse - data: " + theData);
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
@@ -76,15 +74,7 @@ public class DomoticzHandler {
String newUrl = null;
if(thePayload != null && !thePayload.isEmpty()) {
if(domoticzAddress.getSecure() != null && domoticzAddress.getSecure())
newUrl = "https://";
else
newUrl = "http://";
newUrl = newUrl + domoticzAddress.getIp();
if(domoticzAddress.getPort() != null && !domoticzAddress.getPort().isEmpty())
newUrl = newUrl + ":" + domoticzAddress.getPort();
newUrl = domoticzAddress.getHttpPreamble();
if(thePayload.startsWith("/"))
newUrl = newUrl + thePayload;
@@ -95,21 +85,6 @@ public class DomoticzHandler {
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() {
return domoticzAddress;
}

View File

@@ -18,7 +18,10 @@ 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;
@@ -41,7 +44,7 @@ public class DomoticzHome implements Home {
public Object getItems(String type) {
if(!validDomoticz)
return null;
log.debug("consolidating devices for hues");
log.debug("consolidating devices for Domoticzs");
List<DomoticzDevice> theResponse = null;
Iterator<String> keys = domoticzs.keySet().iterator();
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
@@ -63,9 +66,14 @@ public class DomoticzHome implements Home {
return deviceList;
}
@Override
public void refresh() {
// noop
}
private Boolean addDomoticzDevices(List<DomoticzDevice> theDeviceList, List<DomoticzDevice> theSourceList, String theKey) {
if(!validDomoticz)
return null;
return false;
Iterator<DomoticzDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
DomoticzDevice theDevice = devices.next();
@@ -80,7 +88,7 @@ public class DomoticzHome implements Home {
Devices theDomoticzApiResponse = 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://"))) {
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
@@ -95,7 +103,23 @@ public class DomoticzHome implements Home {
String theData;
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
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 {
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
if(theDomoticzApiResponse.getStatus().equals("OK"))
@@ -104,25 +128,25 @@ public class DomoticzHome implements Home {
log.warn("Call failed for Domoticz " + theHandler.getDomoticzAddress().getName() + " with status " + theDomoticzApiResponse.getStatus() + " for item " + theDomoticzApiResponse.getTitle());
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
} catch (Exception e) {
log.warn("Cannot interrpret result from call for Domoticz " + theHandler.getDomoticzAddress().getName() + " as response is not parsable.");
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
} else {
log.warn("Domoticz Call could not complete, no address found: " + theUrl);
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
} else {
log.warn("Domoticz Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
return responseString;
}
@@ -167,7 +191,7 @@ public class DomoticzHome implements Home {
@Override
public void closeHome() {
log.debug("Closing Home.");
if(closed) {
if(closed || !validDomoticz) {
log.debug("Home is already closed....");
return;
}
@@ -175,6 +199,7 @@ public class DomoticzHome implements Home {
if(httpClient != null)
httpClient.closeHandler();
domoticzs = null;
closed = true;
}
}

View File

@@ -31,13 +31,14 @@ public class CommandHome implements Home {
@Override
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() + " and exec Garden: " + (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
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 intermediate;
if (anItem.getItem().getAsString().contains("exec://"))
intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
if (theItem.contains("exec://"))
intermediate = theItem.substring(anItem.getItem().getAsString().indexOf("://") + 3);
else
intermediate = anItem.getItem().getAsString();
intermediate = theItem;
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
if (colorData != null) {
intermediate = ColorDecode.replaceColorData(intermediate, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
@@ -67,13 +68,13 @@ public class CommandHome implements Home {
log.warn("Could not execute request: " + anItem + " with message: " + e.getMessage());
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
+ "state\"}}]";
+ "/state\"}}]";
}
} else {
log.warn("Could not execute request. Request is empty.");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
+ "state\"}}]";
+ "/state\"}}]";
}
return responseString;
@@ -92,6 +93,11 @@ public class CommandHome implements Home {
return null;
}
@Override
public void refresh() {
// noop
}
@Override
public void closeHome() {
log.debug("Closing Home.");

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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() {
}
}

View File

@@ -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;
}
}

View File

@@ -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\">&nbsp;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>";
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -84,6 +84,11 @@ public class FibaroHome implements Home
return null;
}
@Override
public void refresh() {
// noop
}
@Override
public Home createHome(BridgeSettings bridgeSettings)
{

View File

@@ -6,7 +6,6 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -23,19 +22,33 @@ public class FibaroInfo
private final NamedIP fibaroAddress;
private final String fibaroAuth;
private final Gson gson;
// You can disable it if you want TODO config
boolean useSaveLogs = true; // This can be used to exclude some devices from list
boolean useUserDescription = true;
boolean replaceTrash = true;
boolean scenesWithLiliCommandOnly = true;
private Boolean isDevMode;
private FibaroFilter theFilters;
public FibaroInfo(NamedIP addressName)
{
super();
fibaroAddress = addressName;
fibaroAuth = "Basic " + new String(Base64.encodeBase64((addressName.getUsername() + ":" + addressName.getPassword()).getBytes()));
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)
@@ -66,24 +79,6 @@ public class FibaroInfo
return result;
}
protected boolean sendCommand(String request)
{
try
{
URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", fibaroAuth);
connection.getResponseMessage();
}
catch(IOException e)
{
log.warn("Error while get getJson: {} ", request, e);
return false;
}
return true;
}
private String replaceTrash(String name)
{
String sanitizedName = name.replaceAll("[0-9:/-]", "");
@@ -93,9 +88,14 @@ public class FibaroInfo
private Room[] getRooms()
{
String result = request("/api/rooms");
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(replaceTrash)
if(theFilters.isReplaceTrash())
for(Room r : rooms)
r.setName(replaceTrash(r.getName()));
return rooms;
@@ -105,24 +105,29 @@ public class FibaroInfo
{
Room[] rooms = getRooms();
log.info("Found: " + rooms.length + " rooms");
log.debug("getDevices Found: " + rooms.length + " rooms");
String result = request("/api/devices?enabled=true&visible=true");
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 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true))
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 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true))
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
{
if(useUserDescription && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
if(theFilters.isUseUserDescription() && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
d.setName(d.getProperties().getUserDescription());
if(replaceTrash)
if(theFilters.isReplaceTrash())
d.setName(replaceTrash(d.getName()));
devices[i++] = d;
@@ -137,7 +142,7 @@ public class FibaroInfo
d.fibaroname = fibaroAddress.getName();
}
log.info("Found: " + devices.length + " devices");
log.debug("getDevices Found: " + devices.length + " devices");
return devices;
}
@@ -146,19 +151,24 @@ public class FibaroInfo
{
Room[] rooms = getRooms();
String result = request("/api/scenes?enabled=true&visible=true");
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(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
count++;
Scene[] scenes = new Scene[count];
int i = 0;
for(Scene s : all_scenes)
if(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
{
if(replaceTrash)
if(theFilters.isReplaceTrash())
s.setName(replaceTrash(s.getName()));
scenes[i++] = s;
@@ -172,7 +182,7 @@ public class FibaroInfo
s.fibaroAuth = fibaroAuth;
s.fibaroname = fibaroAddress.getName();
}
log.info("Found: " + count + " scenes");
log.debug("getScenes Found: " + count + " scenes");
return scenes;
}
}

View File

@@ -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";
}

View File

@@ -1,35 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro;
public enum ModeType {
OFF(0, "Off"),
HEAT(1, "Heat"),
COOL(2, "Cool"),
AUTO(3, "Auto"),
AUX_HEAT(4, "Aux Heat"),
RESUME(5, "Resume"),
FAN_ONLY(6, "Fan Only"),
FURNANCE(7, "Furnace"),
DRY_AIR(8, "Dry Air"),
MOIST_AIR(9, "Moist Air"),
AUTO_CHANGEOVER(10, "Auto Changeover"),
HEAT_ECON(11, "Heat Econ"),
COOL_ECON(12, "Cool Econ"),
AWAY(13, "Away"),
MANUAL(31, "Manual");
private int key;
private String label;
private ModeType(int key, String label) {
this.key = key;
this.label = label;
}
public int getKey() {
return key;
}
public String getLabel() {
return label;
}
}

View File

@@ -17,48 +17,9 @@ public class Device {
@SerializedName("type")
private String type;
@SerializedName("baseType")
private String baseType;
@SerializedName("enabled")
private boolean enabled;
@SerializedName("visible")
private boolean visible;
@SerializedName("isPlugin")
private boolean isPlugin;
@SerializedName("parentId")
private int parentId;
@SerializedName("remoteGatewayId")
private int remoteGatewayId;
@SerializedName("viewXml")
private boolean viewXml;
@SerializedName("configXml")
private boolean configXml;
@SerializedName("interfaces")
private Object interfaces;
@SerializedName("properties")
private DeviceProperties properties;
@SerializedName("actions")
private Object actions;
@SerializedName("created")
private int created;
@SerializedName("modified")
private int modified;
@SerializedName("sortOrder")
private int sortOrder;
public String getRoomName() {
return roomName;
}

View File

@@ -3,242 +3,21 @@ package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class DeviceProperties {
@SerializedName("batteryLevel")
private String batteryLevel;
@SerializedName("UIMessageSendTime")
private String UIMessageSendTime;
@SerializedName("autoConfig")
private String autoConfig;
@SerializedName("color")
private String color;
@SerializedName("date")
private String date;
@SerializedName("dead")
private String dead;
@SerializedName("deviceControlType")
private String deviceControlType;
@SerializedName("deviceIcon")
private String deviceIcon;
@SerializedName("disabled")
private String disabled;
@SerializedName("emailNotificationID")
private String emailNotificationID;
@SerializedName("emailNotificationType")
private String emailNotificationType;
@SerializedName("endPoint")
private String endPoint;
@SerializedName("energy")
private String energy;
@SerializedName("liliOffCommand")
private String liliOffCommand;
@SerializedName("liliOnCommand")
private String liliOnCommand;
@SerializedName("log")
private String log;
@SerializedName("logTemp")
private String logTemp;
@SerializedName("manufacturer")
private String manufacturer;
@SerializedName("markAsDead")
private String markAsDead;
@SerializedName("mode")
private String mode;
@SerializedName("model")
private String model;
@SerializedName("nodeID")
private String nodeID;
@SerializedName("pollingDeadDevice")
private String pollingDeadDevice;
@SerializedName("pollingTime")
private String pollingTime;
@SerializedName("pollingTimeNext")
private String pollingTimeNext;
@SerializedName("pollingTimeSec")
private int pollingTimeSec;
@SerializedName("power")
private String power;
@SerializedName("productInfo")
private String productInfo;
@SerializedName("pushNotificationID")
private String pushNotificationID;
@SerializedName("pushNotificationType")
private String pushNotificationType;
@SerializedName("remoteGatewayId")
private String remoteGatewayId;
@SerializedName("requestNodeNeighborStat")
private String requestNodeNeighborStat;
@SerializedName("requestNodeNeighborStatTimeStemp")
private String requestNodeNeighborStatTimeStemp;
@SerializedName("requestNodeNeighborState")
private String requestNodeNeighborState;
@SerializedName("requestNodeNeighborStateTimeStemp")
private String requestNodeNeighborStateTimeStemp;
@SerializedName("value")
private String value;
@SerializedName("saveLogs")
private String saveLogs;
@SerializedName("showChildren")
private String showChildren;
@SerializedName("smsNotificationID")
private String smsNotificationID;
@SerializedName("smsNotificationType")
private String smsNotificationType;
@SerializedName("supportedModes")
private String supportedModes;
@SerializedName("targetLevel")
private String targetLevel;
@SerializedName("unit")
private String unit;
@SerializedName("useTemplate")
private String useTemplate;
@SerializedName("status")
private String status;
@SerializedName("sunriseHour")
private String sunriseHour;
@SerializedName("sunsetHour")
private String sunsetHour;
@SerializedName("userDescription")
private String userDescription;
@SerializedName("value")
private String value;
@SerializedName("zwaveBuildVersion")
private String zwaveBuildVersion;
@SerializedName("zwaveCompany")
private String zwaveCompany;
@SerializedName("zwaveInfo")
private String zwaveInfo;
@SerializedName("zwaveRegion")
private String zwaveRegion;
@SerializedName("zwaveVersion")
private double zwaveVersion;
public String getBatteryLevel() {
return batteryLevel;
}
public String getColor() {
return color;
}
public String getDeviceControlType() {
return deviceControlType;
}
public String getEnergy() {
return energy;
}
public String getPower() {
return power;
}
public String getTargetLevel() {
return targetLevel;
}
public String getValue() {
return value;
}
// --- begin yrWeather plugin ---
@SerializedName("Humidity")
private String Humidity;
@SerializedName("Pressure")
private String Pressure;
@SerializedName("Temperature")
private String Temperature;
@SerializedName("WeatherCondition")
private String WeatherCondition;
@SerializedName("Wind")
private String Wind;
public String getHumidity() {
return Humidity;
}
public String getPressure() {
return Pressure;
}
public String getSaveLogs()
{
return saveLogs;
}
public String getTemperature() {
return Temperature;
}
public String getWeatherCondition() {
return WeatherCondition;
}
public String getWind() {
return Wind;
}
// --- end yrWeather plugin ---
public String getUserDescription()
{
return userDescription;
}
public void setUserDescription(String userDescription)
{
this.userDescription = userDescription;
}
public String getSaveLogs() {
return saveLogs;
}
public String getUserDescription() {
return userDescription;
}
}

View File

@@ -12,18 +12,6 @@ public class Room {
@SerializedName("sectionID")
private int sectionID;
@SerializedName("icon")
private String icon;
@SerializedName("defaultSensors")
private Sensor defaultSensors;
@SerializedName("defaultThermostat")
private int defaultThermostat;
@SerializedName("sortOrder")
private int sortOrder;
public int getId() {
return id;
}

View File

@@ -14,51 +14,12 @@ public class Scene {
@SerializedName("type")
private String type;
@SerializedName("properties")
private String properties;
@SerializedName("roomID")
private int roomID;
@SerializedName("iconID")
private int iconID;
@SerializedName("runConfig")
private String runConfig;
@SerializedName("autostart")
private boolean autostart;
@SerializedName("protectedByPIN")
private boolean protectedByPIN;
@SerializedName("killable")
private boolean killable;
@SerializedName("maxRunningInstances")
private int maxRunningInstances;
@SerializedName("runningInstances")
private int runningInstances;
@SerializedName("visible")
private boolean visible;
@SerializedName("isLua")
private boolean isLua;
@SerializedName("triggers")
private SceneTriggers triggers;
@SerializedName("liliStartCommand")
private String liliStartCommand;
@SerializedName("liliStopCommand")
private String liliStopCommand;
@SerializedName("sortOrder")
private int sortOrder;
public String getRoomName() {
return roomName;
}

View File

@@ -1,11 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class SceneProperties {
@SerializedName("id")
private String id;
@SerializedName("name")
private String name;
}

View File

@@ -1,14 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class SceneTriggers {
@SerializedName("properties")
private SceneProperties[] properties;
@SerializedName("globals")
private String[] globals;
@SerializedName("events")
private String[] events;
}

View File

@@ -1,14 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class Sensor {
@SerializedName("temperature")
private int temperature;
@SerializedName("humidity")
private int humidity;
@SerializedName("light")
private int light;
}

View File

@@ -104,7 +104,7 @@ public class HalHome implements Home {
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
if(!validHal)
return null;
return false;
Iterator<HalDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
HalDevice theDevice = devices.next();
@@ -113,12 +113,17 @@ public class HalHome implements Home {
return true;
}
@Override
public void refresh() {
// noop
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
boolean halFound = false;
String responseString = null;
String theUrl = anItem.getItem().getAsString();
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('/'));
@@ -160,7 +165,7 @@ public class HalHome implements Home {
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);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
}
}
@@ -170,7 +175,7 @@ public class HalHome implements Home {
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);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
return responseString;
}

View File

@@ -9,6 +9,7 @@ import net.whistlingfish.harmony.HarmonyClient;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.config.Device;
import net.whistlingfish.harmony.config.HarmonyConfig;
import com.bwssystems.HABridge.NamedIP;
public class HarmonyHandler {
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
@@ -16,8 +17,9 @@ public class HarmonyHandler {
private Boolean noopCalls;
private Boolean devMode;
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();
noopCalls = noopCallsSetting;
devMode = Boolean.TRUE;
@@ -27,6 +29,7 @@ public class HarmonyHandler {
else
devResponse = devResponseSetting;
harmonyClient = theClient;
myNameAndIP = aNameAndIP;
}
public List<Activity> getActivities() {
@@ -34,7 +37,16 @@ public class HarmonyHandler {
if(devMode)
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() {
@@ -42,7 +54,15 @@ public class HarmonyHandler {
if(devMode)
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() {
@@ -50,15 +70,29 @@ public class HarmonyHandler {
if(devMode)
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() {
log.debug("Harmony api current sctivity requested.");
if(devMode)
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) {
@@ -82,12 +116,14 @@ public class HarmonyHandler {
harmonyClient.startActivityByName(anActivity.getName());
} catch (IllegalArgumentException ei) {
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 {
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
return false;
}
return true;
@@ -113,11 +149,22 @@ public class HarmonyHandler {
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
} catch (IllegalArgumentException ei) {
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 {
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;
}
@@ -128,9 +175,19 @@ public class HarmonyHandler {
log.debug("Harmony api shutdown requested.");
if(devMode)
return;
harmonyClient.disconnect();
try {
harmonyClient.disconnect();
} catch(Exception e)
{
// noop
}
harmonyClient = null;
}
/**
* @return the myNameAndIP
*/
public NamedIP getMyNameAndIP() {
return myNameAndIP;
}
}

View File

@@ -27,7 +27,7 @@ import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.config.Device;
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 Boolean isDevMode;
private Boolean validHarmony;
@@ -43,91 +43,136 @@ public class HarmonyHome implements Home {
@Override
public void closeHome() {
if(!validHarmony)
if (!validHarmony)
return;
log.debug("Closing Home.");
if(closed) {
if (closed) {
log.debug("Home is already closed....");
return;
}
if(isDevMode || hubs == null)
if (isDevMode || hubs == null)
return;
Iterator<String> keys = hubs.keySet().iterator();
while(keys.hasNext()) {
while (keys.hasNext()) {
String key = keys.next();
hubs.get(key).getMyHarmony().shutdown();
}
hubs = null;
closed = true;
}
public HarmonyHandler getHarmonyHandler(String aName) {
if(!validHarmony)
if (!validHarmony)
return null;
HarmonyHandler aHandler = null;
if(aName == null || aName.equals("")) {
if (aName == null || aName.equals("")) {
aName = "default";
}
if(hubs.get(aName) == null) {
if (hubs.get(aName) == null) {
Set<String> keys = hubs.keySet();
if(!keys.isEmpty()) {
if (!keys.isEmpty()) {
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
}
else
} else
aHandler = null;
}
else
} else
aHandler = hubs.get(aName).getMyHarmony();
return aHandler;
}
public List<HarmonyActivity> getActivities() {
Iterator<String> keys = hubs.keySet().iterator();
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
if(!validHarmony)
if (!validHarmony)
return null;
while(keys.hasNext()) {
while (keys.hasNext()) {
String key = keys.next();
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();
anActivity.setActivity(activities.next());
anActivity.setActivity(theActivity);
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();
HarmonyActivity anActivity = new HarmonyActivity();
anActivity.setActivity(theActivity);
anActivity.setHub(key);
activityList.add(anActivity);
}
return activityList;
}
public List<HarmonyDevice> getDevices() {
Iterator<String> keys = hubs.keySet().iterator();
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
if(!validHarmony)
if (!validHarmony)
return null;
while(keys.hasNext()) {
while (keys.hasNext()) {
String key = keys.next();
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
while(devices.hasNext()) {
HarmonyDevice aDevice = new HarmonyDevice();
aDevice.setDevice(devices.next());
aDevice.setHub(key);
deviceList.add(aDevice);
if (devices == null) {
resetHub(hubs.get(key).getMyHarmony());
devices = hubs.get(key).getMyHarmony().getDevices().iterator();
if (devices == null) {
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;
@@ -135,36 +180,47 @@ public class HarmonyHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
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");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
if(anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
{
if (anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex])) {
RunActivity anActivity = null;
if(anItem.getItem().isJsonObject())
if (anItem.getItem().isJsonObject())
anActivity = aGsonHandler.fromJson(anItem.getItem(), RunActivity.class);
else
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString(), RunActivity.class);
if(anActivity.getHub() == null || anActivity.getHub().isEmpty())
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), RunActivity.class);
if (anActivity.getHub() == null || anActivity.getHub().isEmpty())
anActivity.setHub(device.getTargetDevice());
HarmonyHandler myHarmony = getHarmonyHandler(anActivity.getHub());
if (myHarmony == null) {
log.warn("Should not get here, no harmony hub available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} 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;
if(anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
if (anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
url = aGsonHandler.toJson(anItem.getItem());
} else
url = anItem.getItem().getAsString();
@@ -172,35 +228,50 @@ public class HarmonyHome implements Home {
if (url.substring(0, 1).equalsIgnoreCase("{")) {
url = "[" + url + "]";
}
url = BrightnessDecode.calculateReplaceIntensityValue(url, intensity, targetBri, targetBriInc, false);
ButtonPress[] deviceButtons = aGsonHandler.fromJson(url, ButtonPress[].class);
Integer theCount = 1;
for(int z = 0; z < deviceButtons.length; z++) {
if(deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
theCount = deviceButtons[z].getCount();
for(int y = 0; y < theCount; y++) {
if( y > 0 || z > 0) {
try {
Thread.sleep(aMultiUtil.getTheDelay());
} catch (InterruptedException e) {
// ignore
Integer theCount = 1;
for (int z = 0; z < deviceButtons.length; z++) {
if (deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
theCount = deviceButtons[z].getCount();
for (int y = 0; y < theCount; y++) {
if (y > 0 || z > 0) {
try {
Thread.sleep(aMultiUtil.getTheDelay());
} catch (InterruptedException e) {
// 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() + " 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
myHarmony.pressButton(deviceButtons[z]);
}
}
}
}
}
}
}
return responseString;
@@ -208,15 +279,14 @@ public class HarmonyHome implements Home {
@Override
public Home createHome(BridgeSettings bridgeSettings) {
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.") + (isDevMode ? " DevMode is set." : ""));
if(validHarmony || isDevMode) {
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.")
+ (isDevMode ? " DevMode is set." : ""));
if (validHarmony || isDevMode) {
hubs = new HashMap<String, HarmonyServer>();
aGsonHandler =
new GsonBuilder()
.create();
if(isDevMode) {
aGsonHandler = new GsonBuilder().create();
if (isDevMode) {
NamedIP devModeIp = new NamedIP();
devModeIp.setIp("10.10.10.10");
devModeIp.setName("devMode");
@@ -226,19 +296,21 @@ public class HarmonyHome implements Home {
thedevList.setDevices(theList);
bridgeSettings.getBridgeSettingsDescriptor().setHarmonyAddress(thedevList);
}
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices().iterator();
while(theList.hasNext() && validHarmony) {
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices()
.iterator();
while (theList.hasNext() && validHarmony) {
NamedIP aHub = theList.next();
boolean loopControl = true;
int retryCount = 0;
while(loopControl) {
while (loopControl) {
try {
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings.getBridgeSettingsDescriptor(), isDevMode, aHub));
loopControl = false;
hubs.put(aHub.getName(), HarmonyServer.setup(isDevMode, aHub));
loopControl = false;
} catch (Exception e) {
if(retryCount > 3) {
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
loopControl = false;
if (retryCount > 3) {
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: "
+ e.getMessage(), e);
loopControl = false;
} else {
try {
Thread.sleep(2000);
@@ -246,27 +318,52 @@ public class HarmonyHome implements Home {
// ignore
}
}
retryCount++;
}
}
}
if(hubs.isEmpty())
if (hubs.isEmpty())
validHarmony = false;
}
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
public Object getItems(String type) {
if(validHarmony) {
if(type.equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
if (validHarmony) {
if (type.equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
return getActivities();
if(type.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex]))
if (type.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex]))
return getDevices();
if(type.equalsIgnoreCase("current_activity"))
if (type.equalsIgnoreCase("current_activity"))
return getCurrentActivities();
}
return null;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -11,7 +11,6 @@ import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.NamedIP;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -50,11 +49,10 @@ public class HarmonyServer {
}
public static HarmonyServer setup(
BridgeSettingsDescriptor bridgeSettings,
Boolean harmonyDevMode,
NamedIP theHarmonyAddress
) throws Exception {
if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
if (harmonyDevMode) {
return new HarmonyServer(theHarmonyAddress);
}
Injector injector = null;
@@ -65,11 +63,11 @@ public class HarmonyServer {
if (!harmonyDevMode) {
injector.injectMembers(mainObject);
}
mainObject.execute(bridgeSettings, harmonyDevMode);
mainObject.execute(harmonyDevMode);
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"));
isDevMode = harmonyDevMode;
String modeString = "";
@@ -110,7 +108,7 @@ public class HarmonyServer {
});
harmonyClient.connect(myNameAndIP.getIp());
}
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse, myNameAndIP);
}
public HarmonyHandler getMyHarmony() {

View File

@@ -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;
}
}

View File

@@ -98,7 +98,7 @@ public class HassHome implements Home {
private Boolean addHassDevices(List<HassDevice> theDeviceList, List<State> theSourceList, String theKey) {
if(!validHass)
return null;
return false;
Iterator<State> devices = theSourceList.iterator();
while(devices.hasNext()) {
State theDevice = devices.next();
@@ -117,6 +117,11 @@ public class HassHome implements Home {
return true;
}
@Override
public void refresh() {
// noop
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
@@ -126,14 +131,14 @@ public class HassHome implements Home {
log.warn("Should not get here, no HomeAssistant clients configured");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no HomeAssistants configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
HassCommand hassCommand = null;
if(anItem.getItem().isJsonObject())
hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class);
else
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), HassCommand.class);
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class);
hassCommand.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(),
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
@@ -141,7 +146,7 @@ public class HassHome implements Home {
log.warn("Should not get here, no HomeAssistants available");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no HiomeAssistant clients available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
log.debug("calling HomeAssistant: " + hassCommand.getHassName() + " - "
+ hassCommand.getEntityId() + " - " + hassCommand.getState() + " - " + hassCommand.getBri());

View File

@@ -16,14 +16,19 @@ import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.google.gson.Gson;
public class HomeAssistant {
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
private NamedIP hassAddress;
private HTTPHandler anHttpHandler;
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
private NamedIP hassAddress;
private HTTPHandler anHttpHandler;
private HassAuth theAuthType;
private NameValue[] headers;
public HomeAssistant(NamedIP addressName) {
super();
anHttpHandler = HTTPHome.getHandler();
hassAddress = addressName;
hassAddress = addressName;
theAuthType = null;
headers = null;
isLegacyAuth();
}
public NamedIP getHassAddress() {
@@ -35,42 +40,30 @@ public class HomeAssistant {
}
public Boolean callCommand(HassCommand aCommand) {
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - "
+ aCommand.getEntityId() + " - " + aCommand.getState() + " - " + aCommand.getBri());
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - " + aCommand.getEntityId() + " - "
+ aCommand.getState() + " - " + aCommand.getBri());
String aUrl = null;
if(hassAddress.getSecure() != null && hassAddress.getSecure())
aUrl = "https";
else
aUrl = "http";
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
if(domain.equals("group"))
aUrl = hassAddress.getHttpPreamble() + "/api/services/";
if (domain.equals("group"))
aUrl = aUrl + "homeassistant";
else
aUrl = aUrl + domain;
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
NameValue[] headers = null;
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
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")) {
headers = getAuthHeader();
if (aCommand.getState().equalsIgnoreCase("on")) {
aUrl = aUrl + "/turn_on";
if(aCommand.getBri() != null)
if (aCommand.getBri() != null)
aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}";
else
aBody = aBody + "}";
}
else {
} else {
aUrl = aUrl + "/turn_off";
aBody = aBody + "}";
aBody = aBody + "}";
}
log.debug("Calling HomeAssistant with url: " + aUrl);
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
log.debug("call Command return is: <" + theData + ">");
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
log.debug("call Command return is: <" + theData + ">");
return true;
}
@@ -78,39 +71,62 @@ public class HomeAssistant {
List<State> theDeviceStates = null;
State[] theHassStates;
String theUrl = null;
String theData;
NameValue[] headers = null;
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
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())
String theData;
headers = getAuthHeader();
if (hassAddress.getSecure() != null && hassAddress.getSecure())
theUrl = "https";
else
theUrl = "http";
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if(theData != null) {
log.debug("GET Hass States - data: " + theData);
theHassStates = new Gson().fromJson(theData, State[].class);
if(theHassStates == null) {
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " as response is not parsable.");
}
else {
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
}
}
else
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if (theData != null) {
log.debug("GET Hass States - data: " + theData);
theHassStates = new Gson().fromJson(theData, State[].class);
if (theHassStates == null) {
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName()
+ " as response is not parsable.");
} else {
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
}
} else
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
return theDeviceStates;
}
protected void closeClient() {
anHttpHandler.closeHandler();
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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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.contains("OK"))
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].isSwitch() || hgModules[i].isDimmer())
deviceList.add(hgModules[i]);
}
}
} catch (Exception e) {
log.warn("Cannot get an devices for Homegenie {} Gson Parse Error.", homegenieIP.getName());
}
}
return deviceList;
}
public NamedIP getHomegenieIP() {
return homegenieIP;
}
public void setHomegenieIP(NamedIP homegenieIP) {
this.homegenieIP = homegenieIP;
}
protected void closeClient() {
}
}

View File

@@ -0,0 +1,104 @@
package com.bwssystems.HABridge.plugins.homegenie;
// import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Module {
@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");
}
private boolean isDeviceType(String theType) {
if(deviceType.equals(theType)) {
return true;
}
return false;
}
}

View File

@@ -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;
}
}

View File

@@ -49,20 +49,20 @@ public class HomeWizardHome implements Home {
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\"}}]";
+ lightId + "/state\"}}]";
} else {
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex])) {
log.debug("Executing HUE api request to change activity to HomeWizard smart plug: " + anItem.getItem().toString());
String jsonToPost = anItem.getItem().toString();
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\"}}]";
+ lightId + "/state\"}}]";
} else {
try {
homeWizzardHandler.execApply(jsonToPost);
@@ -70,7 +70,7 @@ public class HomeWizardHome implements Home {
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\"}}]";
+ "\",\"description\": \"Error posting request to HomeWizard smart plug\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
}
}
}
@@ -85,7 +85,7 @@ public class HomeWizardHome implements Home {
public List<HomeWizardSmartPlugDevice> getDevices() {
log.debug("consolidating devices for plug gateways");
log.debug("consolidating devices for HomeWizard plug gateways");
Iterator<String> keys = plugGateways.keySet().iterator();
ArrayList<HomeWizardSmartPlugDevice> deviceList = new ArrayList<>();
@@ -147,4 +147,9 @@ public class HomeWizardHome implements Home {
plugGateways = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -9,8 +9,6 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -19,9 +17,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.plugins.homewizard.json.Device;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import us.monoid.json.JSONException;
import us.monoid.json.JSONObject;
import com.google.gson.JsonParser;
/**
* Control HomeWizard devices over HomeWizard Cloud
@@ -48,7 +44,7 @@ public class HomeWizzardSmartPlugInfo {
super();
cloudAuth = "Basic " + new String(Base64.encodeBase64((gateway.getUsername() + ":" + DigestUtils.sha1Hex(gateway.getPassword())).getBytes()));
cloudAuth = "Basic " + gateway.getUserPass64();
cloudPlugName = name;
gson = new Gson();
}
@@ -75,10 +71,12 @@ public class HomeWizzardSmartPlugInfo {
br.close();
// Get session id from result JSON
JSONObject json = new JSONObject(buffer.toString());
cloudSessionId = json.get("session").toString();
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(buffer.toString()).getAsJsonObject();
cloudSessionId = json.get("session").getAsString();
}
catch(IOException | JSONException e)
catch(Exception e)
{
log.warn("Error while login to cloud service ", e);
return false;
@@ -191,8 +189,9 @@ public class HomeWizzardSmartPlugInfo {
try {
String result = requestJson(EMPTY_STRING);
JSONObject resultJson = new JSONObject(result);
cloudPlugId = resultJson.getString("id");
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);
@@ -203,7 +202,7 @@ public class HomeWizzardSmartPlugInfo {
homewizardDevices.add(mapDeviceToHomeWizardSmartPlugDevice(device));
}
}
catch(JSONException e) {
catch(Exception e) {
log.warn("Error while get devices from cloud service ", e);
}
@@ -211,12 +210,13 @@ public class HomeWizzardSmartPlugInfo {
return homewizardDevices;
}
public void execApply(String jsonToPost) throws JSONException, IOException {
public void execApply(String jsonToPost) throws Exception {
// Extract
JSONObject resultJson = new JSONObject(jsonToPost);
String deviceId = resultJson.getString("deviceid");
String action = resultJson.getString("action");
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)) {

View File

@@ -17,31 +17,53 @@ import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
private String callType;
public HTTPHandler() {
super();
callType = null;
}
public HTTPHandler(String type) {
super();
callType = type;
}
// This function executes the url from the device repository against the
// target as http or https as defined
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;
String theContent = null;
URI theURI = null;
boolean usingSSL = false;
ContentType parsedContentType = 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()) {
parsedContentType = ContentType.parse(contentType);
if (body != null && body.length() > 0)
requestBody = new StringEntity(body, parsedContentType);
}
if (url.startsWith("https:")) {
usingSSL = true;
}
try {
theURI = new URI(url);
} catch (URISyntaxException e1) {
@@ -78,7 +100,11 @@ public class HTTPHandler {
CloseableHttpResponse response = null;
for (int retryCount = 0; retryCount < 2; retryCount++) {
try {
response = HttpClientPool.getClient().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: "
+ response.getStatusLine().getStatusCode());
if (response != null && response.getEntity() != null) {
@@ -94,32 +120,44 @@ public class HTTPHandler {
// ignore
// content
} catch (Exception e) {
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
+ e.getMessage(), e);
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 (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());
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) {
log.warn("HTTP response code was 504, retrying...");
log.debug("The 504 error content is <<<" + theContent + ">>>");
theContent = null;
} else
retryCount = 2;
theContent = null;
}
} 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());
} catch (IOException e) {
log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage(), e);
retryCount = 2;
}
if(retryCount < 2) {
if (retryCount < 2) {
theContent = null;
try {
Thread.sleep(1000);
@@ -130,6 +168,40 @@ public class HTTPHandler {
}
return theContent;
}
public NameValue[] addBasicAuthHeader(NameValue[] theHeaders, NamedIP theTarget) {
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 void setCallType(String callType) {
this.callType = callType;
}
public void closeHandler() {
}
}

View File

@@ -16,11 +16,14 @@ 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.fibaro.FibaroTestData;
import com.bwssystems.HABridge.plugins.vera.VeraTestData;
import com.google.gson.Gson;
public class HTTPHome implements Home {
private static final Logger log = LoggerFactory.getLogger(HTTPHome.class);
private static HTTPHandler anHttpHandler = null;
private Boolean isDevMode;
private boolean closed;
public HTTPHome(BridgeSettings bridgeSettings) {
@@ -41,7 +44,7 @@ public class HTTPHome implements Home {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
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://"))) {
//Backwards Compatibility Items
if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
@@ -78,18 +81,21 @@ public class HTTPHome implements Home {
aBody = TimeDecode.replaceTimeValue(aBody);
}
// make call
if (anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody,
new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class)) == null) {
String httpReply = anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody, new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class));
if (httpReply == null) {
log.warn("Error on calling url 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);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
if(isDevMode)
log.info("Dev Mode response dump <<<" + httpReply +">>>");
} else {
log.warn("HTTP Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
}
return responseString;
@@ -97,9 +103,21 @@ public class HTTPHome implements Home {
@Override
public Home createHome(BridgeSettings bridgeSettings) {
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
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();
log.info("Http Home created.");
return this;
}
@@ -121,5 +139,9 @@ public class HTTPHome implements Home {
anHttpHandler = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -4,10 +4,22 @@ import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,9 +43,7 @@ public final class HttpClientPool {
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Build the client.
threadSafeClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
threadSafeClient = HttpClients.custom().setConnectionManager(cm).build();
// Start up an eviction thread.
monitor = new IdleConnectionMonitorThread(cm);
// Don't stop quitting.
@@ -47,11 +57,67 @@ public final class HttpClientPool {
}
// Single-element enum to implement Singleton.
private static enum SingletonSSL {
// Just one of me so constructor will be called once.
SSLClient;
// The thread-safe client.
private CloseableHttpClient threadSafeClient;
// The pool monitor.
private IdleConnectionMonitorThread monitor = null;
private TrustStrategy acceptingTrustStrategy = null;
private SSLContext sslContext = null;
private SSLConnectionSocketFactory sslsf = null;
private Registry<ConnectionSocketFactory> socketFactoryRegistry = null;
private NoopHostnameVerifier hostnameVerifier = null;
// The constructor creates it - thus late
private SingletonSSL() {
try {
acceptingTrustStrategy = (cert, authType) -> true;
hostnameVerifier = new NoopHostnameVerifier();
sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
HttpClientPool.log.info("Instantiated SSL components.");
final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", new PlainConnectionSocketFactory())
.register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Build the client.
threadSafeClient = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(cm).build();
// Start up an eviction thread.
monitor = new IdleConnectionMonitorThread(cm);
// Don't stop quitting.
monitor.setDaemon(true);
monitor.start();
} catch (Exception e) {
HttpClientPool.log.warn("SingletonSSL failed on SSL init");
threadSafeClient = null;
}
}
public CloseableHttpClient get() {
return threadSafeClient;
}
}
public static CloseableHttpClient getClient() {
// The thread safe client is held by the singleton.
return Singleton.Client.get();
}
public static CloseableHttpClient getSSLClient() {
// The thread safe client is held by the singleton.
return SingletonSSL.SSLClient.get();
}
// Watches for stale connections and evicts them.
private static class IdleConnectionMonitorThread extends Thread {
// The manager to watch.
@@ -123,6 +189,7 @@ public final class HttpClientPool {
public static void shutdown() throws InterruptedException, IOException {
// Shutdown the monitor.
Singleton.Client.monitor.shutdown();
SingletonSSL.SSLClient.monitor.shutdown();
}
}

View File

@@ -0,0 +1,65 @@
package com.bwssystems.HABridge.plugins.http;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
public class HttpTestHandler extends HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HttpTestHandler.class);
private List<NameValue> theData;
public void setTheData(String compareValue, String testData) {
if( this.theData == null )
this.theData = new ArrayList<NameValue>();
NameValue aValueSet = new NameValue();
aValueSet.setName(compareValue);
aValueSet.setValue(testData);
this.theData.add(aValueSet);
}
public void updateTheData(String compareValue, String testData) {
if( this.theData == null ) {
this.theData = new ArrayList<NameValue>();
NameValue aValueSet = new NameValue();
aValueSet.setName(compareValue);
aValueSet.setValue(testData);
this.theData.add(aValueSet);
}
else {
for(NameValue aTest:this.theData) {
if(aTest.getName().equals(compareValue))
aTest.setValue(testData);
}
}
}
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
log.info("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.info("header index " + i + " name: <<<" + headers[i].getName() + ">>>, value: <<<" + headers[i].getValue() + ">>>");
String responseData = null;
for(NameValue aTest:theData) {
if(aTest.getName() == null)
responseData = aTest.getValue();
else {
if(url.contains(aTest.getName()))
responseData = aTest.getValue();
else if(aTest.getName() == null || aTest.getName().isEmpty())
responseData = aTest.getValue();
}
if(responseData != null)
break;
}
if(responseData == null)
responseData = "No data was set for HttpTestHandler for your request url.";
return responseData;
}
}

View File

@@ -99,7 +99,7 @@ public class HueHome implements Home {
if(anItem.getItem().isJsonObject())
deviceId = aGsonHandler.fromJson(anItem.getItem(), HueDeviceIdentifier.class);
else
deviceId = aGsonHandler.fromJson(anItem.getItem().getAsString(), HueDeviceIdentifier.class);
deviceId = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HueDeviceIdentifier.class);
if(deviceId.getHueName() == null || deviceId.getHueName().isEmpty())
deviceId.setHueName(device.getTargetDevice());
@@ -153,4 +153,9 @@ public class HueHome implements Home {
hues = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -159,10 +159,10 @@ public class HueInfo {
log.warn("Error on calling Hue passthru to change device state: " + deviceId.getHueName());
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Error on calling HUE to change device state\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else if (responseString.contains("[{\"error\":")) {
if(responseString.contains("unauthorized user")) {
}
// if(responseString.contains("unauthorized user")) {
// }
log.warn("Error occurred when calling Hue Passthru: " + responseString);
}
} else {

View File

@@ -5,6 +5,7 @@ import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -20,6 +21,7 @@ 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.MultiCommandUtil;
import com.github.besherman.lifx.LFXClient;
import com.github.besherman.lifx.LFXGroup;
@@ -38,6 +40,7 @@ public class LifxHome implements Home {
private LFXClient client;
private Boolean validLifx;
private Gson aGsonHandler;
private InetAddress configuredAddress;
private boolean closed;
public LifxHome(BridgeSettings bridgeSettings) {
@@ -54,47 +57,17 @@ public class LifxHome implements Home {
validLifx = bridgeSettings.getBridgeSettingsDescriptor().isValidLifx();
log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
if(validLifx) {
try {
log.info("Open Lifx client....");
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
InetAddress bcastInetAddr = null;
if (networkInterface != null) {
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
InetAddress addr = ifaceAddr.getAddress();
if (addr instanceof Inet4Address) {
bcastInetAddr = ifaceAddr.getBroadcast();
break;
}
}
}
if(bcastInetAddr != null) {
lifxMap = new HashMap<String, LifxDevice>();
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
client = new LFXClient(bcastInetAddr.getHostAddress());
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
client.open(false);
aGsonHandler =
new GsonBuilder()
.create();
} else {
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
client = null;
validLifx = false;
return this;
}
} catch (IOException e) {
log.warn("Could not open LIFX, with IO Exception", e);
client = null;
validLifx = false;
return this;
} catch (InterruptedException e) {
log.warn("Could not open LIFX, with Interruprted Exception", e);
client = null;
aGsonHandler =
new GsonBuilder()
.create();
try {
configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
} catch (UnknownHostException e) {
log.warn("Could not get Inet Address for Lifx broadcast.");
validLifx = false;
return this;
}
broadcastDiscover();
}
return this;
}
@@ -116,7 +89,7 @@ public class LifxHome implements Home {
@Override
public Object getItems(String type) {
log.debug("consolidating devices for lifx");
if(!validLifx)
if(!validLifx || lifxMap == null)
return null;
LifxEntry theResponse = null;
Iterator<String> keys = lifxMap.keySet().iterator();
@@ -171,20 +144,20 @@ public class LifxHome implements Home {
log.warn("Should not get here, no LifxDevice clients configured");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
LifxEntry lifxCommand = null;
if(anItem.getItem().isJsonObject())
lifxCommand = aGsonHandler.fromJson(anItem.getItem(), LifxEntry.class);
else
lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), LifxEntry.class);
lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), LifxEntry.class);
LifxDevice theDevice = getLifxDevice(lifxCommand.getName());
if (theDevice == null) {
log.warn("Should not get here, no LifxDevices available");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no Lifx clients available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
log.debug("calling LifxDevice: " + lifxCommand.getName());
if(theDevice.getType().equals(LifxDevice.LIGHT_TYPE)) {
@@ -200,6 +173,10 @@ public class LifxHome implements Home {
theValue = (float)0.99;
theLight.setBrightness(theValue);
}
if(colorData != null) {
int rgbVal = ColorDecode.getIntRGB(colorData, intensity);
theLight.setColor(rgbVal);
}
} else if (theDevice.getType().equals(LifxDevice.GROUP_TYPE)) {
LFXGroup theGroup = (LFXGroup)theDevice.getLifxObject();
if(body.contains("true"))
@@ -221,7 +198,8 @@ public class LifxHome implements Home {
log.debug("Home is already closed....");
return;
}
client.close();
if(client != null)
client.close();
closed = true;
}
private static class MyLightListener implements LFXLightCollectionListener {
@@ -266,4 +244,47 @@ public class LifxHome implements Home {
}
}
private void broadcastDiscover() {
try {
log.info("Open Lifx client....");
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
InetAddress bcastInetAddr = null;
if (networkInterface != null) {
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
InetAddress addr = ifaceAddr.getAddress();
if (addr instanceof Inet4Address) {
bcastInetAddr = ifaceAddr.getBroadcast();
break;
}
}
}
if(bcastInetAddr != null) {
lifxMap = new HashMap<String, LifxDevice>();
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
client = new LFXClient(bcastInetAddr.getHostAddress());
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
client.open(false);
} else {
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
client = null;
return;
}
} catch (IOException e) {
log.warn("Could not open LIFX, with IO Exception", e);
client = null;
return;
} catch (InterruptedException e) {
log.warn("Could not open LIFX, with Interruprted Exception", e);
client = null;
return;
}
}
@Override
public void refresh() {
if(client == null)
broadcastDiscover();
}
}

View File

@@ -0,0 +1,8 @@
package com.bwssystems.HABridge.plugins.moziot;
public class Actions {
}

View File

@@ -0,0 +1,8 @@
package com.bwssystems.HABridge.plugins.moziot;
public class Events {
}

View File

@@ -0,0 +1,21 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class JWT {
@SerializedName("jwt")
@Expose
private String jwt;
public String getJwt() {
return jwt;
}
public void setJwt(String jwt) {
this.jwt = jwt;
}
}

View File

@@ -0,0 +1,88 @@
package com.bwssystems.HABridge.plugins.moziot;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Level {
@SerializedName("title")
@Expose
private String title;
@SerializedName("type")
@Expose
private String type;
@SerializedName("@type")
@Expose
private String attype;
@SerializedName("unit")
@Expose
private String unit;
@SerializedName("minimum")
@Expose
private Integer minimum;
@SerializedName("maximum")
@Expose
private Integer maximum;
@SerializedName("links")
@Expose
private List<Link> links = null;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAttype() {
return attype;
}
public void setAttype(String attype) {
this.attype = attype;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public Integer getMinimum() {
return minimum;
}
public void setMinimum(Integer minimum) {
this.minimum = minimum;
}
public Integer getMaximum() {
return maximum;
}
public void setMaximum(Integer maximum) {
this.maximum = maximum;
}
public List<Link> getLinks() {
return links;
}
public void setLinks(List<Link> links) {
this.links = links;
}
}

View File

@@ -0,0 +1,43 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Link {
@SerializedName("rel")
@Expose
private String rel;
@SerializedName("href")
@Expose
private String href;
@SerializedName("mediaType")
@Expose
private String mediaType;
public String getRel() {
return rel;
}
public void setRel(String rel) {
this.rel = rel;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getMediaType() {
return mediaType;
}
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
}

View File

@@ -0,0 +1,26 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MozIotCommand {
@SerializedName("url")
@Expose
private String url;
@SerializedName("command")
@Expose
private MozIotCommandDetail command;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public MozIotCommandDetail getCommand() {
return command;
}
public void setCommand(MozIotCommandDetail command) {
this.command = command;
}
}

View File

@@ -0,0 +1,54 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MozIotCommandDetail {
@SerializedName("on")
@Expose
private boolean on;
@SerializedName("level")
@Expose
private String level;
@SerializedName("color")
@Expose
private String color;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
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 getBody() {
String theBody = "";
if(level != null && level != "") {
theBody = "{\"level\":" + level + "}";
}
else if(color != null && color != "") {
theBody = "{\"color\":\"" + color + "\"}";
} else {
theBody = "{\"on\":" + on + "}";
}
return theBody;
}
}

View File

@@ -0,0 +1,29 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MozIotDevice {
@SerializedName("gatewayName")
@Expose
private String gatewayName;
@SerializedName("deviceDetail")
@Expose
private MozillaThing deviceDetail;
public String getGatewayName() {
return gatewayName;
}
public void setGatewayName(String gatewayName) {
this.gatewayName = gatewayName;
}
public MozillaThing getDeviceDetail() {
return deviceDetail;
}
public void setDeviceDetail(MozillaThing deviceDetail) {
this.deviceDetail = deviceDetail;
}
}

View File

@@ -0,0 +1,194 @@
package com.bwssystems.HABridge.plugins.moziot;
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 MozIotHome implements Home {
private static final Logger log = LoggerFactory.getLogger(MozIotHome.class);
private Map<String, MozIotInstance> moziotMap;
private Boolean validMoziot;
private HTTPHandler httpClient;
private boolean closed;
public MozIotHome(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);
MozIotCommand theCommand = null;
try {
theUrl = theUrl.replaceAll("^\"|\"$", "");
theCommand = new Gson().fromJson(anUrl, MozIotCommand.class);
} catch (Exception e) {
log.warn("Cannot parse command to Mozilla IOT <<<" + 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("/things/") + 8);
String devicePortion = intermediate.substring(0, intermediate.indexOf('/'));
String theUrlCommand = intermediate.substring(intermediate.indexOf('/') + 1);
MozIotInstance theHandler = moziotMap.get(device.getTargetDevice());
if (theHandler != null) {
try {
boolean success = theHandler.callCommand(devicePortion, theUrlCommand, theCommand.getCommand(), httpClient);
if (!success) {
log.warn("Comand had error to Mozilla IOT");
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 Mozilla IOT", 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("Mozilla IOT 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(
"Mozilla IOT 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 (!validMoziot)
return null;
log.debug("consolidating devices for Mozilla IOT");
List<MozillaThing> theResponse = null;
Iterator<String> keys = moziotMap.keySet().iterator();
List<MozIotDevice> deviceList = new ArrayList<MozIotDevice>();
while (keys.hasNext()) {
String key = keys.next();
theResponse = moziotMap.get(key).getDevices(httpClient);
if (theResponse != null)
addMozIotDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get devices for Mozilla IOT with name: " + key + ", skipping this Mozilla IOT.");
continue;
}
}
return deviceList;
}
private Boolean addMozIotDevices(List<MozIotDevice> theDeviceList, List<MozillaThing> theSourceList,
String theKey) {
Iterator<MozillaThing> things = theSourceList.iterator();
while (things.hasNext()) {
MozillaThing theThing = things.next();
MozIotDevice theDevice = new MozIotDevice();
theDevice.setDeviceDetail(theThing);
theDevice.setGatewayName(theKey);
theDeviceList.add(theDevice);
}
return true;
}
@Override
public Home createHome(BridgeSettings bridgeSettings) {
moziotMap = null;
validMoziot = bridgeSettings.getBridgeSettingsDescriptor().isValidMozIot();
log.info("Mozilla IOT Home created." + (validMoziot ? "" : " No Mozilla IOTs configured."));
if (validMoziot) {
moziotMap = new HashMap<String, MozIotInstance>();
httpClient = HTTPHome.getHandler();
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getMoziotaddress().getDevices()
.iterator();
while (theList.hasNext() && validMoziot) {
NamedIP aMoziot = theList.next();
try {
moziotMap.put(aMoziot.getName(), new MozIotInstance(aMoziot, httpClient));
} catch (Exception e) {
log.error("Cannot get Mozilla IOT (" + aMoziot.getName() + ") setup, Exiting with message: "
+ e.getMessage(), e);
validMoziot = false;
}
}
}
return this;
}
@Override
public void closeHome() {
log.debug("Closing Home.");
if (!closed && validMoziot) {
log.debug("Home is already closed....");
return;
}
if (httpClient != null)
httpClient.closeHandler();
moziotMap = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,148 @@
package com.bwssystems.HABridge.plugins.moziot;
import java.util.ArrayList;
import java.util.List;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.NameValue;
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.apache.http.client.methods.HttpPost;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MozIotInstance {
private static final Logger log = LoggerFactory.getLogger(MozIotInstance.class);
private JWT moziotToken;
private NamedIP mozIotIP;
private NameValue[] headers;
public MozIotInstance(NamedIP theNamedIp, HTTPHandler httpClient) {
mozIotIP = theNamedIp;
headers = null;
gatewayLogin(httpClient);
}
public Boolean callCommand(String deviceId, String aCommand, MozIotCommandDetail commandData, HTTPHandler httpClient) {
log.debug("calling Mozilla IOT: {}:{}{}{}", mozIotIP.getIp(), mozIotIP.getPort(), aCommand, commandData.getBody());
String aUrl = null;
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
aUrl = "https://";
else
aUrl = "http://";
headers = getAuthHeader();
aUrl = aUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/things/" + deviceId + "/" + aCommand;
String theData = httpClient.doHttpRequest(aUrl, HttpPut.METHOD_NAME, "application/json", commandData.getBody(), headers);
log.debug("call Command return is: <<<{}>>>", theData);
if (theData.contains("error") || theData.contains("ERROR") || theData.contains("Error"))
return false;
return true;
}
public List<MozillaThing> getDevices(HTTPHandler httpClient) {
log.debug("calling Mozilla IOT: " + mozIotIP.getIp() + ":" + mozIotIP.getPort());
List<MozillaThing> deviceList = null;
MozillaThing[] theThings;
String theUrl = null;
String theData;
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
theUrl = "https://";
else
theUrl = "http://";
headers = getAuthHeader();
theUrl = theUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/things";
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if (theData != null) {
log.debug("GET Mozilla IOT Devices - data: " + theData);
try {
theThings = new Gson().fromJson(theData, MozillaThing[].class);
if (theThings != null && theThings.length > 0) {
deviceList = new ArrayList<MozillaThing>();
for (int i = 0; i < theThings.length; i++) {
deviceList.add(theThings[i]);
}
}
} catch (Exception e) {
log.warn("Cannot get an devices for Mozilla IOT {} Gson Parse Error.", mozIotIP.getName());
}
}
return deviceList;
}
private NameValue[] getAuthHeader() {
if (headers == null) {
headers = new NameValue[3];
headers[0] = new NameValue();
headers[0].setName("Authorization");
headers[0].setValue("Bearer " + moziotToken.getJwt());
headers[1] = new NameValue();
headers[1].setName("Content-Type");
headers[1].setValue("application/json");
headers[2] = new NameValue();
headers[2].setName("Accept");
headers[2].setValue("application/json");
}
return headers;
}
private void gatewayLogin(HTTPHandler httpClient) {
String aUrl = null;
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
aUrl = "https://";
else
aUrl = "http://";
headers = new NameValue[2];
headers[0] = new NameValue();
headers[0].setName("Content-Type");
headers[0].setValue("application/json");
headers[1] = new NameValue();
headers[1].setName("Accept");
headers[1].setValue("application/json");
aUrl = aUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/login";
log.debug("gateway login URL: {}", aUrl);
String commandData = "{\"email\": \"" + mozIotIP.getUsername() + "\", \"password\":\"" + mozIotIP.getPassword()
+ "\"}";
log.debug("The login body: {}", commandData);
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", commandData, headers);
if (theData != null) {
log.debug("GET Mozilla login - data: {}", theData);
try {
moziotToken = new Gson().fromJson(theData, JWT.class);
} catch (Exception e) {
log.warn("Cannot get login for Mozilla IOT {} Gson Parse Error.", mozIotIP.getName());
}
} else {
log.warn("Could not login {} error: <<<{}>>>", mozIotIP.getName(), theData);
}
headers = null;
}
public NamedIP getMozIotIP() {
return mozIotIP;
}
public void setMozIotIP(NamedIP mozIotIP) {
this.mozIotIP = mozIotIP;
}
protected void closeClient() {
}
public JWT getMoziotToken() {
return moziotToken;
}
public void setMoziotToken(JWT moziotToken) {
this.moziotToken = moziotToken;
}
}

View File

@@ -0,0 +1,154 @@
package com.bwssystems.HABridge.plugins.moziot;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MozillaThing {
@SerializedName("name")
@Expose
private String name;
@SerializedName("type")
@Expose
private String type;
@SerializedName("@context")
@Expose
private String atcontext;
@SerializedName("@type")
@Expose
private List<String> attype = null;
@SerializedName("description")
@Expose
private String description;
@SerializedName("href")
@Expose
private String href;
@SerializedName("properties")
@Expose
private Properties properties;
@SerializedName("actions")
@Expose
private Actions actions;
@SerializedName("events")
@Expose
private Events events;
@SerializedName("links")
@Expose
private List<Link> links = null;
@SerializedName("layoutIndex")
@Expose
private Integer layoutIndex;
@SerializedName("selectedCapability")
@Expose
private String selectedCapability;
@SerializedName("iconHref")
@Expose
private Object iconHref;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAtcontext() {
return atcontext;
}
public void setAtcontext(String atcontext) {
this.atcontext = atcontext;
}
public List<String> getAttype() {
return attype;
}
public void setAttype(List<String> attype) {
this.attype = attype;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public Actions getActions() {
return actions;
}
public void setActions(Actions actions) {
this.actions = actions;
}
public Events getEvents() {
return events;
}
public void setEvents(Events events) {
this.events = events;
}
public List<Link> getLinks() {
return links;
}
public void setLinks(List<Link> links) {
this.links = links;
}
public Integer getLayoutIndex() {
return layoutIndex;
}
public void setLayoutIndex(Integer layoutIndex) {
this.layoutIndex = layoutIndex;
}
public String getSelectedCapability() {
return selectedCapability;
}
public void setSelectedCapability(String selectedCapability) {
this.selectedCapability = selectedCapability;
}
public Object getIconHref() {
return iconHref;
}
public void setIconHref(Object iconHref) {
this.iconHref = iconHref;
}
}

View File

@@ -0,0 +1,55 @@
package com.bwssystems.HABridge.plugins.moziot;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class On {
@SerializedName("title")
@Expose
private String title;
@SerializedName("type")
@Expose
private String type;
@SerializedName("attype")
@Expose
private String attype;
@SerializedName("links")
@Expose
private List<Link> links = null;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAttype() {
return attype;
}
public void setAttype(String attype) {
this.attype = attype;
}
public List<Link> getLinks() {
return links;
}
public void setLinks(List<Link> links) {
this.links = links;
}
}

View File

@@ -0,0 +1,32 @@
package com.bwssystems.HABridge.plugins.moziot;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Properties {
@SerializedName("on")
@Expose
private On on;
@SerializedName("level")
@Expose
private Level level;
public On getOn() {
return on;
}
public void setOn(On on) {
this.on = on;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
}

View File

@@ -15,6 +15,7 @@ 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;
@@ -95,11 +96,14 @@ public class MQTTHome implements Home {
mqttObject = aGsonHandler.toJson(anItem.getItem());
}
else
mqttObject =anItem.getItem().getAsString();
mqttObject = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
mqttObject = BrightnessDecode.calculateReplaceIntensityValue(mqttObject,
intensity, targetBri, targetBriInc, false);
mqttObject = DeviceDataDecode.replaceDeviceData(mqttObject, device);
mqttObject = TimeDecode.replaceTimeValue(mqttObject);
if (colorData != null) {
mqttObject = ColorDecode.replaceColorData(mqttObject, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
if (mqttObject.substring(0, 1).equalsIgnoreCase("{"))
mqttObject = "[" + mqttObject + "]";
MQTTMessage[] mqttMessages = aGsonHandler.fromJson(mqttObject, MQTTMessage[].class);
@@ -124,7 +128,7 @@ public class MQTTHome implements Home {
log.warn("Should not get here, no mqtt brokers configured");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no mqtt brokers configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
}
return responseString;
@@ -146,4 +150,9 @@ public class MQTTHome implements Home {
}
return this;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,19 @@
package com.bwssystems.HABridge.plugins.openhab;
public class OpenHABCommand {
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;
}
}

View File

@@ -0,0 +1,27 @@
package com.bwssystems.HABridge.plugins.openhab;
public class OpenHABDevice {
private String address;
private String name;
private OpenHABItem 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 OpenHABItem getItem() {
return item;
}
public void setItem(OpenHABItem item) {
this.item = item;
}
}

View File

@@ -0,0 +1,211 @@
package com.bwssystems.HABridge.plugins.openhab;
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 OpenHABHome implements Home {
private static final Logger log = LoggerFactory.getLogger(OpenHABHome.class);
private Map<String, OpenHABInstance> openhabMap;
private Boolean validOpenhab;
private HTTPHandler httpClient;
private boolean closed;
public OpenHABHome(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();
String responseString = null;
if(theUrl != null && !theUrl.isEmpty()) {
OpenHABCommand theCommand = null;
try {
if(anItem.getItem().isJsonObject())
theCommand = new Gson().fromJson(anItem.getItem(), OpenHABCommand.class);
else
theCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), OpenHABCommand.class);
} catch(Exception e) {
log.warn("Cannot parse command to OpenHAB <<<" + 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;
OpenHABInstance 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 {
boolean success = theHandler.callCommand(anUrl, aCommand, httpClient);
if(!success) {
log.warn("Comand had error to OpenHAB");
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 OpenHAB", 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("OpenHAB 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("OpenHAB 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(!validOpenhab)
return null;
log.debug("consolidating devices for OpenHAB");
List<OpenHABDevice> theResponse = null;
Iterator<String> keys = openhabMap.keySet().iterator();
List<OpenHABDevice> deviceList = new ArrayList<OpenHABDevice>();
while(keys.hasNext()) {
String key = keys.next();
theResponse = openhabMap.get(key).getDevices(httpClient);
if(theResponse != null)
addOpenhabDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get devices for OpenHAB with name: " + key + ", skipping this OpenHAB.");
continue;
}
}
return deviceList;
}
private Boolean addOpenhabDevices(List<OpenHABDevice> theDeviceList, List<OpenHABDevice> theSourceList, String theKey) {
Iterator<OpenHABDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
OpenHABDevice theDevice = devices.next();
theDeviceList.add(theDevice);
}
return true;
}
@Override
public Home createHome(BridgeSettings bridgeSettings) {
openhabMap = null;
validOpenhab = bridgeSettings.getBridgeSettingsDescriptor().isValidOpenhab();
log.info("OpenHAB Home created." + (validOpenhab ? "" : " No OpenHABs configured."));
if(validOpenhab) {
openhabMap = new HashMap<String,OpenHABInstance>();
httpClient = HTTPHome.getHandler();
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getOpenhabaddress().getDevices().iterator();
while(theList.hasNext() && validOpenhab) {
NamedIP anOpenhab = theList.next();
try {
openhabMap.put(anOpenhab.getName(), new OpenHABInstance(anOpenhab));
} catch (Exception e) {
log.error("Cannot get OpenHAB (" + anOpenhab.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
validOpenhab = false;
}
}
}
return this;
}
private OpenHABInstance findHandlerByAddress(String hostAddress) {
OpenHABInstance aHandler = null;
boolean found = false;
Iterator<String> keys = openhabMap.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
aHandler = openhabMap.get(key);
if(aHandler != null && aHandler.getOpenHABAddress().getIp().equals(hostAddress)) {
found = true;
break;
}
}
if(!found)
aHandler = null;
return aHandler;
}
@Override
public void closeHome() {
log.debug("Closing Home.");
if(!closed && validOpenhab) {
log.debug("Home is already closed....");
return;
}
if(httpClient != null)
httpClient.closeHandler();
openhabMap = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,95 @@
package com.bwssystems.HABridge.plugins.openhab;
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 OpenHABInstance {
private static final Logger log = LoggerFactory.getLogger(OpenHABInstance.class);
private NamedIP theOpenHAB;
public OpenHABInstance(NamedIP openhabLocation) {
super();
theOpenHAB = openhabLocation;
}
public NamedIP getOpenHABAddress() {
return theOpenHAB;
}
public void setOpenHABAddress(NamedIP openhabAddress) {
this.theOpenHAB = openhabAddress;
}
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
log.debug("calling OpenHAB: " + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + aCommand);
String aUrl = null;
if(theOpenHAB.getSecure() != null && theOpenHAB.getSecure())
aUrl = "https://";
else
aUrl = "http://";
aUrl = aUrl + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + "/" + aCommand;
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", commandData, httpClient.addBasicAuthHeader(null, theOpenHAB));
log.debug("call Command return is: <" + theData + ">");
if(theData.contains("error") || theData.contains("ERROR") || theData.contains("Error"))
return false;
return true;
}
public List<OpenHABDevice> getDevices(HTTPHandler httpClient) {
List<OpenHABDevice> deviceList = null;
OpenHABItem[] theOpenhabStates;
String theUrl = null;
String theData;
NameValue[] headers = null;
if(theOpenHAB.getSecure() != null && theOpenHAB.getSecure())
theUrl = "https://";
else
theUrl = "http://";
if(theOpenHAB.getUsername() != null && !theOpenHAB.getUsername().isEmpty() && theOpenHAB.getPassword() != null && !theOpenHAB.getPassword().isEmpty()) {
theUrl = theUrl + theOpenHAB.getUsername() + ":" + theOpenHAB.getPassword() + "@";
}
theUrl = theUrl + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + "/rest/items?recursive=false";
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if(theData != null) {
log.debug("GET OpenHAB States - data: " + theData);
try {
theOpenhabStates = new Gson().fromJson(theData, OpenHABItem[].class);
if(theOpenhabStates == null) {
log.warn("Cannot get any devices for OpenHAB " + theOpenHAB.getName() + " as response is not parsable.");
}
else {
deviceList = new ArrayList<OpenHABDevice>();
for (int i = 0; i < theOpenhabStates.length; i++) {
OpenHABDevice aNewOpenHABDeviceDevice = new OpenHABDevice();
aNewOpenHABDeviceDevice.setItem(theOpenhabStates[i]);
aNewOpenHABDeviceDevice.setAddress(theOpenHAB.getIp() + ":" + theOpenHAB.getPort());
aNewOpenHABDeviceDevice.setName(theOpenHAB.getName());
deviceList.add(aNewOpenHABDeviceDevice);
}
}
} catch (Exception e) {
log.warn("Cannot get an devices for OpenHAB " + theOpenHAB.getName() + " Gson Parse Error.");
}
}
else
log.warn("Cannot get an devices for OpenHAB " + theOpenHAB.getName() + " http call failed.");
return deviceList;
}
protected void closeClient() {
}
}

View File

@@ -0,0 +1,110 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class OpenHABItem {
@SerializedName("link")
@Expose
private String link;
@SerializedName("state")
@Expose
private String state;
@SerializedName("type")
@Expose
private String type;
@SerializedName("name")
@Expose
private String name;
@SerializedName("label")
@Expose
private String label;
@SerializedName("category")
@Expose
private String category;
@SerializedName("tags")
@Expose
private List<Object> tags = null;
@SerializedName("groupNames")
@Expose
private List<Object> groupNames = null;
@SerializedName("stateDescription")
@Expose
private StateDescription stateDescription;
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public List<Object> getTags() {
return tags;
}
public void setTags(List<Object> tags) {
this.tags = tags;
}
public List<Object> getGroupNames() {
return groupNames;
}
public void setGroupNames(List<Object> groupNames) {
this.groupNames = groupNames;
}
public StateDescription getStateDescription() {
return stateDescription;
}
public void setStateDescription(StateDescription stateDescription) {
this.stateDescription = stateDescription;
}
}

View File

@@ -0,0 +1,32 @@
package com.bwssystems.HABridge.plugins.openhab;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Option {
@SerializedName("value")
@Expose
private String value;
@SerializedName("label")
@Expose
private String label;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}

View File

@@ -0,0 +1,44 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StateDescription {
@SerializedName("pattern")
@Expose
private String pattern;
@SerializedName("readOnly")
@Expose
private Boolean readOnly;
@SerializedName("options")
@Expose
private List<Option> options = null;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public Boolean getReadOnly() {
return readOnly;
}
public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}
public List<Option> getOptions() {
return options;
}
public void setOptions(List<Option> options) {
this.options = options;
}
}

View File

@@ -72,26 +72,26 @@ public class SomfyHome implements Home {
log.warn("Should not get here, no somfy hub available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no somfy hub available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex])) {
log.debug("executing HUE api request to change activity to Somfy: " + anItem.getItem().toString());
String jsonToPost = anItem.getItem().toString();
String jsonToPost = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
log.debug("executing HUE api request to change activity to Somfy: {}", jsonToPost);
SomfyInfo somfyHandler = getSomfyHandler(device.getTargetDevice());
if(somfyHandler == null) {
log.warn("Should not get here, no Somfy configured");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no somfy configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
+ lightId + "/state\"}}]";
} else {
try {
somfyHandler.execApply(jsonToPost);
} catch (Exception e) {
log.warn("Error posting request to Somfy");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Error posting request to SomfyTahoma\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
+ "\",\"description\": \"Error posting request to SomfyTahoma\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
}
}
@@ -103,7 +103,7 @@ public class SomfyHome implements Home {
@Override
public Home createHome(BridgeSettings bridgeSettings) {
validSomfy = bridgeSettings.getBridgeSettingsDescriptor().isValidSomfy();
log.info("Somfy Home created." + (validSomfy ? "" : " No Somfys configured."));
log.info("Somfy Home created. {}", (validSomfy ? "" : " No Somfys configured."));
if(validSomfy) {
somfys = new HashMap<>();
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getSomfyAddress().getDevices().iterator();
@@ -125,4 +125,9 @@ public class SomfyHome implements Home {
somfys = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -74,8 +74,8 @@ public class SomfyInfo {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
urlEncodedFormEntity.writeTo(bos);
String body = bos.toString();
String response = httpClient.doHttpRequest(BASE_URL + "json/login",HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
log.debug(response);
String response = httpClient.doHttpRequest(BASE_URL + "json/login", HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
log.debug("Somfy login response <<<{}>>>", response);
}
private NameValue[] getHttpHeaders() {
@@ -89,16 +89,16 @@ public class SomfyInfo {
NameValue[] httpHeader = getHttpHeaders();
log.info("Making SOMFY http setup call");
String response = httpClient.doHttpRequest(BASE_URL + "json/getSetup", HttpGet.METHOD_NAME, "", "", httpHeader );
log.debug(response);
log.debug("Somfy getSetup response <<<{}>>>", response);
GetSetup setupData = new Gson().fromJson(response, GetSetup.class);
return setupData;
}
public void execApply(String jsonToPost) throws Exception {
login(namedIP.getUsername(), namedIP.getPassword());
log.info("Making SOMFY http exec call");
log.info("Making SOMFY http exec call with json: {}", jsonToPost);
String response = httpClient.doHttpRequest(BASE_URL_ENDUSER + "exec/apply", HttpPost.METHOD_NAME, "application/json;charset=UTF-8", jsonToPost, getHttpHeaders());
log.info(response);
log.debug("Somfy exec reply response <<<{}>>>", response);
}

Some files were not shown because too many files have changed in this diff Show More