mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 08:13:23 +00:00
Compare commits
241 Commits
v4.5.0rc3
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6234874cb3 | ||
|
|
483b165f2a | ||
|
|
e2969c1a49 | ||
|
|
c99777efe7 | ||
|
|
8363d4c78c | ||
|
|
e015bca721 | ||
|
|
3b5eea0dce | ||
|
|
25e8b3f24f | ||
|
|
7f72b0311a | ||
|
|
b3f2c25721 | ||
|
|
98008428a7 | ||
|
|
675e74df7b | ||
|
|
fb7aabb780 | ||
|
|
969ed352f7 | ||
|
|
c98513c365 | ||
|
|
add9617a07 | ||
|
|
f9e9f16756 | ||
|
|
f15cc0d53a | ||
|
|
0f791c1e71 | ||
|
|
9887042f4d | ||
|
|
c840f2bc4d | ||
|
|
9a355b7906 | ||
|
|
0d568d8d68 | ||
|
|
f5e100667e | ||
|
|
c376253488 | ||
|
|
a3fd2ca722 | ||
|
|
fe4df16e10 | ||
|
|
9399af7ec7 | ||
|
|
be72f7e62c | ||
|
|
768eebfc78 | ||
|
|
79ce23b80a | ||
|
|
bddc7c1c31 | ||
|
|
51c6ffc48a | ||
|
|
ee4afc00c0 | ||
|
|
8b48f23741 | ||
|
|
87f79df8b1 | ||
|
|
1142704d22 | ||
|
|
d014240fba | ||
|
|
5c2d30e24b | ||
|
|
28d84f667a | ||
|
|
755533b30d | ||
|
|
53208ddabc | ||
|
|
ff2973e473 | ||
|
|
743656cab3 | ||
|
|
53be3ba213 | ||
|
|
a5ee0aafc8 | ||
|
|
aed8ffa8d3 | ||
|
|
369e5a25e6 | ||
|
|
3fe19f5d4e | ||
|
|
5736bb92db | ||
|
|
b61f334826 | ||
|
|
556a5fef1c | ||
|
|
4b0152060f | ||
|
|
fcb31b8f76 | ||
|
|
0205633684 | ||
|
|
7b48590807 | ||
|
|
5f7cd70710 | ||
|
|
46ad4489ad | ||
|
|
bfd1b94473 | ||
|
|
7d920d3885 | ||
|
|
2dbf4c96c4 | ||
|
|
69b510ae18 | ||
|
|
e86b700e93 | ||
|
|
a05b933e43 | ||
|
|
fe0b072b4e | ||
|
|
3e76e6298a | ||
|
|
f266945b7e | ||
|
|
2d3fac691b | ||
|
|
5f6bfae41a | ||
|
|
79d5b5da28 | ||
|
|
45e2b63f98 | ||
|
|
b6b9089ec4 | ||
|
|
063055f5c8 | ||
|
|
c1dc89704d | ||
|
|
f97c718568 | ||
|
|
d05b6bea5c | ||
|
|
2f567cd604 | ||
|
|
3971c81449 | ||
|
|
e1b5aede66 | ||
|
|
14c3614856 | ||
|
|
1311d4a68d | ||
|
|
9cbc290768 | ||
|
|
f90f39e5f1 | ||
|
|
07fa11b9ff | ||
|
|
df04d542db | ||
|
|
92ab02145e | ||
|
|
d9916b7662 | ||
|
|
f8349f12bc | ||
|
|
12823704f3 | ||
|
|
7490cf72a3 | ||
|
|
ce220d999a | ||
|
|
9a438abf79 | ||
|
|
ce97e928ad | ||
|
|
56481f3f72 | ||
|
|
55ed9ba4c2 | ||
|
|
df67980bd6 | ||
|
|
b6b78c4849 | ||
|
|
b1d1f2ac46 | ||
|
|
750056df06 | ||
|
|
3f13e957ad | ||
|
|
afc254720c | ||
|
|
943e4420e6 | ||
|
|
c9e6cd079f | ||
|
|
faae6aa31f | ||
|
|
c25f08f142 | ||
|
|
d6ad9d288e | ||
|
|
3400c4d43a | ||
|
|
ddcbea001c | ||
|
|
9a35e47c27 | ||
|
|
199fcce549 | ||
|
|
bfeb382d1f | ||
|
|
3a93d9e98f | ||
|
|
3b22e3f711 | ||
|
|
5c1f1f5b96 | ||
|
|
82788f1ecd | ||
|
|
d5920e1454 | ||
|
|
b26a63bb7a | ||
|
|
f17cea3c9d | ||
|
|
7f68285a43 | ||
|
|
cb46a13802 | ||
|
|
de07393e6e | ||
|
|
4b40b03da4 | ||
|
|
4f5d4acf56 | ||
|
|
271bd3913c | ||
|
|
869ffaaf36 | ||
|
|
5a73cc20a9 | ||
|
|
1a936c631c | ||
|
|
1a8a6f7a6f | ||
|
|
879d3b5326 | ||
|
|
3313548ec2 | ||
|
|
e6db6e11e5 | ||
|
|
dc28eb2984 | ||
|
|
b8acb4a52c | ||
|
|
c843e8d1ac | ||
|
|
21fdaf4545 | ||
|
|
db192df2c6 | ||
|
|
4a24d263c1 | ||
|
|
3394559539 | ||
|
|
47074ff60f | ||
|
|
047a7de612 | ||
|
|
7fc7f00308 | ||
|
|
14e940134c | ||
|
|
1897633e75 | ||
|
|
5a052d9374 | ||
|
|
4b048c2a7f | ||
|
|
27f77b9caa | ||
|
|
18c47ee5e4 | ||
|
|
27dd8475e9 | ||
|
|
37b381085c | ||
|
|
b2a30f5771 | ||
|
|
b88b3fa245 | ||
|
|
52aac32474 | ||
|
|
037b151729 | ||
|
|
3f3d643053 | ||
|
|
f27d905869 | ||
|
|
4c694cb285 | ||
|
|
ca2c5f7b04 | ||
|
|
0c49df1473 | ||
|
|
fe613f7688 | ||
|
|
4b247557d4 | ||
|
|
dc49de41ce | ||
|
|
9d07fac929 | ||
|
|
4ecbad6558 | ||
|
|
4c86e42776 | ||
|
|
00dbea6dac | ||
|
|
ed2bf3bd83 | ||
|
|
58fb085180 | ||
|
|
800f5ec2aa | ||
|
|
bdf5770ba0 | ||
|
|
a213672341 | ||
|
|
d337546da7 | ||
|
|
b9437d42e8 | ||
|
|
71c4447d25 | ||
|
|
a489061bac | ||
|
|
75b925992b | ||
|
|
05b9f195d7 | ||
|
|
5eca809c4a | ||
|
|
fa00b7106a | ||
|
|
df85c8a349 | ||
|
|
d8d5e8f39a | ||
|
|
690bdaa748 | ||
|
|
feee22dbac | ||
|
|
548da932ad | ||
|
|
b147f6606e | ||
|
|
31fe05fe2b | ||
|
|
924f3059fb | ||
|
|
5231eac4b0 | ||
|
|
28144312ff | ||
|
|
60e8855aa7 | ||
|
|
5ea14f9069 | ||
|
|
ce79fb4b82 | ||
|
|
98ce4e2a3a | ||
|
|
026626b5ab | ||
|
|
95c342b548 | ||
|
|
cb9312f6c3 | ||
|
|
8831fec6be | ||
|
|
0227a05970 | ||
|
|
087d66694e | ||
|
|
20ad6891e8 | ||
|
|
cd2bd072ed | ||
|
|
3a5262ff33 | ||
|
|
430eff958c | ||
|
|
86371c03b2 | ||
|
|
3207b6b76e | ||
|
|
3d4724ac57 | ||
|
|
63ac729967 | ||
|
|
0900fec60f | ||
|
|
5ccb793ddb | ||
|
|
3ebab82977 | ||
|
|
e877f410f3 | ||
|
|
220e337d08 | ||
|
|
92b7f4e260 | ||
|
|
78d39325b0 | ||
|
|
208b1cad2a | ||
|
|
ff760a488c | ||
|
|
9200c0fc5d | ||
|
|
998450af4e | ||
|
|
d78c7c536d | ||
|
|
a55c53299a | ||
|
|
fb9cc64839 | ||
|
|
409c93bfb2 | ||
|
|
543a79bb66 | ||
|
|
16d1054b96 | ||
|
|
165b6ef9bb | ||
|
|
fb94b858f6 | ||
|
|
ea80925533 | ||
|
|
62b896ee07 | ||
|
|
8657ea6704 | ||
|
|
05bd6b6d77 | ||
|
|
19256e4eaa | ||
|
|
905f6aa9ec | ||
|
|
daa0dac5b9 | ||
|
|
0478fc69f4 | ||
|
|
b99e74823c | ||
|
|
9aaab37a17 | ||
|
|
df618afeda | ||
|
|
d36769e2a0 | ||
|
|
ebeb6be7a7 | ||
|
|
d3979da2b4 | ||
|
|
f276f66991 | ||
|
|
3ac5c10f08 |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -12,3 +12,16 @@ data
|
||||
/.settings/
|
||||
/start.bat
|
||||
/.classpath
|
||||
/.project
|
||||
|
||||
sftp-config\.json
|
||||
/bin/
|
||||
.vscode/launch.json
|
||||
.vscode/launch.test.json
|
||||
.vscode/settings.json
|
||||
.vscode/tasks.json
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
package-lock.json
|
||||
.project
|
||||
|
||||
23
.project
23
.project
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ha-bridge</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
273
java8_pom.xml
Normal file
273
java8_pom.xml
Normal file
@@ -0,0 +1,273 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>5.4.0</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>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<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>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<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.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.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.igniterealtime.smack</groupId>
|
||||
<artifactId>smack-core</artifactId>
|
||||
<version>4.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>lifx-sdk-java</artifactId>
|
||||
<version>2.1.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.mob41</groupId>
|
||||
<artifactId>broadlink-java-api</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmdns</groupId>
|
||||
<artifactId>jmdns</artifactId>
|
||||
<version>3.5.5</version>
|
||||
</dependency>
|
||||
</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>
|
||||
<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>
|
||||
<version>3.3</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>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M3</version>
|
||||
<configuration>
|
||||
<skipTests>false</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
<exclude>META-INF/*.txt</exclude>
|
||||
<exclude>META-INF/maven/**</exclude>
|
||||
<exclude>about_files/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.slf4j:slf4j-api</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>commons-logging:commons-logging</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>xpp3:xpp3</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.igniterealtime.smack:*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>com.github.bwssytems:harmony-java-client</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.eclipse.paho:org.eclipse.paho.client.mqttv3</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>com.bwssystems.HABridge.HABridge</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
267
pom.xml
267
pom.xml
@@ -1,160 +1,208 @@
|
||||
<?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>4.5.0rc3</version>
|
||||
<version>5.4.1-java11</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.1</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.3</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>
|
||||
<version>4.5.13</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>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>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.5</version>
|
||||
<version>1.2.13</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.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.5</version>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>lifx-sdk-java</artifactId>
|
||||
<version>2.1.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.mob41</groupId>
|
||||
<artifactId>broadlink-java-api</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmdns</groupId>
|
||||
<artifactId>jmdns</artifactId>
|
||||
<version>3.5.5</version>
|
||||
</dependency>
|
||||
</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, Java 11 is 3.6 -->
|
||||
<version>3.6</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin> <plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<!-- Comment this release line out for Java 1.8 and Raspberry PI compilation -->
|
||||
<release>11</release>
|
||||
<!-- Uncomment the next two lines for Java 1.8 and Raspberry PI compilation -->
|
||||
<!-- <source>1.8</source> -->
|
||||
<!-- <target>1.8</target> -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M3</version>
|
||||
<configuration>
|
||||
<skipTests>false</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<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 +264,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>
|
||||
@@ -227,4 +274,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BridgeSecurity {
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
};
|
||||
private char[] habridgeKey;
|
||||
private static char[] habridgeKey;
|
||||
private String execGarden;
|
||||
private BridgeSecurityDescriptor securityDescriptor;
|
||||
private boolean settingsChanged;
|
||||
@@ -146,7 +146,16 @@ public class BridgeSecurity {
|
||||
public String getExecGarden() {
|
||||
return execGarden;
|
||||
}
|
||||
public void setUseLinkButton(boolean useThis) {
|
||||
|
||||
String getKeyfilePath() {
|
||||
return securityDescriptor.getKeyfilePath();
|
||||
}
|
||||
|
||||
String getKeyfilePassword() {
|
||||
return securityDescriptor.getKeyfilePassword();
|
||||
}
|
||||
|
||||
private void setUseLinkButton(boolean useThis) {
|
||||
securityDescriptor.setUseLinkButton(useThis);
|
||||
settingsChanged = true;
|
||||
}
|
||||
@@ -155,16 +164,77 @@ public class BridgeSecurity {
|
||||
return securityDescriptor.isSecureHueApi();
|
||||
}
|
||||
|
||||
public void setSecureHueApi(boolean theState) {
|
||||
securityDescriptor.setSecureHueApi(theState);
|
||||
public boolean isUseHttps() {
|
||||
return securityDescriptor.isUseHttps();
|
||||
}
|
||||
|
||||
public boolean isKeyfilePW() {
|
||||
if(securityDescriptor.getKeyfilePassword() != null && !securityDescriptor.getKeyfilePassword().trim().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setSecureHueApi(boolean theState) {
|
||||
securityDescriptor.setSecureHueApi(theState);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
private void setUseHttps(boolean usehttps, String keyfilepath, String keyfilepassword) {
|
||||
if(usehttps) {
|
||||
if(!isUseHttps()) {
|
||||
securityDescriptor.setKeyfilePath(keyfilepath);
|
||||
securityDescriptor.setKeyfilePassword(keyfilepassword);
|
||||
securityDescriptor.setUseHttps(usehttps);
|
||||
settingsChanged = true;
|
||||
} else {
|
||||
if(!keyfilepassword.equals("########")) {
|
||||
securityDescriptor.setKeyfilePassword(keyfilepassword);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if(!securityDescriptor.getKeyfilePath().equals(keyfilepath)) {
|
||||
securityDescriptor.setKeyfilePath(keyfilepath);
|
||||
settingsChanged = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(isUseHttps()) {
|
||||
securityDescriptor.setKeyfilePassword("");
|
||||
securityDescriptor.setKeyfilePath("");
|
||||
securityDescriptor.setUseHttps(usehttps);
|
||||
settingsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SecurityInfo getSecurityInfo() {
|
||||
SecurityInfo theInfo = new SecurityInfo();
|
||||
theInfo.setUseLinkButton(isUseLinkButton());
|
||||
theInfo.setSecureHueApi(isSecureHueApi());
|
||||
theInfo.setSecure(isSecure());
|
||||
theInfo.setUseHttps(isUseHttps());
|
||||
theInfo.setKeyfilePath(securityDescriptor.getKeyfilePath());
|
||||
|
||||
if(isKeyfilePW()) {
|
||||
theInfo.setKeyfilePassword("########");
|
||||
}
|
||||
else {
|
||||
theInfo.setKeyfilePassword("");
|
||||
}
|
||||
if(isSecure()) {
|
||||
theInfo.setExecGarden(execGarden);
|
||||
}
|
||||
return theInfo;
|
||||
}
|
||||
|
||||
public void setSecurityDataByInfo(SecurityInfo theInfo) {
|
||||
setUseLinkButton(theInfo.isUseLinkButton());
|
||||
setSecureHueApi(theInfo.isSecureHueApi());
|
||||
setUseHttps(theInfo.isUseHttps(), theInfo.getKeyfilePath(), theInfo.getKeyfilePassword());
|
||||
}
|
||||
|
||||
public LoginResult validatePassword(User targetUser) throws IOException {
|
||||
LoginResult result = new LoginResult();
|
||||
if(targetUser != null && targetUser.getUsername() != null) {
|
||||
@@ -201,43 +271,75 @@ public class BridgeSecurity {
|
||||
public void setSettingsChanged(boolean settingsChanged) {
|
||||
this.settingsChanged = settingsChanged;
|
||||
}
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return securityDescriptor.getWhitelist();
|
||||
}
|
||||
|
||||
public void setWhitelist(Map<String, WhitelistEntry> aWhitelist) {
|
||||
securityDescriptor.setWhitelist(aWhitelist);
|
||||
settingsChanged = true;
|
||||
return;
|
||||
}
|
||||
|
||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
||||
&& !aUser.equalsIgnoreCase("")) {
|
||||
&& !aUser.equalsIgnoreCase("") && !aUser.equals(DEPRACATED_INTERNAL_USER)) {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
Set<String> theUserIds = securityDescriptor.getWhitelist().keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while (userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
if (validUser.equals(aUser))
|
||||
if (validUser.equals(aUser)) {
|
||||
found = true;
|
||||
log.debug("validateWhitelistUser: found a user <" + aUser + ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && !strict) {
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
|
||||
found = true;
|
||||
if(!found && !strict) {
|
||||
log.debug("validateWhitelistUser: a user was not found and it is not strict rules <" + aUser + "> being created");
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
log.debug("validateWhitelistUser: a user was not found and strict rules is set to: " + strict + "for user <" + aUser + ">");
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser == null ? "" : aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
}
|
||||
|
||||
Object anUser = securityDescriptor.getWhitelist().remove(DEPRACATED_INTERNAL_USER);
|
||||
if(anUser != null)
|
||||
setSettingsChanged(true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newWhitelistUser(String aUser, String userDescription) {
|
||||
if(aUser.equals(DEPRACATED_INTERNAL_USER))
|
||||
return;
|
||||
public String findWhitelistUserByDeviceType(String aDeviceType) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
WhitelistEntry anEntry = null;
|
||||
if (aDeviceType != null) {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
Set<String> theUserIds = securityDescriptor.getWhitelist().keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while (!found && userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
anEntry = securityDescriptor.getWhitelist().get(validUser);
|
||||
if (anEntry.getName().equals(aDeviceType)) {
|
||||
found = true;
|
||||
log.debug("findWhitelistUserByDeviceType: found a user <" + validUser + "> for device type <" + aDeviceType + ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
validUser = null;
|
||||
|
||||
return validUser;
|
||||
}
|
||||
|
||||
private void newWhitelistUser(String aUser, String userDescription) {
|
||||
if (securityDescriptor.getWhitelist() == null) {
|
||||
securityDescriptor.setWhitelist(new HashMap<>());
|
||||
}
|
||||
@@ -249,8 +351,14 @@ public class BridgeSecurity {
|
||||
}
|
||||
|
||||
public String createWhitelistUser(String userDescription) {
|
||||
String aUser = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
String aUser = null;
|
||||
String theEntry = findWhitelistUserByDeviceType(userDescription);
|
||||
if(theEntry == null) {
|
||||
aUser = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
} else {
|
||||
aUser = theEntry;
|
||||
}
|
||||
return aUser;
|
||||
}
|
||||
|
||||
@@ -268,6 +376,13 @@ public class BridgeSecurity {
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public void removeHttpsSettings() {
|
||||
securityDescriptor.setUseHttps(false);
|
||||
securityDescriptor.setKeyfilePassword(null);
|
||||
securityDescriptor.setKeyfilePath(null);
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
|
||||
public void removeTestUsers() {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
@@ -278,16 +393,15 @@ public class BridgeSecurity {
|
||||
Iterator<Entry<String, WhitelistEntry>> it = securityDescriptor.getWhitelist().entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, WhitelistEntry> pair = it.next();
|
||||
it.remove(); // avoids a ConcurrentModificationException
|
||||
if(pair.getValue().getName().equals(TEST_USER_TYPE)) {
|
||||
securityDescriptor.getWhitelist().remove(pair.getKey());
|
||||
it.remove(); // avoids a ConcurrentModificationException
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
static String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||
@@ -299,7 +413,7 @@ public class BridgeSecurity {
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
private String decrypt(String property) throws GeneralSecurityException, IOException {
|
||||
static String decrypt(String property) throws GeneralSecurityException, IOException {
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||
@@ -318,7 +432,7 @@ public class BridgeSecurity {
|
||||
|
||||
public void removeAuthenticatedUser(Request request) {
|
||||
request.session().removeAttribute(USER_SESSION_ID);
|
||||
|
||||
request.session().invalidate();
|
||||
}
|
||||
|
||||
public User getAuthenticatedUser(Request request) {
|
||||
|
||||
@@ -9,7 +9,10 @@ public class BridgeSecurityDescriptor {
|
||||
private String execGarden;
|
||||
private boolean secureHueApi;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
|
||||
private boolean useHttps;
|
||||
private String keyfilePassword;
|
||||
private String keyfilePath;
|
||||
|
||||
public BridgeSecurityDescriptor() {
|
||||
super();
|
||||
this.setUseLinkButton(false);
|
||||
@@ -67,4 +70,28 @@ public class BridgeSecurityDescriptor {
|
||||
return secureFlag;
|
||||
|
||||
}
|
||||
|
||||
public boolean isUseHttps() {
|
||||
return useHttps;
|
||||
}
|
||||
|
||||
public void setUseHttps(boolean useHttps) {
|
||||
this.useHttps = useHttps;
|
||||
}
|
||||
|
||||
public String getKeyfilePassword() {
|
||||
return keyfilePassword;
|
||||
}
|
||||
|
||||
public void setKeyfilePassword(String keyfilePassword) {
|
||||
this.keyfilePassword = keyfilePassword;
|
||||
}
|
||||
|
||||
public String getKeyfilePath() {
|
||||
return keyfilePath;
|
||||
}
|
||||
|
||||
public void setKeyfilePath(String keyfilePath) {
|
||||
this.keyfilePath = keyfilePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,13 +59,14 @@ 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;
|
||||
String theFibaroAddress = null;
|
||||
String theSomfyAddress = null;
|
||||
String theHarmonyAddress = null;
|
||||
String configFileProperty = System.getProperty("config.file");
|
||||
@@ -90,6 +92,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
|
||||
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
|
||||
theBridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db"));
|
||||
theBridgeSettings.setUpnpGroupDb(System.getProperty("upnp.group.db"));
|
||||
theBridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||
|
||||
theVeraAddress = System.getProperty("vera.address");
|
||||
@@ -107,6 +110,22 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
}
|
||||
theBridgeSettings.setVeraAddress(theVeraList);
|
||||
|
||||
theFibaroAddress = System.getProperty("fibaro.address");
|
||||
IpList theFibaroList = null;
|
||||
if(theFibaroAddress != null) {
|
||||
try {
|
||||
theFibaroList = new Gson().fromJson(theFibaroAddress, IpList.class);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
theFibaroList = new Gson().fromJson("{devices:[{name:default,ip:" + theFibaroAddress + "}]}", IpList.class);
|
||||
} catch (Exception et) {
|
||||
log.error("Cannot parse fibaro.address, not set with message: " + e.getMessage(), e);
|
||||
theFibaroList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
theBridgeSettings.setFibaroAddress(theFibaroList);
|
||||
|
||||
theHarmonyAddress = System.getProperty("harmony.address");
|
||||
IpList theHarmonyList = null;
|
||||
@@ -140,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.");
|
||||
@@ -158,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)
|
||||
@@ -170,14 +192,21 @@ public class BridgeSettings extends BackupHandler {
|
||||
|
||||
if(theBridgeSettings.getUpnpDeviceDb() == null)
|
||||
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
||||
|
||||
if(theBridgeSettings.getUpnpGroupDb() == null)
|
||||
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));
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||
|
||||
if(theBridgeSettings.getLinkbuttontimeout() < 30)
|
||||
theBridgeSettings.setLinkbuttontimeout(Configuration.LINK_BUTTON_TIMEOUT);
|
||||
|
||||
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
||||
theBridgeSettings.setFibaroconfigured(theBridgeSettings.isValidFibaro());
|
||||
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
||||
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
||||
@@ -186,11 +215,19 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
|
||||
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);
|
||||
theBridgeSettings.setUpnpConfigAddress(serverIpOverride);
|
||||
}
|
||||
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
|
||||
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());
|
||||
@@ -216,10 +253,10 @@ public class BridgeSettings extends BackupHandler {
|
||||
return;
|
||||
try {
|
||||
theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
|
||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||
theBridgeSettings.setConfigfile(aPath.toString());
|
||||
} catch (Exception e) {
|
||||
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed. Using default settings.");
|
||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -12,6 +12,12 @@ public class BridgeSettingsDescriptor {
|
||||
@SerializedName("upnpconfigaddress")
|
||||
@Expose
|
||||
private String upnpconfigaddress;
|
||||
@SerializedName("useupnpiface")
|
||||
@Expose
|
||||
private boolean useupnpiface;
|
||||
@SerializedName("userooms")
|
||||
@Expose
|
||||
private boolean userooms;
|
||||
@SerializedName("serverport")
|
||||
@Expose
|
||||
private Integer serverport;
|
||||
@@ -21,18 +27,21 @@ public class BridgeSettingsDescriptor {
|
||||
@SerializedName("upnpdevicedb")
|
||||
@Expose
|
||||
private String upnpdevicedb;
|
||||
@SerializedName("upnpgroupdb")
|
||||
@Expose
|
||||
private String upnpgroupdb;
|
||||
@SerializedName("veraaddress")
|
||||
@Expose
|
||||
private IpList veraaddress;
|
||||
@SerializedName("fibaroaddress")
|
||||
@Expose
|
||||
private IpList fibaroaddress;
|
||||
@SerializedName("harmonyaddress")
|
||||
@Expose
|
||||
private IpList harmonyaddress;
|
||||
@SerializedName("buttonsleep")
|
||||
@Expose
|
||||
private Integer buttonsleep;
|
||||
@SerializedName("upnpstrict")
|
||||
@Expose
|
||||
private boolean upnpstrict;
|
||||
@SerializedName("traceupnp")
|
||||
@Expose
|
||||
private boolean traceupnp;
|
||||
@@ -57,9 +66,6 @@ public class BridgeSettingsDescriptor {
|
||||
@SerializedName("haladdress")
|
||||
@Expose
|
||||
private IpList haladdress;
|
||||
@SerializedName("haltoken")
|
||||
@Expose
|
||||
private String haltoken;
|
||||
@SerializedName("whitelist")
|
||||
@Expose
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
@@ -81,16 +87,68 @@ 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;
|
||||
@SerializedName("hubmac")
|
||||
@Expose
|
||||
private String hubmac;
|
||||
@SerializedName("securityData")
|
||||
@Expose
|
||||
private String securityData;
|
||||
|
||||
@SerializedName("homewizardaddress")
|
||||
@Expose
|
||||
private IpList homewizardaddress;
|
||||
@SerializedName("upnpsenddelay")
|
||||
@Expose
|
||||
private Integer upnpsenddelay;
|
||||
@SerializedName("fhemaddress")
|
||||
@Expose
|
||||
private IpList fhemaddress;
|
||||
@SerializedName("homegenieaddress")
|
||||
@Expose
|
||||
private IpList homegenieaddress;
|
||||
@SerializedName("lifxconfigured")
|
||||
@Expose
|
||||
private boolean lifxconfigured;
|
||||
@SerializedName("broadlinkconfigured")
|
||||
@Expose
|
||||
private boolean broadlinkconfigured;
|
||||
@SerializedName("tracestate")
|
||||
@Expose
|
||||
private boolean tracestate;
|
||||
@SerializedName("upnporiginal")
|
||||
@Expose
|
||||
private boolean upnporiginal;
|
||||
@SerializedName("seedid")
|
||||
@Expose
|
||||
private Integer seedid;
|
||||
@SerializedName("haaddressessecured")
|
||||
@Expose
|
||||
private boolean haaddressessecured;
|
||||
@SerializedName("upnpadvanced")
|
||||
@Expose
|
||||
private boolean upnpadvanced;
|
||||
@SerializedName("linkbuttontimeout")
|
||||
@Expose
|
||||
private Integer linkbuttontimeout;
|
||||
@SerializedName("uidnineoctets")
|
||||
@Expose
|
||||
private boolean uidnineoctets;
|
||||
|
||||
// @SerializedName("activeloggers")
|
||||
// @Expose
|
||||
// private List<NameValue> activeloggers;
|
||||
|
||||
private boolean settingsChanged;
|
||||
private boolean veraconfigured;
|
||||
private boolean fibaroconfigured;
|
||||
private boolean harmonyconfigured;
|
||||
private boolean hueconfigured;
|
||||
private boolean nestconfigured;
|
||||
@@ -99,329 +157,732 @@ 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;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
this.upnpstrict = true;
|
||||
// this.upnpstrict = true;
|
||||
this.useupnpiface = false;
|
||||
this.userooms = false;
|
||||
this.traceupnp = false;
|
||||
this.nestconfigured = false;
|
||||
this.veraconfigured = false;
|
||||
this.fibaroconfigured = false;
|
||||
this.somfyconfigured = false;
|
||||
this.harmonyconfigured = false;
|
||||
this.hueconfigured = false;
|
||||
this.halconfigured = false;
|
||||
this.mqttconfigured = false;
|
||||
this.hassconfigured = false;
|
||||
this.domoticzconfigured = false;
|
||||
this.homewizardconfigured = false;
|
||||
this.lifxconfigured = false;
|
||||
this.openhabconfigured = false;
|
||||
this.moziotconfigured = false;
|
||||
this.homegenieconfigured = false;
|
||||
this.farenheit = true;
|
||||
this.whitelist = null;
|
||||
this.securityData = null;
|
||||
this.settingsChanged = false;
|
||||
this.myechourl = "echo.amazon.com/#cards";
|
||||
this.myechourl = "alexa.amazon.com/spa/index.html#cards";
|
||||
this.webaddress = "0.0.0.0";
|
||||
this.hubversion = HueConstants.HUB_VERSION;
|
||||
this.hubmac = null;
|
||||
// this.activeloggers = null;
|
||||
this.upnpsenddelay = Configuration.UPNP_SEND_DELAY;
|
||||
this.broadlinkconfigured = false;
|
||||
this.tracestate = false;
|
||||
this.upnporiginal = false;
|
||||
this.seedid = 100;
|
||||
this.haaddressessecured = false;
|
||||
this.configfile = Configuration.CONFIG_FILE;
|
||||
this.upnpadvanced = false;
|
||||
this.linkbuttontimeout = Configuration.LINK_BUTTON_TIMEOUT;
|
||||
this.uidnineoctets = false;
|
||||
}
|
||||
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
}
|
||||
|
||||
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
||||
this.upnpconfigaddress = upnpConfigAddress;
|
||||
}
|
||||
public Integer getServerPort() {
|
||||
|
||||
public boolean isUseupnpiface() {
|
||||
return useupnpiface;
|
||||
}
|
||||
|
||||
public void setUseupnpiface(boolean useupnpiface) {
|
||||
this.useupnpiface = useupnpiface;
|
||||
}
|
||||
|
||||
public boolean isUserooms() {
|
||||
return userooms;
|
||||
}
|
||||
|
||||
public void setUserooms(boolean userooms) {
|
||||
this.userooms = userooms;
|
||||
}
|
||||
|
||||
public Integer getServerPort() {
|
||||
return serverport;
|
||||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getFibaroAddress().getDevices();
|
||||
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;
|
||||
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))
|
||||
return false;
|
||||
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||
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()))
|
||||
indexHue = i;
|
||||
}
|
||||
if (indexHue >= 0) {
|
||||
hueaddress.getDevices().set(indexHue, aHue);
|
||||
this.setSettingsChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean isValidHomeWizard() {
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isHaaddressessecured() {
|
||||
return haaddressessecured;
|
||||
}
|
||||
|
||||
public void setHaaddressessecured(boolean haaddressessecured) {
|
||||
this.haaddressessecured = haaddressessecured;
|
||||
}
|
||||
|
||||
public boolean isUpnpadvanced() {
|
||||
return upnpadvanced;
|
||||
}
|
||||
|
||||
public void setUpnpadvanced(boolean upnpadvanced) {
|
||||
this.upnpadvanced = upnpadvanced;
|
||||
}
|
||||
|
||||
public Integer getLinkbuttontimeout() {
|
||||
return linkbuttontimeout;
|
||||
}
|
||||
|
||||
public void setLinkbuttontimeout(Integer linkbuttontimeout) {
|
||||
this.linkbuttontimeout = linkbuttontimeout;
|
||||
}
|
||||
|
||||
public boolean isUidnineoctets() {
|
||||
return uidnineoctets;
|
||||
}
|
||||
|
||||
public void setUidnineoctets(boolean uidnineoctets) {
|
||||
this.uidnineoctets = uidnineoctets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge;
|
||||
|
||||
public class Configuration {
|
||||
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||
public final static String GROUP_DB_DIRECTORY = "data/group.db";
|
||||
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
||||
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
||||
@@ -13,4 +14,8 @@ 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;
|
||||
public static final int LINK_BUTTON_TIMEOUT = 45;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ public class DeviceMapTypes {
|
||||
public final static String[] CUSTOM_DEVICE = { "custom", "Custom"};
|
||||
public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"};
|
||||
public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"};
|
||||
public final static String[] FIBARO_DEVICE = { "fibaroDevice", "Fibaro Device"};
|
||||
public final static String[] FIBARO_SCENE = { "fibaroScene", "Fibaro Scene"};
|
||||
public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"};
|
||||
public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"};
|
||||
public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"};
|
||||
@@ -20,6 +22,7 @@ public class DeviceMapTypes {
|
||||
public final static String[] EXEC_DEVICE_COMPAT = { "exec", "Execute Script/Program"};
|
||||
public final static String[] CMD_DEVICE = { "cmdDevice", "Execute Command/Script/Program"};
|
||||
public final static String[] HASS_DEVICE = { "hassDevice", "HomeAssistant Device"};
|
||||
public final static String[] HOMEWIZARD_DEVICE = { "homewizardDevice", "HomeWizard Device"};
|
||||
public final static String[] TCP_DEVICE = { "tcpDevice", "TCP Device"};
|
||||
public final static String[] TCP_DEVICE_COMPAT = { "TCP", "TCP Device"};
|
||||
public final static String[] UDP_DEVICE = { "udpDevice", "UDP Device"};
|
||||
@@ -28,6 +31,11 @@ public class DeviceMapTypes {
|
||||
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz Device"};
|
||||
public final static String[] 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;
|
||||
@@ -46,18 +54,25 @@ public class DeviceMapTypes {
|
||||
deviceMapTypes.add(HARMONY_ACTIVITY);
|
||||
deviceMapTypes.add(HARMONY_BUTTON);
|
||||
deviceMapTypes.add(HASS_DEVICE);
|
||||
deviceMapTypes.add(HOMEWIZARD_DEVICE);
|
||||
deviceMapTypes.add(HTTP_DEVICE);
|
||||
deviceMapTypes.add(HUE_DEVICE);
|
||||
deviceMapTypes.add(LIFX_DEVICE);
|
||||
deviceMapTypes.add(MQTT_MESSAGE);
|
||||
deviceMapTypes.add(NEST_HOMEAWAY);
|
||||
deviceMapTypes.add(NEST_THERMO_SET);
|
||||
deviceMapTypes.add(SOMFY_DEVICE);
|
||||
deviceMapTypes.add(TCP_DEVICE);
|
||||
deviceMapTypes.add(UDP_DEVICE);
|
||||
deviceMapTypes.add(VERA_DEVICE);
|
||||
deviceMapTypes.add(VERA_SCENE);
|
||||
deviceMapTypes.add(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;
|
||||
|
||||
@@ -2,16 +2,20 @@ package com.bwssystems.HABridge;
|
||||
|
||||
import static spark.Spark.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.devicemanagmeent.*;
|
||||
import com.bwssystems.HABridge.hue.HueMulator;
|
||||
import com.bwssystems.HABridge.plugins.http.HttpClientPool;
|
||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||
|
||||
public class HABridge {
|
||||
private static SystemControl theSystem;
|
||||
|
||||
/*
|
||||
* This program is based on the work of armzilla from this github repository:
|
||||
@@ -36,30 +40,47 @@ public class HABridge {
|
||||
UDPDatagramSender udpSender;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
SystemControl theSystem;
|
||||
BridgeSettings bridgeSettings;
|
||||
Version theVersion;
|
||||
|
||||
theVersion = new Version();
|
||||
@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
|
||||
staticFileLocation("/public");
|
||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
bridgeSettings.buildSettings();
|
||||
log.info("HA Bridge initializing....");
|
||||
log.info("HA Bridge (v{}) initializing....", theVersion.getVersion() );
|
||||
bridgeSettings.buildSettings();
|
||||
if(bridgeSettings.getBridgeSecurity().isUseHttps()) {
|
||||
secure(bridgeSettings.getBridgeSecurity().getKeyfilePath(), bridgeSettings.getBridgeSecurity().getKeyfilePassword(), null, null);
|
||||
log.info("Using https for web and api calls");
|
||||
}
|
||||
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||
// sparkjava config directive to set ip address for the web server to listen on
|
||||
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
||||
// sparkjava config directive to set port for the web server to listen on
|
||||
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
staticFileLocation("/public");
|
||||
initExceptionHandler((e) -> HABridge.theExceptionHandler(e, bridgeSettings.getBridgeSettingsDescriptor().getServerPort()));
|
||||
if(!bridgeSettings.getBridgeControl().isReinit())
|
||||
init();
|
||||
bridgeSettings.getBridgeControl().setReinit(false);
|
||||
// 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) {
|
||||
@@ -71,23 +92,38 @@ public class HABridge {
|
||||
homeManager.buildHomes(bridgeSettings, udpSender);
|
||||
// setup the class to handle the resource setup rest api
|
||||
theResources = new DeviceResource(bridgeSettings, homeManager);
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
theSettingResponder.setupServer();
|
||||
// setup the class to handle the hue emulator rest api
|
||||
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), homeManager);
|
||||
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), theResources.getGroupRepository(), homeManager);
|
||||
theHueMulator.setupServer();
|
||||
// wait for the sparkjava initialization of the rest api classes to be complete
|
||||
awaitInitialization();
|
||||
|
||||
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp()) {
|
||||
log.info("Traceupnp: upnp config address: {} -useIface: {} on web server: {}:{}",
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
}
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||
theSettingResponder.setupServer();
|
||||
|
||||
// start the upnp ssdp discovery listener
|
||||
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender);
|
||||
if(theUpnpListener.startListening())
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
||||
theUpnpListener = null;
|
||||
try {
|
||||
theUpnpListener = new UpnpListener(bridgeSettings, bridgeSettings.getBridgeControl(), udpSender);
|
||||
} catch (IOException e) {
|
||||
log.error("Could not initialize UpnpListener, exiting....", e);
|
||||
theUpnpListener = null;
|
||||
}
|
||||
if(theUpnpListener != null && theUpnpListener.startListening())
|
||||
log.info("HA Bridge (v{}) reinitialization requessted....", theVersion.getVersion());
|
||||
else
|
||||
bridgeSettings.getBridgeControl().setStop(true);
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
log.info("Going to close all homes");
|
||||
homeManager.closeHomes();
|
||||
udpSender.closeResponseSocket();
|
||||
udpSender = null;
|
||||
@@ -97,15 +133,34 @@ public class HABridge {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
log.error("Sleep error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||
if(bridgeSettings.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettings.updateConfigFile();
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||
try {
|
||||
HttpClientPool.shutdown();
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||
} catch (IOException e) {
|
||||
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||
}
|
||||
thePool = null;
|
||||
log.info("HA Bridge (v{}) exiting....", theVersion.getVersion());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static void theExceptionHandler(Exception e, Integer thePort) {
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
if(e.getMessage().equals("no valid keystore") || e.getMessage().equals("keystore password was incorrect")) {
|
||||
log.error("Https settings have been removed as {}. Restart system manually after this process exits....", e.getMessage());
|
||||
log.warn(theSystem.removeHttpsSettings());
|
||||
}
|
||||
else {
|
||||
log.error("Could not start ha-bridge webservice on port [{}] due to: {}", thePort, e.getMessage());
|
||||
log.warn(theSystem.stop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,35 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
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;
|
||||
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 {
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeManager.class);
|
||||
Map<String, Home> homeList;
|
||||
Map<String, Home> resourceList;
|
||||
|
||||
@@ -33,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);
|
||||
@@ -63,16 +82,14 @@ public class HomeManager {
|
||||
aHome = new HassHome(bridgeSettings);
|
||||
resourceList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
homeList.put(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
// Setup the HomeWizard configuration if available
|
||||
aHome = new HomeWizardHome(bridgeSettings);
|
||||
resourceList.put(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
homeList.put(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
//setup the command execution Home
|
||||
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);
|
||||
//setup the tcp handler Home
|
||||
aHome = new TCPHome(bridgeSettings);
|
||||
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
@@ -85,11 +102,15 @@ public class HomeManager {
|
||||
aHome = new VeraHome(bridgeSettings);
|
||||
resourceList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
resourceList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||
// Setup Fibaro Home if available
|
||||
aHome = new FibaroHome(bridgeSettings);
|
||||
resourceList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
resourceList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
|
||||
//setup the Domoticz configuration if available
|
||||
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);
|
||||
@@ -97,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) {
|
||||
@@ -107,8 +148,10 @@ public class HomeManager {
|
||||
}
|
||||
|
||||
public void closeHomes() {
|
||||
log.info("Manager close homes called....");
|
||||
Collection<Home> theHomes = homeList.values();
|
||||
for(Home aHome : theHomes) {
|
||||
log.info("Closing home: " + aHome.getClass().getCanonicalName());
|
||||
aHome.closeHome();
|
||||
}
|
||||
homeList.clear();
|
||||
|
||||
@@ -10,15 +10,18 @@ public class LinkButtonPressed extends TimerTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(LinkButtonPressed.class);
|
||||
private BridgeControlDescriptor linkDescriptor;
|
||||
private Timer myTimer;
|
||||
private boolean isSilent;
|
||||
|
||||
public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer) {
|
||||
public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer, boolean keepSilent) {
|
||||
linkDescriptor = theDescriptor;
|
||||
myTimer = aTimer;
|
||||
isSilent = keepSilent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("Link button time ended....");
|
||||
if(!isSilent)
|
||||
log.info("Link button time ended....");
|
||||
linkDescriptor.setLinkButton(false);
|
||||
myTimer.cancel();
|
||||
}
|
||||
|
||||
20
src/main/java/com/bwssystems/HABridge/LinkParams.java
Normal file
20
src/main/java/com/bwssystems/HABridge/LinkParams.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
public class LinkParams {
|
||||
private Integer seconds;
|
||||
private boolean silent;
|
||||
|
||||
public Integer getSeconds() {
|
||||
return seconds;
|
||||
}
|
||||
public void setSeconds(Integer seconds) {
|
||||
this.seconds = seconds;
|
||||
}
|
||||
public boolean isSilent() {
|
||||
return silent;
|
||||
}
|
||||
public void setSilent(boolean silent) {
|
||||
this.silent = silent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +1,113 @@
|
||||
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;
|
||||
private String webhook;
|
||||
private String ip;
|
||||
private String webhook;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ public class SecurityInfo {
|
||||
private boolean useLinkButton;
|
||||
private boolean secureHueApi;
|
||||
private boolean isSecure;
|
||||
private String execGarden;
|
||||
private boolean useHttps;
|
||||
private String keyfilePath;
|
||||
private String keyfilePassword;
|
||||
|
||||
public boolean isUseLinkButton() {
|
||||
return useLinkButton;
|
||||
@@ -23,4 +27,36 @@ public class SecurityInfo {
|
||||
public void setSecure(boolean isSecure) {
|
||||
this.isSecure = isSecure;
|
||||
}
|
||||
|
||||
public boolean isUseHttps() {
|
||||
return useHttps;
|
||||
}
|
||||
|
||||
public void setUseHttps(boolean useHttps) {
|
||||
this.useHttps = useHttps;
|
||||
}
|
||||
|
||||
public String getKeyfilePath() {
|
||||
return keyfilePath;
|
||||
}
|
||||
|
||||
public void setKeyfilePath(String keyfilePath) {
|
||||
this.keyfilePath = keyfilePath;
|
||||
}
|
||||
|
||||
public String getExecGarden() {
|
||||
return execGarden;
|
||||
}
|
||||
|
||||
public void setExecGarden(String execGarden) {
|
||||
this.execGarden = execGarden;
|
||||
}
|
||||
|
||||
public String getKeyfilePassword() {
|
||||
return keyfilePassword;
|
||||
}
|
||||
|
||||
public void setKeyfilePassword(String keyfilePassword) {
|
||||
this.keyfilePassword = keyfilePassword;
|
||||
}
|
||||
}
|
||||
|
||||
48
src/main/java/com/bwssystems/HABridge/ShutdownHook.java
Normal file
48
src/main/java/com/bwssystems/HABridge/ShutdownHook.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class implements the shutdown hook used to properly stop server from the
|
||||
* command line (sending SIGTERM), or while shutting down the host machine.
|
||||
*
|
||||
* @author gaudryc
|
||||
*/
|
||||
public class ShutdownHook extends Thread {
|
||||
|
||||
private final BridgeSettings bridgeSettings;
|
||||
private final SystemControl theSystem;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bridgeSettings
|
||||
* bridge settings
|
||||
* @param theSystem
|
||||
*/
|
||||
public ShutdownHook(final BridgeSettings bridgeSettings, final SystemControl theSystem) {
|
||||
this.bridgeSettings = bridgeSettings;
|
||||
this.theSystem = theSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Logger log = LoggerFactory.getLogger(ShutdownHook.class);
|
||||
log.info("Shutdown requested...");
|
||||
if (bridgeSettings != null) {
|
||||
if (!bridgeSettings.getBridgeControl().isStop() && (theSystem != null)) {
|
||||
log.info("Forcing system stop...");
|
||||
theSystem.stop();
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Sleep error: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
log.info("Already stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,19 +8,26 @@ import static spark.Spark.before;
|
||||
import static spark.Spark.halt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.DatagramPacket;
|
||||
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;
|
||||
import com.bwssystems.HABridge.util.TextStringFormatter;
|
||||
@@ -28,10 +35,12 @@ import com.bwssystems.logservices.LoggerInfo;
|
||||
import com.bwssystems.logservices.LoggingForm;
|
||||
import com.bwssystems.logservices.LoggingManager;
|
||||
import com.google.gson.Gson;
|
||||
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 {
|
||||
@@ -51,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();
|
||||
}
|
||||
@@ -84,7 +93,7 @@ public class SystemControl {
|
||||
String logMsgs;
|
||||
int count = -1;
|
||||
if(cyclicBufferAppender == null)
|
||||
reacquireCBA();
|
||||
setupLoggerSettings();
|
||||
if (cyclicBufferAppender != null) {
|
||||
count = cyclicBufferAppender.getLength();
|
||||
}
|
||||
@@ -234,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);
|
||||
@@ -245,10 +272,22 @@ public class SystemControl {
|
||||
});
|
||||
// http://ip_address:port/system/presslinkbutton which sets the link button for device registration
|
||||
put(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> {
|
||||
log.info("Link button pressed....");
|
||||
LinkParams linkParams = null;
|
||||
if(!request.body().isEmpty()) {
|
||||
linkParams = new Gson().fromJson(request.body(), LinkParams.class);
|
||||
if(linkParams.getSeconds() <= 0)
|
||||
linkParams.setSeconds(3);
|
||||
}
|
||||
else {
|
||||
linkParams = new LinkParams();
|
||||
linkParams.setSilent(false);
|
||||
linkParams.setSeconds(bridgeSettings.getBridgeSettingsDescriptor().getLinkbuttontimeout());
|
||||
}
|
||||
if(!linkParams.isSilent())
|
||||
log.info("Link button pressed....");
|
||||
bridgeSettings.getBridgeControl().setLinkButton(true);
|
||||
Timer theTimer = new Timer();
|
||||
theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer), 30000);
|
||||
theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer, linkParams.isSilent()), (linkParams.getSeconds() * 1000));
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return "";
|
||||
@@ -275,14 +314,43 @@ public class SystemControl {
|
||||
post(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||
log.debug("changesecurityinfo....");
|
||||
SecurityInfo theInfo = new Gson().fromJson(request.body(), SecurityInfo.class);
|
||||
bridgeSettings.getBridgeSecurity().setUseLinkButton(theInfo.isUseLinkButton());
|
||||
bridgeSettings.getBridgeSecurity().setSecureHueApi(theInfo.isSecureHueApi());
|
||||
bridgeSettings.getBridgeSecurity().setSecurityDataByInfo(theInfo);
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/whitelist gets the whitelist for the bridge
|
||||
get (SYSTEM_CONTEXT + "/whitelist", (request, response) -> {
|
||||
log.debug("Get whitelist");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSecurity().getWhitelist();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/setwhitelist CORS request
|
||||
options(SYSTEM_CONTEXT + "/setwhitelist", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/setwhitelist which sets the whitelist after being managed
|
||||
post(SYSTEM_CONTEXT + "/setwhitelist", (request, response) -> {
|
||||
log.debug("setwhitelist....");
|
||||
Type listType = new TypeToken<Map<String, WhitelistEntry>>() {
|
||||
}.getType();
|
||||
Map<String, WhitelistEntry> aWhitelist = new Gson().fromJson(request.body(), listType);
|
||||
bridgeSettings.getBridgeSecurity().setWhitelist(aWhitelist);
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSecurity().getWhitelist();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/logmgmt/update CORS request
|
||||
options(SYSTEM_CONTEXT + "/logmgmt/update", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
@@ -310,6 +378,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());
|
||||
|
||||
@@ -326,6 +396,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");
|
||||
@@ -364,6 +436,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");
|
||||
@@ -436,11 +543,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 {
|
||||
@@ -460,7 +598,12 @@ public class SystemControl {
|
||||
log.warn("Error pinging listener. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String removeHttpsSettings() {
|
||||
bridgeSettings.getBridgeSecurity().removeHttpsSettings();
|
||||
return stop();
|
||||
}
|
||||
|
||||
public String reinit() {
|
||||
bridgeSettings.getBridgeControl().setReinit(true);
|
||||
pingListener();
|
||||
@@ -472,4 +615,5 @@ public class SystemControl {
|
||||
pingListener();
|
||||
return "{\"control\":\"stopping\"}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
@@ -14,6 +15,9 @@ public class DeviceResponse {
|
||||
private String luminaireuniqueid;
|
||||
private String uniqueid;
|
||||
private String swversion;
|
||||
private String swconfigid;
|
||||
private String productid;
|
||||
private String productname;
|
||||
|
||||
public DeviceState getState() {
|
||||
return state;
|
||||
@@ -71,6 +75,31 @@ public class DeviceResponse {
|
||||
this.swversion = swversion;
|
||||
}
|
||||
|
||||
public String getSwconfigid() {
|
||||
return swconfigid;
|
||||
}
|
||||
|
||||
public void setSwconfigid(String swconfigid) {
|
||||
this.swconfigid = swconfigid;
|
||||
}
|
||||
|
||||
public String getProductid() {
|
||||
return productid;
|
||||
}
|
||||
|
||||
public void setProductid(String productid) {
|
||||
this.productid = productid;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productname;
|
||||
}
|
||||
|
||||
public void setProductName(String productname) {
|
||||
this.productname = productname;
|
||||
}
|
||||
|
||||
|
||||
public String getLuminaireuniqueid() {
|
||||
return luminaireuniqueid;
|
||||
}
|
||||
@@ -86,11 +115,43 @@ public class DeviceResponse {
|
||||
response.setName(device.getName());
|
||||
response.setUniqueid(device.getUniqueid());
|
||||
response.setManufacturername("Philips");
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB004");
|
||||
response.setSwversion("66012040");
|
||||
|
||||
if (device.isColorDevice()) {
|
||||
response.setType("Extended color light");
|
||||
response.setModelid("LCT015");
|
||||
response.setSwversion("1.46.13_r26312");
|
||||
response.setSwconfigid("52E3234B");
|
||||
response.setProductid("Philips-LCT015-1-A19ECLv5");
|
||||
response.setProductName("Hue color lamp");
|
||||
} else {
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB007");
|
||||
response.setSwversion("66012040");
|
||||
}
|
||||
|
||||
response.setLuminaireuniqueid(null);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static DeviceResponse createResponseForVirtualLight(GroupDescriptor group){
|
||||
DeviceResponse response = new DeviceResponse();
|
||||
response.setState(group.getAction());
|
||||
|
||||
response.setName(group.getName());
|
||||
response.setUniqueid("00:11:22:33:44:55:66:77-" + String.format("%02X", Integer.parseInt(group.getId())));
|
||||
response.setManufacturername("Philips");
|
||||
response.setType("Extended color light");
|
||||
response.setModelid("LCT015");
|
||||
response.setSwversion("1.46.13_r26312");
|
||||
response.setSwconfigid("52E3234B");
|
||||
response.setProductid("Philips-LCT015-1-A19ECLv5");
|
||||
response.setProductName("Hue color lamp");
|
||||
|
||||
response.setLuminaireuniqueid(null);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
// import java.util.ArrayList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -9,14 +9,15 @@ import java.util.List;
|
||||
public class DeviceState {
|
||||
private boolean on;
|
||||
private int bri;
|
||||
private int hue;
|
||||
private int sat;
|
||||
private Integer hue;
|
||||
private Integer sat;
|
||||
private String effect;
|
||||
private int ct;
|
||||
private List<Double> xy;
|
||||
private Integer ct;
|
||||
private String alert;
|
||||
private String colormode;
|
||||
private boolean reachable;
|
||||
private List<Double> xy;
|
||||
|
||||
// private int transitiontime;
|
||||
|
||||
public boolean isOn() {
|
||||
@@ -36,19 +37,21 @@ public class DeviceState {
|
||||
}
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
return hue != null ? hue.intValue() : 0;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
this.colormode = "hs";
|
||||
}
|
||||
|
||||
public int getSat() {
|
||||
return sat;
|
||||
return sat != null ? sat.intValue() : 0;
|
||||
}
|
||||
|
||||
public void setSat(int sat) {
|
||||
this.sat = sat;
|
||||
this.colormode = "hs";
|
||||
}
|
||||
|
||||
public String getEffect() {
|
||||
@@ -60,11 +63,12 @@ public class DeviceState {
|
||||
}
|
||||
|
||||
public int getCt() {
|
||||
return ct;
|
||||
return ct != null ? ct.intValue() : 0;
|
||||
}
|
||||
|
||||
public void setCt(int ct) {
|
||||
this.ct = ct;
|
||||
this.colormode = "ct";
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
@@ -97,6 +101,7 @@ public class DeviceState {
|
||||
|
||||
public void setXy(List<Double> xy) {
|
||||
this.xy = xy;
|
||||
this.colormode = "xy";
|
||||
}
|
||||
// public int getTransitiontime() {
|
||||
// return transitiontime;
|
||||
@@ -106,22 +111,28 @@ public class DeviceState {
|
||||
// this.transitiontime = transitiontime;
|
||||
// }
|
||||
|
||||
public static DeviceState createDeviceState() {
|
||||
public static DeviceState createDeviceState(boolean color) {
|
||||
DeviceState newDeviceState = new DeviceState();
|
||||
newDeviceState.fillIn();
|
||||
// newDeviceState.setColormode("none");
|
||||
// ArrayList<Double> doubleArray = new ArrayList<Double>();
|
||||
// doubleArray.add(new Double(0));
|
||||
// doubleArray.add(new Double(0));
|
||||
// newDeviceState.setXy(doubleArray);
|
||||
|
||||
newDeviceState.fillIn(color);
|
||||
if (color) {
|
||||
newDeviceState.setColormode("xy");
|
||||
newDeviceState.setHue(0);
|
||||
newDeviceState.setSat(0);
|
||||
newDeviceState.setCt(153);
|
||||
ArrayList<Double> doubleArray = new ArrayList<Double>();
|
||||
doubleArray.add(0.3146);
|
||||
doubleArray.add(0.3303);
|
||||
newDeviceState.setXy(doubleArray);
|
||||
}
|
||||
return newDeviceState;
|
||||
}
|
||||
public void fillIn() {
|
||||
public void fillIn(boolean color) {
|
||||
if(this.getAlert() == null)
|
||||
this.setAlert("none");
|
||||
if(this.getEffect() == null)
|
||||
this.setEffect("none");
|
||||
if (color) {
|
||||
if(this.getEffect() == null)
|
||||
this.setEffect("none");
|
||||
}
|
||||
this.setReachable(true);
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GroupClassTypes {
|
||||
|
||||
public final static String BATHROOM = "Bathroom";
|
||||
public final static String BEDROOM = "Bedroom";
|
||||
public final static String CARPORT = "Carport";
|
||||
public final static String DINING = "Dining";
|
||||
public final static String DRIVEWAY = "Driveway";
|
||||
public final static String FRONT_DOOR = "Front door";
|
||||
public final static String GARAGE = "Garage";
|
||||
public final static String GARDEN = "Garden";
|
||||
public final static String GYM = "Gym";
|
||||
public final static String HALLWAY = "Hallway";
|
||||
public final static String BEDROOM_KIDS = "Kids bedroom";
|
||||
public final static String KITCHEN = "Kitchen";
|
||||
public final static String LIVING_ROOM = "Living room";
|
||||
public final static String NURSERY = "Nursery";
|
||||
public final static String OFFICE = "Office";
|
||||
public final static String OTHER = "Other";
|
||||
public final static String RECREATION = "Recreation";
|
||||
public final static String TERRACE = "Terrace";
|
||||
public final static String TOILET = "Toilet";
|
||||
|
||||
ArrayList<String> groupClassTypes;
|
||||
|
||||
public GroupClassTypes() {
|
||||
groupClassTypes = new ArrayList<String>();
|
||||
groupClassTypes.add(BATHROOM);
|
||||
groupClassTypes.add(BEDROOM);
|
||||
groupClassTypes.add(CARPORT);
|
||||
groupClassTypes.add(DINING);
|
||||
groupClassTypes.add(DRIVEWAY);
|
||||
groupClassTypes.add(FRONT_DOOR);
|
||||
groupClassTypes.add(GARAGE);
|
||||
groupClassTypes.add(GARDEN);
|
||||
groupClassTypes.add(GYM);
|
||||
groupClassTypes.add(HALLWAY);
|
||||
groupClassTypes.add(BEDROOM_KIDS);
|
||||
groupClassTypes.add(KITCHEN);
|
||||
groupClassTypes.add(LIVING_ROOM);
|
||||
groupClassTypes.add(NURSERY);
|
||||
groupClassTypes.add(OFFICE);
|
||||
groupClassTypes.add(OTHER);
|
||||
groupClassTypes.add(RECREATION);
|
||||
groupClassTypes.add(TERRACE);
|
||||
groupClassTypes.add(TOILET);
|
||||
}
|
||||
|
||||
public Boolean validateType(String type) {
|
||||
if(type == null || type.trim().isEmpty())
|
||||
return false;
|
||||
for(String classType : groupClassTypes) {
|
||||
if(type.trim().contentEquals(classType))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class GroupResponse {
|
||||
@@ -16,6 +16,8 @@ public class GroupResponse {
|
||||
private String type;
|
||||
@SerializedName("class")
|
||||
String class_name;
|
||||
@SerializedName("state")
|
||||
private GroupState state;
|
||||
|
||||
public DeviceState getAction() {
|
||||
return action;
|
||||
@@ -23,6 +25,14 @@ public class GroupResponse {
|
||||
public void setAction(DeviceState action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public GroupState getState() {
|
||||
return state;
|
||||
}
|
||||
public void setState(GroupState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String[] getLights() {
|
||||
return lights;
|
||||
}
|
||||
@@ -48,34 +58,69 @@ public class GroupResponse {
|
||||
public void setClass_name(String class_name) {
|
||||
this.class_name = class_name;
|
||||
}
|
||||
public static GroupResponse createDefaultGroupResponse(List<DeviceDescriptor> deviceList) {
|
||||
String[] theList = new String[deviceList.size()];
|
||||
int i = 0;
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
theList[i] = device.getId();
|
||||
i++;
|
||||
}
|
||||
GroupResponse theResponse = new GroupResponse();
|
||||
theResponse.setAction(DeviceState.createDeviceState());
|
||||
theResponse.setName("Lightset 0");
|
||||
theResponse.setLights(theList);
|
||||
theResponse.setType("LightGroup");
|
||||
return theResponse;
|
||||
}
|
||||
public static GroupResponse createOtherGroupResponse(List<DeviceDescriptor> deviceList) {
|
||||
String[] theList = new String[deviceList.size()];
|
||||
int i = 0;
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
theList[i] = device.getId();
|
||||
i++;
|
||||
}
|
||||
GroupResponse theResponse = new GroupResponse();
|
||||
theResponse.setAction(DeviceState.createDeviceState());
|
||||
theResponse.setName("AGroup");
|
||||
theResponse.setLights(theList);
|
||||
theResponse.setType("Room");
|
||||
theResponse.setClass_name("Other");
|
||||
|
||||
public static GroupResponse createDefaultGroupResponse(Map<String, DeviceResponse> deviceList) {
|
||||
String[] theList = new String[deviceList.size()];
|
||||
Boolean all_on = true;
|
||||
Boolean any_on = false;
|
||||
int i = 0;
|
||||
for (Map.Entry<String, DeviceResponse> device : deviceList.entrySet()) {
|
||||
if (Integer.parseInt(device.getKey()) >= 10000) { // don't show fake lights for other groups
|
||||
continue;
|
||||
}
|
||||
theList[i] = device.getKey();
|
||||
Boolean is_on = device.getValue().getState().isOn();
|
||||
if (is_on)
|
||||
any_on = true;
|
||||
else
|
||||
all_on = false;
|
||||
i++;
|
||||
}
|
||||
GroupResponse theResponse = new GroupResponse();
|
||||
theResponse.setAction(DeviceState.createDeviceState(true));
|
||||
theResponse.setState(new GroupState(all_on, any_on));
|
||||
theResponse.setName("Group 0");
|
||||
theResponse.setLights(theList);
|
||||
theResponse.setType("LightGroup");
|
||||
return theResponse;
|
||||
}
|
||||
|
||||
return theResponse;
|
||||
}
|
||||
public static GroupResponse createResponse(GroupDescriptor group, Map<String, DeviceResponse> lights){
|
||||
GroupResponse response = new GroupResponse();
|
||||
Boolean all_on = true;
|
||||
Boolean any_on = false;
|
||||
String[] groupLights = null;
|
||||
if (lights == null) {
|
||||
all_on = false;
|
||||
groupLights = group.getLights();
|
||||
} else {
|
||||
for (DeviceResponse light : lights.values()) {
|
||||
Boolean is_on = light.getState().isOn();
|
||||
if (is_on)
|
||||
any_on = true;
|
||||
else
|
||||
all_on = false;
|
||||
}
|
||||
|
||||
// group.getLights() is not filtered by requester, lights is
|
||||
// we want the filtered version but keep the order from group.getLights()
|
||||
groupLights = new String[lights.size()];
|
||||
int i = 0;
|
||||
for (String light : group.getLights()) {
|
||||
if (lights.keySet().contains(light)) {
|
||||
groupLights[i] = light;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.setState(new GroupState(all_on, any_on));
|
||||
response.setAction(group.getAction());
|
||||
response.setName(group.getName());
|
||||
response.setType(group.getGroupType());
|
||||
response.setLights(groupLights);
|
||||
response.setClass_name(group.getGroupClass());
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
/**
|
||||
* Created by Florian Foerderreuther on 07/23/17
|
||||
*/
|
||||
public class GroupState {
|
||||
private boolean all_on;
|
||||
private boolean any_on;
|
||||
|
||||
public boolean isAllOn() {
|
||||
return all_on;
|
||||
}
|
||||
|
||||
public boolean isAnyOn() {
|
||||
return any_on;
|
||||
}
|
||||
|
||||
public void setState(boolean all_on, boolean any_on) {
|
||||
this.all_on = all_on;
|
||||
this.any_on = any_on;
|
||||
}
|
||||
|
||||
public GroupState(boolean all_on, boolean any_on) {
|
||||
this.all_on = all_on;
|
||||
this.any_on = any_on;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GroupState{" +
|
||||
"all_on=" + all_on +
|
||||
", any_on=" + any_on +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ public class HueApiResponse {
|
||||
private Map<String, JsonObject> rules;
|
||||
private HueConfig config;
|
||||
|
||||
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion) {
|
||||
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) {
|
||||
super();
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion));
|
||||
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion, isLinkButtonPressed, emulateMAC));
|
||||
this.setRules(new HashMap<>());
|
||||
this.setSensors(new HashMap<>());
|
||||
this.setSchedules(new HashMap<>());
|
||||
|
||||
@@ -34,7 +34,7 @@ public class HueConfig
|
||||
private String replacesbridgeid;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
|
||||
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion) {
|
||||
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) {
|
||||
HueConfig aConfig = new HueConfig();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
@@ -44,7 +44,7 @@ public class HueConfig
|
||||
aConfig.setPortalservices(false);
|
||||
aConfig.setGateway(ipaddress);
|
||||
aConfig.setSwversion(emulateHubVersion);
|
||||
aConfig.setLinkbutton(true);
|
||||
aConfig.setLinkbutton(isLinkButtonPressed);
|
||||
aConfig.setIpaddress(ipaddress);
|
||||
aConfig.setProxyport(0);
|
||||
aConfig.setSwupdate(Swupdate.createSwupdate());
|
||||
@@ -56,7 +56,7 @@ public class HueConfig
|
||||
aConfig.setLocaltime(dateFormat.format(new Date()));
|
||||
aConfig.setTimezone(TimeZone.getDefault().getID());
|
||||
aConfig.setZigbeechannel("6");
|
||||
aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion).getHueBridgeIdFromMac());
|
||||
aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion, emulateMAC).getHueBridgeIdFromMac());
|
||||
aConfig.setModelid(HueConstants.MODEL_ID);
|
||||
aConfig.setFactorynew(false);
|
||||
aConfig.setReplacesbridgeid(null);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueConstants {
|
||||
public final static String HUB_VERSION = "01036659";
|
||||
public final static String API_VERSION = "1.15.0";
|
||||
public final static String HUB_VERSION = "9999999999";
|
||||
public final static String API_VERSION = "1.17.0";
|
||||
public final static String MODEL_ID = "BSB002";
|
||||
public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-";
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ public class HuePublicConfig
|
||||
private Boolean factorynew;
|
||||
private String modelid;
|
||||
|
||||
public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion) {
|
||||
public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion, String emulateMAC) {
|
||||
HuePublicConfig aConfig = new HuePublicConfig();
|
||||
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
|
||||
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress, emulateMAC));
|
||||
aConfig.setApiversion(HueConstants.API_VERSION);
|
||||
aConfig.setSwversion(emulateHubVersion);
|
||||
aConfig.setName(name);
|
||||
@@ -32,34 +32,39 @@ public class HuePublicConfig
|
||||
return aConfig;
|
||||
}
|
||||
|
||||
private static String getMacAddress(String addr)
|
||||
private static String getMacAddress(String addr, String aMAC)
|
||||
{
|
||||
InetAddress ip;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
if(aMAC == null || aMAC.trim().length() <= 0) {
|
||||
try {
|
||||
|
||||
ip = InetAddress.getByName(addr);
|
||||
|
||||
ip = InetAddress.getByName(addr);
|
||||
|
||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||
}
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (SocketException e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (Exception e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||
}
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (SocketException e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
} catch (Exception e){
|
||||
|
||||
sb.append("00:00:88:00:bb:ee");
|
||||
|
||||
}
|
||||
else {
|
||||
sb.append(aMAC.trim());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ public class DeviceDescriptor{
|
||||
@SerializedName("onUrl")
|
||||
@Expose
|
||||
private String onUrl;
|
||||
@SerializedName("colorUrl")
|
||||
@Expose
|
||||
private String colorUrl;
|
||||
@SerializedName("headers")
|
||||
@Expose
|
||||
private String headers;
|
||||
@@ -74,9 +77,28 @@ public class DeviceDescriptor{
|
||||
@SerializedName("comments")
|
||||
@Expose
|
||||
private String comments;
|
||||
|
||||
@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;
|
||||
@SerializedName("dimNoOn")
|
||||
@Expose
|
||||
private boolean dimNoOn;
|
||||
@SerializedName("dimOnColor")
|
||||
@Expose
|
||||
private boolean dimOnColor;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -141,6 +163,14 @@ public class DeviceDescriptor{
|
||||
this.onUrl = onUrl;
|
||||
}
|
||||
|
||||
public String getColorUrl() {
|
||||
return colorUrl;
|
||||
}
|
||||
|
||||
public void setColorUrl(String colorUrl) {
|
||||
this.colorUrl = colorUrl;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -207,7 +237,7 @@ public class DeviceDescriptor{
|
||||
|
||||
public DeviceState getDeviceState() {
|
||||
if(deviceState == null)
|
||||
deviceState = DeviceState.createDeviceState();
|
||||
deviceState = DeviceState.createDeviceState(this.isColorDevice());
|
||||
return deviceState;
|
||||
}
|
||||
|
||||
@@ -263,6 +293,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;
|
||||
@@ -281,7 +327,54 @@ public class DeviceDescriptor{
|
||||
|
||||
if(this.offUrl != null && this.offUrl.contains(aType))
|
||||
return true;
|
||||
|
||||
if(this.colorUrl != null && this.colorUrl.contains(aType))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isColorDevice() {
|
||||
boolean color = true;
|
||||
if ((deviceType == null || !deviceType.trim().equals("passthru")) && (colorUrl == null || colorUrl.trim().equals(""))) {
|
||||
color = false;
|
||||
} else if (deviceType != null && deviceType.trim().equals("passthru")) {
|
||||
if (deviceState != null && (deviceState.getColormode() == null || deviceState.getColormode().equals(""))) {
|
||||
color = false;
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public boolean isLockDeviceId() {
|
||||
return lockDeviceId;
|
||||
}
|
||||
|
||||
public void setLockDeviceId(boolean lockDeviceId) {
|
||||
this.lockDeviceId = lockDeviceId;
|
||||
}
|
||||
|
||||
public String getStartupActions() {
|
||||
return startupActions;
|
||||
}
|
||||
|
||||
public void setStartupActions(String startupActions) {
|
||||
this.startupActions = startupActions;
|
||||
}
|
||||
|
||||
public boolean isDimNoOn() {
|
||||
return dimNoOn;
|
||||
}
|
||||
|
||||
public void setDimNoOn(boolean dimNoOn) {
|
||||
this.dimNoOn = dimNoOn;
|
||||
}
|
||||
|
||||
public boolean isDimOnColor() {
|
||||
return dimOnColor;
|
||||
}
|
||||
|
||||
public void setDimOnColor(boolean dimOnColor) {
|
||||
this.dimOnColor = dimOnColor;
|
||||
}
|
||||
}
|
||||
@@ -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,62 +11,79 @@ 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.dao.DeviceDescriptor;
|
||||
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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/*
|
||||
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
||||
* loading.
|
||||
*/
|
||||
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 boolean uidnineoctets;
|
||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
|
||||
public DeviceRepository(String deviceDb, Integer seedid, boolean uidnineoctets_setting) {
|
||||
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;
|
||||
uidnineoctets = uidnineoctets_setting;
|
||||
_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++) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nextId = nextId + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DeviceDescriptor> findAll() {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
return list;
|
||||
@@ -76,8 +91,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;
|
||||
@@ -85,17 +100,21 @@ public class DeviceRepository extends BackupHandler {
|
||||
|
||||
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
return findAllByRequester(anAddress, list);
|
||||
}
|
||||
|
||||
private List<DeviceDescriptor> findAllByRequester(String anAddress, Collection<DeviceDescriptor> list) {
|
||||
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
|
||||
Iterator<DeviceDescriptor> anIterator = list.iterator();
|
||||
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) {
|
||||
@@ -110,116 +129,235 @@ public class DeviceRepository extends BackupHandler {
|
||||
return theReturnList;
|
||||
}
|
||||
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||
HueHome myHueHome, Gson aGsonBuilder) {
|
||||
return findAllByGroupWithState(lightsInGroup, anAddress, myHueHome, aGsonBuilder, false);
|
||||
}
|
||||
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||
HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) {
|
||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||
Map<String, DeviceDescriptor> lights = new HashMap<String, DeviceDescriptor>(devices);
|
||||
lights.keySet().retainAll(Arrays.asList(lightsInGroup));
|
||||
for (DeviceDescriptor light : (ignoreAddress ? lights.values()
|
||||
: findAllByRequester(anAddress, lights.values()))) {
|
||||
DeviceResponse deviceResponse = null;
|
||||
if (!light.isInactive()) {
|
||||
if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
CallItem[] callItems = null;
|
||||
try {
|
||||
if (light.getOnUrl() != null)
|
||||
callItems = aGsonBuilder.fromJson(light.getOnUrl(), CallItem[].class);
|
||||
} catch (JsonSyntaxException e) {
|
||||
log.warn("Could not decode Json for url items to get Hue state for device: {}",
|
||||
light.getName());
|
||||
callItems = null;
|
||||
}
|
||||
|
||||
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||
if ((callItems[i].getType() != null
|
||||
&& callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]))
|
||||
|| (callItems[i].getItem() != null && callItems[i].getItem().getAsString() != null
|
||||
&& callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], light);
|
||||
i = callItems.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceResponse == null) {
|
||||
deviceResponse = DeviceResponse.createResponse(light);
|
||||
}
|
||||
deviceResponseMap.put(light.getId(), deviceResponse);
|
||||
}
|
||||
}
|
||||
return (deviceResponseMap.size() == 0) ? null : deviceResponseMap;
|
||||
}
|
||||
|
||||
public DeviceDescriptor findOne(String id) {
|
||||
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);
|
||||
|
||||
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
||||
}
|
||||
put(descriptors[i].getId(), descriptors[i]);
|
||||
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||
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) {
|
||||
descriptors[i].setUniqueid(hueUniqueId(Integer.valueOf(descriptors[i].getId())));
|
||||
}
|
||||
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>();
|
||||
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));
|
||||
theDevice.setUniqueid(hueUniqueId(nextId));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private String hueUniqueId(Integer anId) {
|
||||
String theUniqueId = null;
|
||||
Integer newValue;
|
||||
String hexValueLeft;
|
||||
String hexValueRight;
|
||||
|
||||
MessageDigest md = null;
|
||||
|
||||
try {
|
||||
md = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.warn("Cannot get MD5 utility to hash unique ids.");
|
||||
}
|
||||
|
||||
if (md != null) {
|
||||
md.update(anId.toString().getBytes());
|
||||
byte[] digest = md.digest();
|
||||
if (uidnineoctets) {
|
||||
theUniqueId = String.format("00:%s:%s:%s:%s:%s:%s:%s-%s",
|
||||
HexLibrary.encodeHexString(digest).substring(0, 2),
|
||||
HexLibrary.encodeHexString(digest).substring(2, 4),
|
||||
HexLibrary.encodeHexString(digest).substring(4, 6),
|
||||
HexLibrary.encodeHexString(digest).substring(6, 8),
|
||||
HexLibrary.encodeHexString(digest).substring(8, 10),
|
||||
HexLibrary.encodeHexString(digest).substring(10, 12),
|
||||
HexLibrary.encodeHexString(digest).substring(12, 14),
|
||||
HexLibrary.encodeHexString(digest).substring(14, 16));
|
||||
|
||||
} else {
|
||||
theUniqueId = String.format("%s:%s:%s:%s:%s:%s:%s-%s",
|
||||
HexLibrary.encodeHexString(digest).substring(0, 2),
|
||||
HexLibrary.encodeHexString(digest).substring(2, 4),
|
||||
HexLibrary.encodeHexString(digest).substring(4, 6),
|
||||
HexLibrary.encodeHexString(digest).substring(6, 8),
|
||||
HexLibrary.encodeHexString(digest).substring(8, 10),
|
||||
HexLibrary.encodeHexString(digest).substring(10, 12),
|
||||
HexLibrary.encodeHexString(digest).substring(12, 14),
|
||||
HexLibrary.encodeHexString(digest).substring(14, 16));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (theUniqueId == null) {
|
||||
newValue = anId % 256;
|
||||
if (newValue <= 0)
|
||||
newValue = 1;
|
||||
else if (newValue > 255)
|
||||
newValue = 255;
|
||||
hexValueLeft = HexLibrary.byteToHex(newValue.byteValue());
|
||||
newValue = anId / 256;
|
||||
newValue = newValue % 256;
|
||||
if (newValue < 0)
|
||||
newValue = 0;
|
||||
else if (newValue > 255)
|
||||
newValue = 255;
|
||||
hexValueRight = HexLibrary.byteToHex(newValue.byteValue());
|
||||
|
||||
theUniqueId = String.format("11:22:33:44:55:66:%s-%s", hexValueLeft, hexValueRight).toUpperCase();
|
||||
}
|
||||
return theUniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
147
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
147
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
@@ -0,0 +1,147 @@
|
||||
package com.bwssystems.HABridge.dao;
|
||||
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.bwssystems.HABridge.api.hue.GroupState;
|
||||
|
||||
/*
|
||||
* Object to handle the device configuration
|
||||
*/
|
||||
public class GroupDescriptor{
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
private String id;
|
||||
@SerializedName("name")
|
||||
@Expose
|
||||
private String name;
|
||||
@SerializedName("groupType")
|
||||
@Expose
|
||||
private String groupType;
|
||||
@SerializedName("groupClass")
|
||||
@Expose
|
||||
private String groupClass;
|
||||
@SerializedName("requesterAddress")
|
||||
@Expose
|
||||
private String requesterAddress;
|
||||
@SerializedName("inactive")
|
||||
@Expose
|
||||
private boolean inactive;
|
||||
@SerializedName("description")
|
||||
@Expose
|
||||
private String description;
|
||||
@SerializedName("comments")
|
||||
@Expose
|
||||
private String comments;
|
||||
|
||||
private DeviceState action;
|
||||
private GroupState groupState;
|
||||
|
||||
@SerializedName("lights")
|
||||
@Expose
|
||||
private String[] lights;
|
||||
@SerializedName("exposeAsLight")
|
||||
@Expose
|
||||
private String exposeAsLight;
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getGroupType() {
|
||||
return groupType;
|
||||
}
|
||||
|
||||
public void setGroupType(String groupType) {
|
||||
this.groupType = groupType;
|
||||
}
|
||||
|
||||
public String getGroupClass() {
|
||||
return groupClass;
|
||||
}
|
||||
|
||||
public void setGroupClass(String groupClass) {
|
||||
this.groupClass = groupClass;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public GroupState getGroupState() {
|
||||
if(groupState == null)
|
||||
groupState = new GroupState(false,false);
|
||||
return groupState;
|
||||
}
|
||||
|
||||
public void setGroupState(GroupState groupState) {
|
||||
this.groupState = groupState;
|
||||
}
|
||||
|
||||
public DeviceState getAction() {
|
||||
if(action == null)
|
||||
action = DeviceState.createDeviceState(true);
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(DeviceState action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public boolean isInactive() {
|
||||
return inactive;
|
||||
}
|
||||
|
||||
public void setInactive(boolean inactive) {
|
||||
this.inactive = inactive;
|
||||
}
|
||||
|
||||
public String getRequesterAddress() {
|
||||
return requesterAddress;
|
||||
}
|
||||
|
||||
public void setRequesterAddress(String requesterAddress) {
|
||||
this.requesterAddress = requesterAddress;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getComments() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public void setComments(String comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
|
||||
public String[] getLights() {
|
||||
return lights;
|
||||
}
|
||||
|
||||
public void setLights(String[] lights) {
|
||||
this.lights = lights;
|
||||
}
|
||||
|
||||
public void setExposeAsLight(String exposeFor) {
|
||||
this.exposeAsLight = exposeFor;
|
||||
}
|
||||
|
||||
public String getExposeAsLight() {
|
||||
return exposeAsLight;
|
||||
}
|
||||
}
|
||||
224
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
224
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
@@ -0,0 +1,224 @@
|
||||
package com.bwssystems.HABridge.dao;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||
import com.bwssystems.HABridge.util.BackupHandler;
|
||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
/*
|
||||
* This is an in memory list to manage the configured groups and saves the list as a JSON string to a file for later
|
||||
* loading.
|
||||
*/
|
||||
public class GroupRepository extends BackupHandler {
|
||||
private Map<String, GroupDescriptor> groups;
|
||||
private Path repositoryPath;
|
||||
private Gson gson;
|
||||
private Integer nextId;
|
||||
private Logger log = LoggerFactory.getLogger(GroupRepository.class);
|
||||
|
||||
public GroupRepository(String groupDb) {
|
||||
super();
|
||||
gson =
|
||||
new GsonBuilder()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
nextId = 0;
|
||||
try {
|
||||
repositoryPath = null;
|
||||
repositoryPath = Paths.get(groupDb);
|
||||
setupParams(repositoryPath, ".bk", "group.db-");
|
||||
_loadRepository(repositoryPath);
|
||||
} catch (Exception ex) {
|
||||
groups = new HashMap<String, GroupDescriptor>();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadRepository() {
|
||||
if(repositoryPath != null)
|
||||
_loadRepository(repositoryPath);
|
||||
}
|
||||
private void _loadRepository(Path aPath){
|
||||
String jsonContent = repositoryReader(aPath);
|
||||
groups = new HashMap<String, GroupDescriptor>();
|
||||
|
||||
if(jsonContent != null)
|
||||
{
|
||||
GroupDescriptor list[] = gson.fromJson(jsonContent, GroupDescriptor[].class);
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
list[i].setGroupState(null);
|
||||
put(list[i].getId(), list[i]);
|
||||
if(Integer.decode(list[i].getId()) > nextId) {
|
||||
nextId = Integer.decode(list[i].getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<GroupDescriptor> findAll() {
|
||||
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<GroupDescriptor> findActive() {
|
||||
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
|
||||
for(GroupDescriptor aGroup : new ArrayList<GroupDescriptor>(groups.values())) {
|
||||
if(!aGroup.isInactive())
|
||||
list.add(aGroup);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<GroupDescriptor> findAllByRequester(String anAddress) {
|
||||
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
|
||||
List<GroupDescriptor> theReturnList = new ArrayList<GroupDescriptor>();
|
||||
Iterator<GroupDescriptor> anIterator = list.iterator();
|
||||
GroupDescriptor theGroup;
|
||||
String theRequesterAddress;
|
||||
|
||||
HashMap<String,String > addressMap;
|
||||
while (anIterator.hasNext()) {
|
||||
theGroup = anIterator.next();
|
||||
theRequesterAddress = theGroup.getRequesterAddress();
|
||||
addressMap = new HashMap<String, String>();
|
||||
if(theRequesterAddress != null) {
|
||||
if (theRequesterAddress.contains(",")) {
|
||||
String[] theArray = theRequesterAddress.split(",");
|
||||
for (String v : theArray) {
|
||||
addressMap.put(v.trim(), v.trim());
|
||||
}
|
||||
} else
|
||||
addressMap.put(theRequesterAddress, theRequesterAddress);
|
||||
}
|
||||
if (theRequesterAddress == null || theRequesterAddress.length() == 0 || addressMap.containsKey(anAddress))
|
||||
theReturnList.add(theGroup);
|
||||
}
|
||||
return theReturnList;
|
||||
}
|
||||
|
||||
public List<GroupDescriptor> findVirtualLights(String anAddress) {
|
||||
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
|
||||
for (GroupDescriptor group : groups.values()) {
|
||||
String expose = group.getExposeAsLight();
|
||||
if (expose != null && expose.contains(anAddress)) {
|
||||
list.add(group);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public GroupDescriptor findOne(String id) {
|
||||
return groups.get(id);
|
||||
}
|
||||
|
||||
private void put(String id, GroupDescriptor aDescriptor) {
|
||||
groups.put(id, aDescriptor);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
save(groups.values().toArray(new GroupDescriptor[0]));
|
||||
}
|
||||
|
||||
public void save(GroupDescriptor[] descriptors) {
|
||||
String theNames = "";
|
||||
for(int i = 0; i < descriptors.length; i++) {
|
||||
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||
groups.remove(descriptors[i].getId());
|
||||
else {
|
||||
nextId++;
|
||||
descriptors[i].setId(String.valueOf(nextId));
|
||||
}
|
||||
|
||||
put(descriptors[i].getId(), descriptors[i]);
|
||||
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||
}
|
||||
String jsonValue = gson.toJson(findAll());
|
||||
repositoryWriter(jsonValue, repositoryPath);
|
||||
log.debug("Save group(s): " + theNames);
|
||||
}
|
||||
|
||||
public Integer getNewId() {
|
||||
return nextId + 1;
|
||||
}
|
||||
|
||||
public String delete(GroupDescriptor aDescriptor) {
|
||||
if (aDescriptor != null) {
|
||||
groups.remove(aDescriptor.getId());
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
String jsonValue = aRenderer.render(findAll());
|
||||
repositoryWriter(jsonValue, repositoryPath);
|
||||
return "Group with id '" + aDescriptor.getId() + "' deleted";
|
||||
} else {
|
||||
return "Group not found";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void repositoryWriter(String content, Path filePath) {
|
||||
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||
log.error("Error file is not writable: " + filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Files.notExists(filePath.getParent())) {
|
||||
try {
|
||||
Files.createDirectories(filePath.getParent());
|
||||
} catch (IOException e) {
|
||||
log.error("Error creating the directory: " + filePath + " message: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Path target = null;
|
||||
if(Files.exists(filePath)) {
|
||||
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "group.db.old");
|
||||
Files.move(filePath, target);
|
||||
}
|
||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||
if(target != null)
|
||||
Files.delete(target);
|
||||
} catch (IOException e) {
|
||||
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String repositoryReader(Path filePath) {
|
||||
|
||||
String content = null;
|
||||
if(Files.notExists(filePath)){
|
||||
log.debug("Error, the file: " + filePath + " - does not exist. continuing...");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!Files.isReadable(filePath)){
|
||||
log.warn("Error, the file: " + filePath + " - is not readable. continuing...");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
content = new String(Files.readAllBytes(filePath));
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||
import com.bwssystems.HABridge.dao.GroupRepository;
|
||||
import com.bwssystems.HABridge.dao.ErrorMessage;
|
||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||
import com.google.gson.Gson;
|
||||
@@ -38,16 +39,20 @@ public class DeviceResource {
|
||||
private static final String API_CONTEXT = "/api/devices";
|
||||
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
||||
private DeviceRepository deviceRepository;
|
||||
private GroupRepository groupRepository;
|
||||
private HomeManager homeManager;
|
||||
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(), bridgeSettings.getBridgeSettingsDescriptor().isUidnineoctets());
|
||||
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
|
||||
homeManager = aHomeManager;
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
errorMessage = null;
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
@@ -55,6 +60,10 @@ public class DeviceResource {
|
||||
return deviceRepository;
|
||||
}
|
||||
|
||||
public GroupRepository getGroupRepository() {
|
||||
return groupRepository;
|
||||
}
|
||||
|
||||
private void setupEndpoints() {
|
||||
log.info("HABridge device management service started.... ");
|
||||
before(API_CONTEXT + "/*", (request, response) -> {
|
||||
@@ -76,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);
|
||||
@@ -84,14 +93,14 @@ public class DeviceResource {
|
||||
else {
|
||||
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
||||
}
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -101,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 {
|
||||
@@ -110,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 {
|
||||
@@ -119,13 +128,22 @@ 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 {
|
||||
if(devices[i].getColorUrl() != null && !devices[i].getColorUrl().isEmpty())
|
||||
callItems = aGsonHandler.fromJson(devices[i].getColorUrl(), CallItem[].class);
|
||||
} catch(JsonSyntaxException e) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad color URL JSON in create device(s) for name: " + devices[i].getName() + " with color URL: " + devices[i].getColorUrl();
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -143,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());
|
||||
@@ -170,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);
|
||||
@@ -189,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
|
||||
{
|
||||
@@ -214,6 +237,18 @@ public class DeviceResource {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return homeManager.findResource(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex]);
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/fibaro/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get fibaro devices");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]);
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/fibaro/scenes", "application/json", (request, response) -> {
|
||||
log.debug("Get fibaro scenes");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex]);
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||
log.debug("Get harmony activities");
|
||||
@@ -262,6 +297,12 @@ public class DeviceResource {
|
||||
return homeManager.findResource(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HASS_DEVICE[DeviceMapTypes.typeIndex]);
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/homewizard/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get HomeWizard Clients");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return homeManager.findResource(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]);
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/domoticz/devices", "application/json", (request, response) -> {
|
||||
log.debug("Get Domoticz Clients");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
@@ -280,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);
|
||||
@@ -301,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);
|
||||
@@ -316,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()));
|
||||
@@ -333,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());
|
||||
@@ -352,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());
|
||||
|
||||
@@ -2,4 +2,5 @@ package com.bwssystems.HABridge.devicemanagmeent;
|
||||
|
||||
public interface ResourceHandler {
|
||||
public Object getItems(String type);
|
||||
public void refresh();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.hue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.Conversion;
|
||||
@@ -20,12 +21,15 @@ public class BrightnessDecode {
|
||||
private static final String INTENSITY_MATH_CLOSE_HEX = ").hex}";
|
||||
private static final String INTENSITY_PERCENT_HEX = "${intensity.percent.hex}";
|
||||
private static final String INTENSITY_BYTE_HEX = "${intensity.byte.hex}";
|
||||
private static final String INTENSITY_PREVIOUS_PERCENT = "${intensity.previous_percent}";
|
||||
private static final String INTENSITY_PREVIOUS_DECIMAL_PERCENT = "${intensity.previous_decimal_percent}";
|
||||
private static final String INTENSITY_PREVIOUS_BYTE = "${intensity.previous_byte}";
|
||||
|
||||
public static int calculateIntensity(int setIntensity, Integer targetBri, Integer targetBriInc) {
|
||||
if (targetBri != null) {
|
||||
setIntensity = targetBri;
|
||||
} else if (targetBriInc != null) {
|
||||
if ((setIntensity + targetBriInc) <= 0)
|
||||
if ((setIntensity + targetBriInc) <= 1)
|
||||
setIntensity = targetBriInc;
|
||||
else if ((setIntensity + targetBriInc) > 254)
|
||||
setIntensity = targetBriInc;
|
||||
@@ -44,18 +48,42 @@ public class BrightnessDecode {
|
||||
* intensity.math(X*1) : where X is the value from the interface call and
|
||||
* can use net.java.dev.eval math
|
||||
*/
|
||||
public static String replaceIntensityValue(String request, int intensity, boolean isHex) {
|
||||
private static String replaceIntensityValue(String request, int previous_intensity, int intensity, boolean isHex) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
boolean notDone = true;
|
||||
String replaceValue = null;
|
||||
String replaceTarget = null;
|
||||
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
|
||||
float decimalBrightness = (float) (intensity / 255.0);
|
||||
int percentBrightness = 0;
|
||||
float decimalBrightness = (float) 1.0;
|
||||
int previousPercentBrightness = 0;
|
||||
float previousDecimalBrightness = (float) 1.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) 1.0;
|
||||
percentBrightness = 1;
|
||||
}
|
||||
|
||||
if(previous_intensity > 0) {
|
||||
previousDecimalBrightness = (float) (previous_intensity / 255.0);
|
||||
if(previous_intensity > 0 && previous_intensity < 5)
|
||||
previousPercentBrightness = 1;
|
||||
else
|
||||
previousPercentBrightness = (int) Math.round(previous_intensity / 255.0 * 100);
|
||||
} else {
|
||||
previousDecimalBrightness = (float) 1.0;
|
||||
previousPercentBrightness = 1;
|
||||
}
|
||||
|
||||
while(notDone) {
|
||||
notDone = false;
|
||||
if (request.contains(INTENSITY_BYTE)) {
|
||||
@@ -66,6 +94,14 @@ public class BrightnessDecode {
|
||||
}
|
||||
replaceTarget = INTENSITY_BYTE;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_PREVIOUS_BYTE)) {
|
||||
if (isHex) {
|
||||
replaceValue = convertToHex(previous_intensity);
|
||||
} else {
|
||||
replaceValue = String.valueOf(previous_intensity);
|
||||
}
|
||||
replaceTarget = INTENSITY_PREVIOUS_BYTE;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_BYTE_HEX)) {
|
||||
replaceValue = convertToHex(intensity);
|
||||
replaceTarget = INTENSITY_BYTE_HEX;
|
||||
@@ -78,14 +114,26 @@ public class BrightnessDecode {
|
||||
}
|
||||
replaceTarget = INTENSITY_PERCENT;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_PREVIOUS_PERCENT)) {
|
||||
if (isHex) {
|
||||
replaceValue = convertToHex(previousPercentBrightness);
|
||||
} else {
|
||||
replaceValue = String.valueOf(previousPercentBrightness);
|
||||
}
|
||||
replaceTarget = INTENSITY_PREVIOUS_PERCENT;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_PERCENT_HEX)) {
|
||||
replaceValue = convertToHex(percentBrightness);
|
||||
replaceTarget = INTENSITY_PERCENT_HEX;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
|
||||
replaceValue = String.format("%1.2f", decimalBrightness);
|
||||
replaceValue = String.format(Locale.ROOT, "%1.2f", decimalBrightness);
|
||||
replaceTarget = INTENSITY_DECIMAL_PERCENT;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_PREVIOUS_DECIMAL_PERCENT)) {
|
||||
replaceValue = String.format(Locale.ROOT, "%1.2f", previousDecimalBrightness);
|
||||
replaceTarget = INTENSITY_PREVIOUS_DECIMAL_PERCENT;
|
||||
notDone = true;
|
||||
} else if (request.contains(INTENSITY_MATH_CLOSE)) {
|
||||
mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
|
||||
request.indexOf(INTENSITY_MATH_CLOSE));
|
||||
@@ -110,11 +158,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;
|
||||
}
|
||||
@@ -127,7 +171,7 @@ public class BrightnessDecode {
|
||||
|
||||
// Helper Method
|
||||
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
|
||||
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
|
||||
return replaceIntensityValue(request, theIntensity, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
|
||||
}
|
||||
|
||||
// Apache Commons Conversion utils likes little endian too much
|
||||
|
||||
954
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
954
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
@@ -0,0 +1,954 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
/**
|
||||
* Convert between different color spaces supported.
|
||||
* RGB -> CMYK -> RGB
|
||||
* RGB -> YIQ -> RGB
|
||||
* RGB -> YCbCr -> RGB
|
||||
* RGB -> YUV -> RGB
|
||||
* RGB -> RGChromaticity
|
||||
* RGB -> HSV -> RGB
|
||||
* RGB -> YCC -> RGB
|
||||
* RGB -> YCoCg -> RGB
|
||||
* RGB -> XYZ -> RGB
|
||||
* RGB -> HunterLAB -> RGB
|
||||
* RGB -> HLS -> RGB
|
||||
* RGB -> CIE-LAB -> RGB
|
||||
* XYZ -> HunterLAB -> XYZ
|
||||
* XYZ -> CIE-LAB -> XYZ
|
||||
* @author Diego Catalano
|
||||
*/
|
||||
|
||||
|
||||
public class ColorConverter {
|
||||
|
||||
/**
|
||||
* Don't let anyone instantiate this class.
|
||||
*/
|
||||
private ColorConverter() {}
|
||||
|
||||
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
|
||||
private final static double EPSILON = 0.00001;
|
||||
|
||||
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
|
||||
|
||||
//2o Observer (CIE 1931)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE2_A = {109.850f, 100f, 35.585f}; //Incandescent
|
||||
public static float[] CIE2_C = {98.074f, 100f, 118.232f};
|
||||
public static float[] CIE2_D50 = {96.422f, 100f, 82.521f};
|
||||
public static float[] CIE2_D55 = {95.682f, 100f, 92.149f};
|
||||
public static float[] CIE2_D65 = {95.047f, 100f, 108.883f}; //Daylight
|
||||
public static float[] CIE2_D75 = {94.972f, 100f, 122.638f};
|
||||
public static float[] CIE2_F2 = {99.187f, 100f, 67.395f}; //Fluorescent
|
||||
public static float[] CIE2_F7 = {95.044f, 100f, 108.755f};
|
||||
public static float[] CIE2_F11 = {100.966f, 100f, 64.370f};
|
||||
|
||||
//10o Observer (CIE 1964)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE10_A = {111.144f, 100f, 35.200f}; //Incandescent
|
||||
public static float[] CIE10_C = {97.285f, 100f, 116.145f};
|
||||
public static float[] CIE10_D50 = {96.720f, 100f, 81.427f};
|
||||
public static float[] CIE10_D55 = {95.799f, 100f, 90.926f};
|
||||
public static float[] CIE10_D65 = {94.811f, 100f, 107.304f}; //Daylight
|
||||
public static float[] CIE10_D75 = {94.416f, 100f, 120.641f};
|
||||
public static float[] CIE10_F2 = {103.280f, 100f, 69.026f}; //Fluorescent
|
||||
public static float[] CIE10_F7 = {95.792f, 100f, 107.687f};
|
||||
public static float[] CIE10_F11 = {103.866f, 100f, 65.627f};
|
||||
|
||||
/**
|
||||
* RFB -> CMYK
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return CMYK color space. Normalized.
|
||||
*/
|
||||
public static float[] RGBtoCMYK(int red, int green, int blue){
|
||||
float[] cmyk = new float[4];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float k = 1.0f - Math.max(r, Math.max(g, b));
|
||||
float c = (1f-r-k) / (1f-k);
|
||||
float m = (1f-g-k) / (1f-k);
|
||||
float y = (1f-b-k) / (1f-k);
|
||||
|
||||
cmyk[0] = c;
|
||||
cmyk[1] = m;
|
||||
cmyk[2] = y;
|
||||
cmyk[3] = k;
|
||||
|
||||
return cmyk;
|
||||
}
|
||||
|
||||
/**
|
||||
* CMYK -> RGB
|
||||
* @param c Cyan.
|
||||
* @param m Magenta.
|
||||
* @param y Yellow.
|
||||
* @param k Black.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] CMYKtoRGB(float c, float m, float y, float k){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
rgb[0] = (int)(255 * (1-c) * (1-k));
|
||||
rgb[1] = (int)(255 * (1-m) * (1-k));
|
||||
rgb[2] = (int)(255 * (1-y) * (1-k));
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YUV.
|
||||
* Y in the range [0..1].
|
||||
* U in the range [-0.5..0.5].
|
||||
* V in the range [-0.5..0.5].
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YUV color space.
|
||||
*/
|
||||
public static float[] RGBtoYUV(int red, int green, int blue){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] yuv = new float[3];
|
||||
float y,u,v;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
u = (float)(-0.14713 * r - 0.28886 * g + 0.436 * b);
|
||||
v = (float)(0.615 * r - 0.51499 * g - 0.10001 * b);
|
||||
|
||||
yuv[0] = y;
|
||||
yuv[1] = u;
|
||||
yuv[2] = v;
|
||||
|
||||
return yuv;
|
||||
}
|
||||
|
||||
/**
|
||||
* YUV -> RGB.
|
||||
* @param y Luma. In the range [0..1].
|
||||
* @param u Chrominance. In the range [-0.5..0.5].
|
||||
* @param v Chrominance. In the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YUVtoRGB(float y, float u, float v){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
r = (float)((y + 0.000 * u + 1.140 * v) * 255);
|
||||
g = (float)((y - 0.396 * u - 0.581 * v) * 255);
|
||||
b = (float)((y + 2.029 * u + 0.000 * v) * 255);
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YIQ.
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YIQ color space.
|
||||
*/
|
||||
public static float[] RGBtoYIQ(int red, int green, int blue){
|
||||
float[] yiq = new float[3];
|
||||
float y,i,q;
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
i = (float)(0.596 * r - 0.275 * g - 0.322 * b);
|
||||
q = (float)(0.212 * r - 0.523 * g + 0.311 * b);
|
||||
|
||||
yiq[0] = y;
|
||||
yiq[1] = i;
|
||||
yiq[2] = q;
|
||||
|
||||
return yiq;
|
||||
}
|
||||
|
||||
/**
|
||||
* YIQ -> RGB.
|
||||
* @param y Luma. Values in the range [0..1].
|
||||
* @param i In-phase. Values in the range [-0.5..0.5].
|
||||
* @param q Quadrature. Values in the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YIQtoRGB(double y, double i, double q){
|
||||
int[] rgb = new int[3];
|
||||
int r,g,b;
|
||||
|
||||
r = (int)((y + 0.956 * i + 0.621 * q) * 255);
|
||||
g = (int)((y - 0.272 * i - 0.647 * q) * 255);
|
||||
b = (int)((y - 1.105 * i + 1.702 * q) * 255);
|
||||
|
||||
r = Math.max(0,Math.min(255,r));
|
||||
g = Math.max(0,Math.min(255,g));
|
||||
b = Math.max(0,Math.min(255,b));
|
||||
|
||||
rgb[0] = r;
|
||||
rgb[1] = g;
|
||||
rgb[2] = b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
public static float[] RGBtoYCbCr(int red, int green, int blue, YCbCrColorSpace colorSpace){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] YCbCr = new float[3];
|
||||
float y,cb,cr;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
cb = (float)(-0.169 * r - 0.331 * g + 0.500 * b);
|
||||
cr = (float)(0.500 * r - 0.419 * g - 0.081 * b);
|
||||
}
|
||||
else{
|
||||
y = (float)(0.2215 * r + 0.7154 * g + 0.0721 * b);
|
||||
cb = (float)(-0.1145 * r - 0.3855 * g + 0.5000 * b);
|
||||
cr = (float)(0.5016 * r - 0.4556 * g - 0.0459 * b);
|
||||
}
|
||||
|
||||
YCbCr[0] = (float)y;
|
||||
YCbCr[1] = (float)cb;
|
||||
YCbCr[2] = (float)cr;
|
||||
|
||||
return YCbCr;
|
||||
}
|
||||
|
||||
public static int[] YCbCrtoRGB(float y, float cb, float cr, YCbCrColorSpace colorSpace){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
r = (float)(y + 0.000 * cb + 1.403 * cr) * 255;
|
||||
g = (float)(y - 0.344 * cb - 0.714 * cr) * 255;
|
||||
b = (float)(y + 1.773 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
else{
|
||||
r = (float)(y + 0.000 * cb + 1.5701 * cr) * 255;
|
||||
g = (float)(y - 0.1870 * cb - 0.4664 * cr) * 255;
|
||||
b = (float)(y + 1.8556 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rg-Chromaticity space is already known to remove ambiguities due to illumination or surface pose.
|
||||
* @see Neural Information Processing - Chi Sing Leung. p. 668
|
||||
* @param red Red coefficient.
|
||||
* @param green Green coefficient.
|
||||
* @param blue Blue coefficient.
|
||||
* @return Normalized RGChromaticity. Range[0..1].
|
||||
*/
|
||||
public static float[] RGChromaticity(int red, int green, int blue){
|
||||
double[] color = new double[5];
|
||||
|
||||
double sum = red + green + blue;
|
||||
|
||||
//red
|
||||
color[0] = red / sum;
|
||||
|
||||
//green
|
||||
color[1] = green / sum;
|
||||
|
||||
//blue
|
||||
color[2] = 1 - color[0] - color[1];
|
||||
|
||||
double rS = color[0] - 0.333;
|
||||
double gS = color[1] - 0.333;
|
||||
|
||||
//saturationBRGBtoHSV(int red, int green, int blue){
|
||||
float[] hsv = new float[3];
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float max = Math.max(r, Math.max(g, b));
|
||||
float min = Math.min(r, Math.min(g, b));
|
||||
float delta = max - min;
|
||||
|
||||
// Hue
|
||||
if (max == min){
|
||||
hsv[0] = 0;
|
||||
}
|
||||
else if (max == r){
|
||||
hsv[0] = ((g - b) / delta) * 60f;
|
||||
}
|
||||
else if (max == g){
|
||||
hsv[0] = ((b - r) / delta + 2f) * 60f;
|
||||
}
|
||||
else if (max == b){
|
||||
hsv[0] = ((r - g) / delta + 4f) * 60f;
|
||||
}
|
||||
|
||||
// Saturation
|
||||
if (delta == 0)
|
||||
hsv[1] = 0;
|
||||
else
|
||||
hsv[1] = delta / max;
|
||||
|
||||
//Value
|
||||
hsv[2] = max;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
/**
|
||||
* HSV -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation. In the range[0..1].
|
||||
* @param value Value. In the range[0..1].
|
||||
* @return RGB color space. In the range[0..255].
|
||||
*/
|
||||
public static int[] HSVtoRGB(float hue, float saturation, float value){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float hi = (float)Math.floor(hue / 60.0) % 6;
|
||||
float f = (float)((hue / 60.0) - Math.floor(hue / 60.0));
|
||||
float p = (float)(value * (1.0 - saturation));
|
||||
float q = (float)(value * (1.0 - (f * saturation)));
|
||||
float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));
|
||||
|
||||
if (hi == 0){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(t * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 1){
|
||||
rgb[0] = (int)(q * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 2){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(t * 255);
|
||||
}
|
||||
else if (hi == 3){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
else if (hi == 4){
|
||||
rgb[0] = (int)(t * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 5){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(p * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCC.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCC color space. In the range [0..1].
|
||||
*/
|
||||
public static float[] RGBtoYCC(int red, int green, int blue){
|
||||
float[] ycc = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = 0.213f * r + 0.419f * g + 0.081f * b;
|
||||
float c1 = -0.131f * r - 0.256f * g + 0.387f * b + 0.612f;
|
||||
float c2 = 0.373f * r - 0.312f * r - 0.061f * b + 0.537f;
|
||||
|
||||
ycc[0] = y;
|
||||
ycc[1] = c1;
|
||||
ycc[2] = c2;
|
||||
|
||||
return ycc;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCC -> RGB.
|
||||
* @param y Y coefficient.
|
||||
* @param c1 C coefficient.
|
||||
* @param c2 C coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCCtoRGB(float y, float c1, float c2){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = 0.981f * y + 1.315f * (c2 - 0.537f);
|
||||
float g = 0.981f * y - 0.311f * (c1 - 0.612f)- 0.669f * (c2 - 0.537f);
|
||||
float b = 0.981f * y + 1.601f * (c1 - 0.612f);
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCoCg.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCoCg color space.
|
||||
*/
|
||||
public static float[] RGBtoYCoCg(int red, int green, int blue){
|
||||
float[] yCoCg = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = r / 4f + g / 2f + b / 4f;
|
||||
float co = r / 2f - b / 2f;
|
||||
float cg = -r / 4f + g / 2f - b / 4f;
|
||||
|
||||
yCoCg[0] = y;
|
||||
yCoCg[1] = co;
|
||||
yCoCg[2] = cg;
|
||||
|
||||
return yCoCg;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCoCg -> RGB.
|
||||
* @param y Pseudo luminance, or intensity.
|
||||
* @param co Orange chrominance.
|
||||
* @param cg Green chrominance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCoCgtoRGB(float y, float co, float cg){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = y + co - cg;
|
||||
float g = y + cg;
|
||||
float b = y - co - cg;
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> XYZ
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] RGBtoXYZ(int red, int green, int blue){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
//R
|
||||
if ( r > 0.04045)
|
||||
r = (float)Math.pow(( ( r + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
r /= 12.92f;
|
||||
|
||||
//G
|
||||
if ( g > 0.04045)
|
||||
g = (float)Math.pow(( ( g + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
g /= 12.92f;
|
||||
|
||||
//B
|
||||
if ( b > 0.04045)
|
||||
b = (float)Math.pow(( ( b + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
b /= 12.92f;
|
||||
|
||||
r *= 100;
|
||||
g *= 100;
|
||||
b *= 100;
|
||||
|
||||
float x = 0.412453f * r + 0.35758f * g + 0.180423f * b;
|
||||
float y = 0.212671f * r + 0.71516f * g + 0.072169f * b;
|
||||
float z = 0.019334f * r + 0.119193f * g + 0.950227f * b;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> RGB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] XYZtoRGB(float x, float y, float z){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
x /= 100;
|
||||
y /= 100;
|
||||
z /= 100;
|
||||
|
||||
float r = 3.240479f * x - 1.53715f * y - 0.498535f * z;
|
||||
float g = -0.969256f * x + 1.875991f * y + 0.041556f * z;
|
||||
float b = 0.055648f * x - 0.204043f * y + 1.057311f * z;
|
||||
|
||||
if ( r > 0.0031308 )
|
||||
r = 1.055f * ( (float)Math.pow(r, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
r = 12.92f * r;
|
||||
|
||||
if ( g > 0.0031308 )
|
||||
g = 1.055f * ( (float)Math.pow(g, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
g = 12.92f * g;
|
||||
|
||||
if ( b > 0.0031308 )
|
||||
b = 1.055f * ( (float)Math.pow(b, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
b = 12.92f * b;
|
||||
|
||||
rgb[0] = (int)(r * 255);
|
||||
rgb[1] = (int)(g * 255);
|
||||
rgb[2] = (int)(b * 255);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> HunterLAB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return HunterLab coefficient.
|
||||
*/
|
||||
public static float[] XYZtoHunterLAB(float x, float y, float z){
|
||||
float[] hunter = new float[3];
|
||||
|
||||
|
||||
float sqrt = (float)Math.sqrt(y);
|
||||
|
||||
float l = 10 * sqrt;
|
||||
float a = 17.5f * (((1.02f * x) - y) / sqrt);
|
||||
float b = 7f * ((y - (0.847f * z)) / sqrt);
|
||||
|
||||
hunter[0] = l;
|
||||
hunter[1] = a;
|
||||
hunter[2] = b;
|
||||
|
||||
return hunter;
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> XYZ
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] HunterLABtoXYZ(float l, float a, float b){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
|
||||
float tempY = l / 10f;
|
||||
float tempX = a / 17.5f * l / 10f;
|
||||
float tempZ = b / 7f * l / 10f;
|
||||
|
||||
float y = tempY * tempY;
|
||||
float x = (tempX + y) / 1.02f;
|
||||
float z = -(tempZ - y) / 0.847f;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HunterLAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HunterLAB color space.
|
||||
*/
|
||||
public static float[] RGBtoHunterLAB(int red, int green, int blue){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
return XYZtoHunterLAB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HunterLABtoRGB(float l, float a, float b){
|
||||
float[] xyz = HunterLABtoXYZ(l, a, b);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HSL.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HSL color space.
|
||||
*/
|
||||
public static float[] RGBtoHSL(int red, int green, int blue){
|
||||
float[] hsl = new float[3];
|
||||
|
||||
double r = red;
|
||||
double g = green;
|
||||
double b = blue;
|
||||
|
||||
double max = Math.max(r,Math.max(g,b));
|
||||
double min = Math.min(r,Math.min(g,b));
|
||||
// double delta = max - min;
|
||||
|
||||
//HSK
|
||||
Double h = 0d;
|
||||
Double s = 0d;
|
||||
Double l = 0d;
|
||||
|
||||
//saturation
|
||||
double cnt = (max + min) / 2d;
|
||||
if (cnt <= 127d) {
|
||||
s = ((max - min) / (max + min));
|
||||
}
|
||||
else {
|
||||
s = ((max - min) / (510d - max - min));
|
||||
}
|
||||
|
||||
//lightness
|
||||
l = ((max + min) / 2d) / 255d;
|
||||
|
||||
//hue
|
||||
if (Math.abs(max - min) <= EPSILON) {
|
||||
h = 0d;
|
||||
s = 0d;
|
||||
}
|
||||
else {
|
||||
double diff = max - min;
|
||||
|
||||
if (Math.abs(max - r) <= EPSILON) {
|
||||
h = 60d * (g - b) / diff;
|
||||
}
|
||||
else if (Math.abs(max - g) <= EPSILON) {
|
||||
h = 60d * (b - r) / diff + 120d;
|
||||
}
|
||||
else {
|
||||
h = 60d * (r - g) / diff + 240d;
|
||||
}
|
||||
|
||||
if (h < 0d) {
|
||||
h += 360d;
|
||||
}
|
||||
}
|
||||
|
||||
hsl[0] = h.floatValue();
|
||||
hsl[1] = s.floatValue();
|
||||
hsl[2] = l.floatValue();
|
||||
|
||||
return hsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* HLS -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation.
|
||||
* @param luminance Luminance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HSLtoRGB(float hue, float saturation, float luminance){
|
||||
int[] rgb = new int[3];
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
if ( saturation == 0 )
|
||||
{
|
||||
// gray values
|
||||
r = g = b = (int) ( luminance * 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
float v1, v2;
|
||||
float h = (float) hue / 360;
|
||||
|
||||
v2 = ( luminance < 0.5 ) ?
|
||||
( luminance * ( 1 + saturation ) ) :
|
||||
( ( luminance + saturation ) - ( luminance * saturation ) );
|
||||
v1 = 2 * luminance - v2;
|
||||
|
||||
r = (int) ( 255 * Hue_2_RGB( v1, v2, h + ( 1.0f / 3 ) ) );
|
||||
g = (int) ( 255 * Hue_2_RGB( v1, v2, h ) );
|
||||
b = (int) ( 255 * Hue_2_RGB( v1, v2, h - ( 1.0f / 3 ) ) );
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static float Hue_2_RGB( float v1, float v2, float vH ){
|
||||
if ( vH < 0 )
|
||||
vH += 1;
|
||||
if ( vH > 1 )
|
||||
vH -= 1;
|
||||
if ( ( 6 * vH ) < 1 )
|
||||
return ( v1 + ( v2 - v1 ) * 6 * vH );
|
||||
if ( ( 2 * vH ) < 1 )
|
||||
return v2;
|
||||
if ( ( 3 * vH ) < 2 )
|
||||
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
|
||||
return v1;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> CIE-LAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] RGBtoLAB(int red, int green, int blue, float[] tristimulus){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
float[] lab = XYZtoLAB(xyz[0], xyz[1], xyz[2], tristimulus);
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] LABtoRGB(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = LABtoXYZ(l, a, b, tristimulus);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> CIE-LAB.
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] XYZtoLAB(float x, float y, float z, float[] tristimulus){
|
||||
float[] lab = new float[3];
|
||||
|
||||
x /= tristimulus[0];
|
||||
y /= tristimulus[1];
|
||||
z /= tristimulus[2];
|
||||
|
||||
if (x > 0.008856)
|
||||
x = (float)Math.pow(x,0.33f);
|
||||
else
|
||||
x = (7.787f * x) + ( 0.1379310344827586f );
|
||||
|
||||
if (y > 0.008856)
|
||||
y = (float)Math.pow(y,0.33f);
|
||||
else
|
||||
y = (7.787f * y) + ( 0.1379310344827586f );
|
||||
|
||||
if (z > 0.008856)
|
||||
z = (float)Math.pow(z,0.33f);
|
||||
else
|
||||
z = (7.787f * z) + ( 0.1379310344827586f );
|
||||
|
||||
lab[0] = ( 116 * y ) - 16;
|
||||
lab[1] = 500 * ( x - y );
|
||||
lab[2] = 200 * ( y - z );
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> XYZ.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] LABtoXYZ(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float y = ( l + 16f ) / 116f;
|
||||
float x = a / 500f + y;
|
||||
float z = y - b / 200f;
|
||||
|
||||
//Y
|
||||
if ( Math.pow(y,3) > 0.008856 )
|
||||
y = (float)Math.pow(y,3);
|
||||
else
|
||||
y = (float)(( y - 16 / 116 ) / 7.787);
|
||||
|
||||
//X
|
||||
if ( Math.pow(x,3) > 0.008856 )
|
||||
x = (float)Math.pow(x,3);
|
||||
else
|
||||
x = (float)(( x - 16 / 116 ) / 7.787);
|
||||
|
||||
// Z
|
||||
if ( Math.pow(z,3) > 0.008856 )
|
||||
z = (float)Math.pow(z,3);
|
||||
else
|
||||
z = (float)(( z - 16 / 116 ) / 7.787);
|
||||
|
||||
xyz[0] = x * tristimulus[0];
|
||||
xyz[1] = y * tristimulus[1];
|
||||
xyz[2] = z * tristimulus[2];
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> C1C2C3.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return C1C2C3 color space.
|
||||
*/
|
||||
public static float[] RGBtoC1C2C3(int r, int g, int b){
|
||||
|
||||
float[] c = new float[3];
|
||||
|
||||
c[0] = (float)Math.atan(r / Math.max(g, b));
|
||||
c[1] = (float)Math.atan(g / Math.max(r, b));
|
||||
c[2] = (float)Math.atan(b / Math.max(r, g));
|
||||
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> O1O2.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return O1O2 color space.
|
||||
*/
|
||||
public static float[] RGBtoO1O2(int r, int g, int b){
|
||||
|
||||
float[] o = new float[2];
|
||||
|
||||
o[0] = (r - g) / 2f;
|
||||
o[1] = (r + g) / 4f - (b / 2f);
|
||||
|
||||
return o;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> Grayscale.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return Grayscale color space.
|
||||
*/
|
||||
public static float RGBtoGrayscale(int r, int g, int b){
|
||||
|
||||
return r*0.2125f + g*0.7154f + b*0.0721f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> Philips Hue XY
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return Hue xy array
|
||||
*/
|
||||
public static XYColorSpace XYZtoXY(float x, float y, float z){
|
||||
float[] xy = new float[2];
|
||||
|
||||
xy[0] = x / (x + y + z);
|
||||
xy[1] = y / (x + y + z);
|
||||
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness((int)Math.round(y * 254.0f));
|
||||
xyColor.setXy(xy);
|
||||
return xyColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Philips Hue XY -> XYZ
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @return XYZ array
|
||||
*/
|
||||
public static float[] XYtoXYZ(XYColorSpace xy){
|
||||
float[] xyz = new float[3];
|
||||
/* Old Way
|
||||
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
|
||||
xyz[1] = xy.getBrightnessAdjusted();
|
||||
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
|
||||
*/
|
||||
// New Way
|
||||
xyz[0] = xy.getXy()[0] * (xy.getBrightnessAdjusted() / xy.getXy()[1]) ;
|
||||
xyz[1] = xy.getBrightnessAdjusted();
|
||||
xyz[2] = (float) ((1.0 - xy.getXy()[0] - xy.getXy()[1]) * (xy.getBrightnessAdjusted() / xy.getXy()[1]));
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
public static int[] normalizeRGB(int[] rgb) {
|
||||
int[] newRGB = new int[3];
|
||||
|
||||
newRGB[0] = assureBounds(rgb[0]);
|
||||
newRGB[1] = assureBounds(rgb[1]);
|
||||
newRGB[2] = assureBounds(rgb[2]);
|
||||
|
||||
|
||||
return newRGB;
|
||||
}
|
||||
|
||||
private static int assureBounds(int value) {
|
||||
if (value < 0.0) {
|
||||
value = 0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
28
src/main/java/com/bwssystems/HABridge/hue/ColorData.java
Normal file
28
src/main/java/com/bwssystems/HABridge/hue/ColorData.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
public class ColorData {
|
||||
public enum ColorMode { XY, CT, HS}
|
||||
|
||||
private ColorMode mode;
|
||||
private Object data;
|
||||
|
||||
public ColorData(ColorMode mode, Object value) {
|
||||
this.mode = mode;
|
||||
this.data = value;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ColorMode getColorMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String formatString;
|
||||
|
||||
formatString = "Color Data mode: " + mode + ", data: " + data;
|
||||
return formatString;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,492 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
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;
|
||||
|
||||
// import com.bwssystems.HABridge.hue.ColorData;
|
||||
|
||||
public class ColorDecode {
|
||||
private static final Logger log = LoggerFactory.getLogger(ColorDecode.class);
|
||||
private static final String COLOR_R = "${color.r}";
|
||||
private static final String COLOR_G = "${color.g}";
|
||||
private static final String COLOR_B = "${color.b}";
|
||||
private static final String COLOR_RX = "${color.rx}";
|
||||
private static final String COLOR_GX = "${color.gx}";
|
||||
private static final String COLOR_BX = "${color.bx}";
|
||||
private static final String COLOR_RGBX = "${color.rgbx}";
|
||||
private static final String COLOR_HSB = "${color.hsb}";
|
||||
private static final String COLOR_H = "${color.h}";
|
||||
private static final String COLOR_S = "${color.s}";
|
||||
private static final String COLOR_XY = "${color.xy}";
|
||||
private static final String COLOR_BRI = "${colorbri}";
|
||||
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
|
||||
|
||||
public static String convertCIEtoRGB(List<Double> xy) {
|
||||
double x;
|
||||
double y;
|
||||
double Y;
|
||||
|
||||
/* This is supersceded by the next iteration function below this original one
|
||||
public static List<Integer> convertHSBtoRGBOrig(HueSatBri hsb) {
|
||||
List<Integer> rgb;
|
||||
Float hue = (Float)(hsb.getHue()*1.0f);
|
||||
Float saturation = (Float)(hsb.getSat()*1.0f);
|
||||
Float brightness = (Float)(hsb.getBri()*1.0f);
|
||||
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
|
||||
//Convert Hue into degrees for HSB
|
||||
// hue = hue / 182.04f;
|
||||
hue = (hue / 65535.0f) * 360.0f;
|
||||
//Bri and Sat must be values from 0-1 (~percentage)
|
||||
// ightness = brightness / 255.0f;
|
||||
// saturation = saturation / 255.0f;
|
||||
|
||||
brightness = brightness / 254.0f;
|
||||
saturation = saturation / 254.0f;
|
||||
|
||||
Float r = 0f;
|
||||
Float g = 0f;
|
||||
Float b = 0f;
|
||||
|
||||
if(brightness > 0.0f) {
|
||||
if (saturation == 0)
|
||||
{
|
||||
r = g = b = brightness;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the color wheel consists of 6 sectors.
|
||||
Float sectorPos = hue / 60.0f;
|
||||
int sectorNumber = (int)(Math.floor(sectorPos));
|
||||
// get the fractional part of the sector
|
||||
Float fractionalSector = sectorPos - sectorNumber;
|
||||
|
||||
x = xy.get(0) * 100;
|
||||
y = xy.get(1) * 100;
|
||||
Y= y;
|
||||
double R = 3.240479*((x*Y)/y) + -1.537150*Y + -0.498535*(((1-x-y)*Y)/y);
|
||||
double G = -0.969256*((x*Y)/y) + 1.875992*Y + 0.041556*(((1-x-y)*Y)/y);
|
||||
double B = 0.055648*((x*Y)/y) + -0.204043*Y + 1.057311*(((1-x-y)*Y)/y);
|
||||
// calculate values for the three axes of the color.
|
||||
Float p = brightness * (1.0f - saturation);
|
||||
Float q = brightness * (1.0f - (saturation * fractionalSector));
|
||||
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
|
||||
|
||||
return null;
|
||||
// assign the fractional colors to r, g, and b based on the sector the angle is in.
|
||||
switch (sectorNumber)
|
||||
{
|
||||
case 0:
|
||||
r = brightness;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = brightness;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = brightness;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = brightness;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = brightness;
|
||||
break;
|
||||
case 5:
|
||||
r = brightness;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if any value is out of byte range
|
||||
if (r < 0f)
|
||||
{
|
||||
r = 0f;
|
||||
}
|
||||
if (g < 0f)
|
||||
{
|
||||
g = 0f;
|
||||
}
|
||||
if (b < 0f)
|
||||
{
|
||||
b = 0f;
|
||||
}
|
||||
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add((int)Math.round(r*255));
|
||||
rgb.add((int)Math.round(g*255));
|
||||
rgb.add((int)Math.round(b*255));
|
||||
log.info("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
|
||||
int theRGB = Color.HSBtoRGB(hue, saturation, brightness);
|
||||
Color decodedRGB = new Color(theRGB);
|
||||
log.info("Color change with HSB using java Color: " + hsb + ". Resulting RGB Values: " + decodedRGB.getRed() + " " + decodedRGB.getGreen() + " "
|
||||
+ decodedRGB.getBlue());
|
||||
|
||||
return rgb;
|
||||
}
|
||||
*/
|
||||
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
|
||||
List<Integer> rgb;
|
||||
Float hue = (Float)(hsb.getHue()*1.0f);
|
||||
Float saturation = (Float)(hsb.getSat()*1.0f);
|
||||
Float brightness = (Float)(hsb.getBri()*1.0f);
|
||||
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
|
||||
//Convert Hue into degrees for HSB
|
||||
// hue = hue / 182.04f;
|
||||
hue = (hue / 65535.0f);
|
||||
//Bri and Sat must be values from 0-1 (~percentage)
|
||||
// ightness = brightness / 255.0f;
|
||||
// saturation = saturation / 255.0f;
|
||||
|
||||
brightness = brightness / 254.0f;
|
||||
saturation = saturation / 254.0f;
|
||||
|
||||
Float r = 0f;
|
||||
Float g = 0f;
|
||||
Float b = 0f;
|
||||
Float temp2 = 0f;
|
||||
Float temp1 = 0f;
|
||||
|
||||
if(brightness > 0.0f) {
|
||||
if (saturation == 0)
|
||||
{
|
||||
r = g = b = brightness;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp2 = (brightness < 0.5f) ? brightness * (1.0f + saturation) : brightness + saturation - (brightness * saturation);
|
||||
temp1 = 2.0f * brightness - temp2;
|
||||
|
||||
r = GetColorComponent(temp1, temp2, hue + 1.0f/3.0f);
|
||||
g = GetColorComponent(temp1, temp2, hue);
|
||||
b = GetColorComponent(temp1, temp2, hue - 1.0f/3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//Check if any value is out of byte range
|
||||
if (r < 0f)
|
||||
{
|
||||
r = 0f;
|
||||
}
|
||||
if (g < 0f)
|
||||
{
|
||||
g = 0f;
|
||||
}
|
||||
if (b < 0f)
|
||||
{
|
||||
b = 0f;
|
||||
}
|
||||
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add((int)Math.round(r*255));
|
||||
rgb.add((int)Math.round(g*255));
|
||||
rgb.add((int)Math.round(b*255));
|
||||
log.debug("Color change with HSB New: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static Float GetColorComponent(Float temp1, Float temp2, Float temp3)
|
||||
{
|
||||
temp3 = MoveIntoRange(temp3);
|
||||
if (temp3 < 1.0f/6.0f)
|
||||
{
|
||||
return temp1 + (temp2 - temp1) * 6.0f * temp3;
|
||||
}
|
||||
|
||||
if (temp3 < 0.5f)
|
||||
{
|
||||
return temp2;
|
||||
}
|
||||
|
||||
if (temp3 < 2.0f/3.0f)
|
||||
{
|
||||
return temp1 + ((temp2 - temp1) * ((2.0f/3.0f) - temp3) * 6.0f);
|
||||
}
|
||||
|
||||
return temp1;
|
||||
}
|
||||
|
||||
private static Float MoveIntoRange(Float temp3)
|
||||
{
|
||||
if (temp3 < 0.0f) return temp3 + 1f;
|
||||
if (temp3 > 1.0f) return temp3 - 1f;
|
||||
return temp3;
|
||||
}
|
||||
|
||||
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
|
||||
List<Integer> rgb;
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness(brightness);
|
||||
float[] xyFloat = new float[2];
|
||||
xyFloat[0] = xy.get(0).floatValue();
|
||||
xyFloat[1] = xy.get(1).floatValue();
|
||||
xyColor.setXy(xyFloat);
|
||||
float[] xyz = ColorConverter.XYtoXYZ(xyColor);
|
||||
int[] rgbInt = ColorConverter.normalizeRGB(ColorConverter.XYZtoRGB(xyz[0], xyz[1], xyz[2]));
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add(rgbInt[0]);
|
||||
rgb.add(rgbInt[1]);
|
||||
rgb.add(rgbInt[2]);
|
||||
log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " " + brightness + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||
+ " " + rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
// took that approximation from
|
||||
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
public static List<Integer> convertCTtoRGB(Integer ct) {
|
||||
double temperature = 1000000.0 / (double) ct;
|
||||
temperature /= 100;
|
||||
double r, g, b;
|
||||
if (temperature <= 66) {
|
||||
r = 255;
|
||||
g = temperature;
|
||||
g = 99.4708025861 * Math.log(g) - 161.1195681661;
|
||||
} else {
|
||||
r = temperature - 60;
|
||||
r = 329.698727446 * (Math.pow(r, -0.1332047592));
|
||||
g = temperature - 60;
|
||||
g = 288.1221695283 * (Math.pow(g, -0.0755148492));
|
||||
}
|
||||
|
||||
if (temperature >= 66) {
|
||||
b = 255;
|
||||
} else {
|
||||
if (temperature <= 19) {
|
||||
b = 0;
|
||||
} else {
|
||||
b = temperature - 10;
|
||||
b = 138.5177312231 * Math.log(b) - 305.0447927307;
|
||||
}
|
||||
}
|
||||
r = assureBounds(r);
|
||||
g = assureBounds(g);
|
||||
b = assureBounds(b);
|
||||
List<Integer> rgb = new ArrayList<Integer>();
|
||||
rgb.add((int) Math.round(r));
|
||||
rgb.add((int) Math.round(g));
|
||||
rgb.add((int) Math.round(b));
|
||||
log.debug("Color change with CT: " + ct + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static double assureBounds(double value) {
|
||||
if (value < 0.0) {
|
||||
value = 0.0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255.0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static String replaceColorData(String request, ColorData colorData, int setIntensity, boolean isHex) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
if (colorData == null) {
|
||||
return request;
|
||||
}
|
||||
boolean notDone = true;
|
||||
ColorData.ColorMode colorMode = colorData.getColorMode();
|
||||
List<Integer> rgb = null;
|
||||
if (colorMode == ColorData.ColorMode.XY) {
|
||||
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
|
||||
} else if (colorMode == ColorData.ColorMode.CT) {
|
||||
rgb = convertCTtoRGB((Integer) colorData.getData());
|
||||
} else if (colorMode == ColorData.ColorMode.HS) {
|
||||
rgb = convertHSBtoRGB((HueSatBri) colorData.getData());
|
||||
}
|
||||
|
||||
while (notDone) {
|
||||
notDone = false;
|
||||
if (request.contains(COLOR_R)) {
|
||||
request = request.replace(COLOR_R,
|
||||
isHex ? String.format("%02X", rgb.get(0)) : String.valueOf(rgb.get(0)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_G)) {
|
||||
request = request.replace(COLOR_G,
|
||||
isHex ? String.format("%02X", rgb.get(1)) : String.valueOf(rgb.get(1)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_B)) {
|
||||
request = request.replace(COLOR_B,
|
||||
isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_RX)) {
|
||||
request = request.replace(COLOR_RX, String.format("%02X", rgb.get(0)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_GX)) {
|
||||
request = request.replace(COLOR_GX, String.format("%02X", rgb.get(1)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_BX)) {
|
||||
request = request.replace(COLOR_BX, String.format("%02X", rgb.get(2)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_RGBX)) {
|
||||
request = request.replace(COLOR_RGBX,
|
||||
String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_XY)) {
|
||||
if (colorMode == ColorData.ColorMode.XY) {
|
||||
List<Double> xyData = (List<Double>) colorData.getData();
|
||||
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||
} else {
|
||||
float[] xyz = ColorConverter.RGBtoXYZ(rgb.get(0), rgb.get(1), rgb.get(2));
|
||||
XYColorSpace theXYcolor = ColorConverter.XYZtoXY(xyz[0], xyz[1], xyz[2]);
|
||||
request = request.replace(COLOR_XY, String.format("%f,%f",theXYcolor.getXy()[0], theXYcolor.getXy()[1]));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_H)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
|
||||
} else {
|
||||
float[] hsb;
|
||||
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
|
||||
float hue = hsb[0];
|
||||
request = request.replace(COLOR_H, String.format("%f", hue));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_S)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
|
||||
} else {
|
||||
float[] hsb;
|
||||
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
request = request.replace(COLOR_S, String.format("%f", sat));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_BRI)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
|
||||
} else {
|
||||
request = request.replace(COLOR_BRI, String.format("%d", setIntensity));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_HSB)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_HSB,
|
||||
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
|
||||
float hue = hsb[0];
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
float bright = hsb[2] * (float) 100.0;
|
||||
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
Matcher m = COLOR_MILIGHT.matcher(request);
|
||||
while (m.find()) {
|
||||
int group = Integer.parseInt(m.group(1));
|
||||
request = m.replaceFirst(getMilightV5FromRgb(rgb, group));
|
||||
m.reset(request);
|
||||
}
|
||||
|
||||
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private static String getMilightV5FromRgb(List<Integer> rgb, int group) {
|
||||
double r = (double) rgb.get(0);
|
||||
double g = (double) rgb.get(1);
|
||||
double b = (double) rgb.get(2);
|
||||
if (r > 245 && g > 245 && b > 245) { // it's white
|
||||
String retVal = "";
|
||||
if (group == 0) {
|
||||
retVal += "C2";
|
||||
} else if (group == 1) {
|
||||
retVal += "C5";
|
||||
} else if (group == 2) {
|
||||
retVal += "C7";
|
||||
} else if (group == 3) {
|
||||
retVal += "C9";
|
||||
} else if (group == 4) {
|
||||
retVal += "CB";
|
||||
}
|
||||
log.debug("Convert RGB to Milight. Result: WHITE. RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return retVal + "0055";
|
||||
} else { // normal color
|
||||
r /= (double) 0xFF;
|
||||
g /= (double) 0xFF;
|
||||
b /= (double) 0xFF;
|
||||
double max = Math.max(Math.max(r, g), b), min = Math.min(Math.min(r, g), b);
|
||||
double h = 0;
|
||||
double d = max - min;
|
||||
|
||||
if (max == min) {
|
||||
h = 0;
|
||||
} else {
|
||||
if (max == r) {
|
||||
h = ((g - b) / d + (g < b ? 6 : 0));
|
||||
} else if (max == g) {
|
||||
h = ((b - r) / d + 2);
|
||||
} else if (max == b) {
|
||||
h = ((r - g) / d + 4);
|
||||
}
|
||||
h = Math.round(h * 60);
|
||||
}
|
||||
int milight = (int) ((256 + 176 - Math.floor(h / 360.0 * 255.0)) % 256);
|
||||
log.debug("Convert RGB to Milight. Result: " + milight + " RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||
+ " " + rgb.get(2));
|
||||
return "40" + String.format("%02X", milight) + "55";
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static int getIntRGB(ColorData colorData, int setIntensity) {
|
||||
ColorData.ColorMode colorMode = colorData.getColorMode();
|
||||
List<Integer> rgb = null;
|
||||
if (colorMode == ColorData.ColorMode.XY) {
|
||||
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
|
||||
} else if (colorMode == ColorData.ColorMode.CT) {
|
||||
rgb = convertCTtoRGB((Integer) colorData.getData());
|
||||
}
|
||||
|
||||
int rgbIntVal = Integer.parseInt(String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)), 16);
|
||||
log.debug("Convert RGB to int. Result: " + rgbIntVal + " RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return rgbIntVal;
|
||||
}
|
||||
}
|
||||
|
||||
75
src/main/java/com/bwssystems/HABridge/hue/ColorMap.java
Normal file
75
src/main/java/com/bwssystems/HABridge/hue/ColorMap.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
public class ColorMap {
|
||||
private double red;
|
||||
private double green;
|
||||
private double blue;
|
||||
private long R;
|
||||
private long G;
|
||||
private long B;
|
||||
private double X;
|
||||
private double Y;
|
||||
private Double Z;
|
||||
private double z;
|
||||
public double getRed() {
|
||||
return red;
|
||||
}
|
||||
public void setRed(double red) {
|
||||
this.red = red;
|
||||
}
|
||||
public double getGreen() {
|
||||
return green;
|
||||
}
|
||||
public void setGreen(double green) {
|
||||
this.green = green;
|
||||
}
|
||||
public double getBlue() {
|
||||
return blue;
|
||||
}
|
||||
public void setBlue(double blue) {
|
||||
this.blue = blue;
|
||||
}
|
||||
public long getR() {
|
||||
return R;
|
||||
}
|
||||
public void setR(long r) {
|
||||
R = r;
|
||||
}
|
||||
public long getG() {
|
||||
return G;
|
||||
}
|
||||
public void setG(long g) {
|
||||
G = g;
|
||||
}
|
||||
public long getB() {
|
||||
return B;
|
||||
}
|
||||
public void setB(long b) {
|
||||
B = b;
|
||||
}
|
||||
public double getX() {
|
||||
return X;
|
||||
}
|
||||
public void setX(double x) {
|
||||
X = x;
|
||||
}
|
||||
public double getY() {
|
||||
return Y;
|
||||
}
|
||||
public void setY(double y) {
|
||||
Y = y;
|
||||
}
|
||||
public Double getZ() {
|
||||
return Z;
|
||||
}
|
||||
public void setZ(Double z) {
|
||||
Z = z;
|
||||
}
|
||||
public double getz() {
|
||||
return z;
|
||||
}
|
||||
public void setz(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,9 @@ public class DeviceDataDecode {
|
||||
private static final String DEVICE_MAPTYPE = "${device.mapType}";
|
||||
private static final String DEVICE_DEVICETYPE = "${device.deviceType}";
|
||||
private static final String DEVICE_TARGETDEVICE = "${device.targetDevice}";
|
||||
private static final String DEVICE_REQUESTERADDRESS = "${device.requesterAddress}";
|
||||
private static final String DEVICE_DESCRIPTION = "${device.description}";
|
||||
private static final String DEVICE_COMMENTS = "${device.comments}";
|
||||
|
||||
public static String replaceDeviceData(String request, DeviceDescriptor device) {
|
||||
if (request == null) {
|
||||
@@ -58,6 +61,21 @@ public class DeviceDataDecode {
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(DEVICE_REQUESTERADDRESS)) {
|
||||
request = request.replace(DEVICE_REQUESTERADDRESS, device.getRequesterAddress());
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(DEVICE_DESCRIPTION)) {
|
||||
request = request.replace(DEVICE_DESCRIPTION, device.getDescription());
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(DEVICE_COMMENTS)) {
|
||||
request = request.replace(DEVICE_COMMENTS, device.getComments());
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
||||
}
|
||||
return request;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,8 @@ package com.bwssystems.HABridge.hue;
|
||||
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
|
||||
public interface HueMulatorHandler {
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body);
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body);
|
||||
}
|
||||
|
||||
38
src/main/java/com/bwssystems/HABridge/hue/HueSatBri.java
Normal file
38
src/main/java/com/bwssystems/HABridge/hue/HueSatBri.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
public class HueSatBri {
|
||||
int hue;
|
||||
int sat;
|
||||
int bri;
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public int getSat() {
|
||||
return sat;
|
||||
}
|
||||
|
||||
public void setSat(int sat) {
|
||||
this.sat = sat;
|
||||
}
|
||||
|
||||
public int getBri() {
|
||||
return bri;
|
||||
}
|
||||
|
||||
public void setBri(int bri) {
|
||||
this.bri = bri;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String formatString = new String();
|
||||
|
||||
formatString = "Hue: " + Integer.toString(hue) + ", Sat: " + Integer.toString(sat) + ", Bri: " + Integer.toString(bri);
|
||||
return formatString;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class TimeDecode {
|
||||
private static final Logger log = LoggerFactory.getLogger(TimeDecode.class);
|
||||
private static final String TIME_FORMAT = "${time.format(";
|
||||
private static final String TIMESTAMP = "${time.millis}";
|
||||
private static final String TIME_FORMAT_CLOSE = ")}";
|
||||
|
||||
/*
|
||||
@@ -38,6 +39,10 @@ public class TimeDecode {
|
||||
log.warn("Could not format current time: " + timeFormatDescriptor, e);
|
||||
}
|
||||
}
|
||||
if (request.contains(TIMESTAMP)) {
|
||||
request = request.replace(TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
||||
notDone = true;
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
public class XYColorSpace {
|
||||
float[] xy;
|
||||
int brightness;
|
||||
|
||||
public float[] getXy() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXy(float[] xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
public float getBrightnessAdjusted() {
|
||||
return ((float) brightness / 254.0f) * 100f;
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
this.brightness = brightness;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
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.MultiCommandUtil;
|
||||
import com.bwssystems.nest.controller.Home;
|
||||
import com.bwssystems.nest.controller.Nest;
|
||||
@@ -31,10 +32,13 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
private Gson aGsonHandler;
|
||||
private Boolean isFarenheit;
|
||||
private Boolean validNest;
|
||||
private boolean closed;
|
||||
|
||||
public NestHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,30 +96,36 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
if(theSession != null) {
|
||||
theNest.endNestSession();
|
||||
}
|
||||
theNest = null;
|
||||
theSession = null;
|
||||
nestItems = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String responseString = null;
|
||||
log.debug("executing HUE api request to set away for nest " + anItem.getType() + ": " + anItem.getItem().toString());
|
||||
if(!validNest) {
|
||||
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;
|
||||
@@ -157,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;
|
||||
@@ -187,5 +197,10 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
public class BroadlinkEntry {
|
||||
private String name;
|
||||
private String id;
|
||||
private String ipAddr;
|
||||
private String macAddr;
|
||||
private String command;
|
||||
private String data;
|
||||
private String type;
|
||||
private String baseType;
|
||||
private String desc;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public String getIpAddr() {
|
||||
return ipAddr;
|
||||
}
|
||||
public void setIpAddr(String ipAddr) {
|
||||
this.ipAddr = ipAddr;
|
||||
}
|
||||
public String getMacAddr() {
|
||||
return macAddr;
|
||||
}
|
||||
public void setMacAddr(String macAddr) {
|
||||
this.macAddr = macAddr;
|
||||
}
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getBaseType() {
|
||||
return baseType;
|
||||
}
|
||||
public void setBaseType(String baseType) {
|
||||
this.baseType = baseType;
|
||||
}
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
public boolean hasIpAndMac() {
|
||||
boolean deviceOk = true;
|
||||
if(ipAddr == null || ipAddr.trim().isEmpty())
|
||||
deviceOk = false;
|
||||
else if(macAddr == null || macAddr.trim().isEmpty())
|
||||
deviceOk = false;
|
||||
else if(type == null || type.trim().isEmpty())
|
||||
deviceOk = false;
|
||||
return deviceOk;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.BindException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.Configuration;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
import com.github.mob41.blapi.BLDevice;
|
||||
import com.github.mob41.blapi.MP1Device;
|
||||
import com.github.mob41.blapi.SP1Device;
|
||||
import com.github.mob41.blapi.SP2Device;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.mac.MacFormatException;
|
||||
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class BroadlinkHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(BroadlinkHome.class);
|
||||
private Map<String, BLDevice> broadlinkMap;
|
||||
private Boolean validBroadlink;
|
||||
private boolean closed;
|
||||
private Boolean isDevMode;
|
||||
private BridgeSettingsDescriptor bridgeSettingsDesc;
|
||||
|
||||
public BroadlinkHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
broadlinkMap = null;
|
||||
bridgeSettingsDesc = bridgeSettings.getBridgeSettingsDescriptor();
|
||||
validBroadlink = bridgeSettings.getBridgeSettingsDescriptor().isValidBroadlink();
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
if (isDevMode)
|
||||
validBroadlink = true;
|
||||
|
||||
if(validBroadlink)
|
||||
broadlinkDiscover();
|
||||
|
||||
log.info("Broadlink Home created." + (validBroadlink ? "" : " No Broadlinks configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
List<BroadlinkEntry> deviceList = new ArrayList<BroadlinkEntry>();
|
||||
if(!validBroadlink || broadlinkMap == null)
|
||||
return deviceList;
|
||||
BroadlinkEntry theResponse = null;
|
||||
log.debug("consolidating devices for Broadlink");
|
||||
Iterator<String> keys = broadlinkMap.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = toEntry(broadlinkMap.get(key));
|
||||
if(theResponse != null)
|
||||
deviceList.add(theResponse);
|
||||
else {
|
||||
log.warn("Cannot get BroadlinkDevice with name: " + key + ", skipping this Broadlink.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
if(validBroadlink)
|
||||
broadlinkDiscover();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String theReturn = null;
|
||||
boolean changeState = false;
|
||||
String theStringData = null;
|
||||
log.debug("executing HUE api request to send message to BroadlinkDevice: " + anItem.getItem().toString());
|
||||
if(!validBroadlink) {
|
||||
log.warn("Should not get here, no Broadlinks configured");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
|
||||
} else {
|
||||
BroadlinkEntry broadlinkCommand = null;
|
||||
if(anItem.getItem().isJsonObject())
|
||||
broadlinkCommand = new Gson().fromJson(anItem.getItem(), BroadlinkEntry.class);
|
||||
else
|
||||
broadlinkCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), BroadlinkEntry.class);
|
||||
BLDevice theDevice = null;
|
||||
if(broadlinkMap != null && !broadlinkMap.isEmpty())
|
||||
theDevice = broadlinkMap.get(broadlinkCommand.getId());
|
||||
|
||||
if (theDevice == null) {
|
||||
if(broadlinkCommand.hasIpAndMac()) {
|
||||
byte[] intBytes = HexLibrary.decodeHexString(broadlinkCommand.getType());
|
||||
BigInteger theBig = new BigInteger(intBytes);
|
||||
int theType = theBig.intValue();
|
||||
try {
|
||||
theDevice = BLDevice.createInstance((short)theType, broadlinkCommand.getIpAddr(), new Mac(broadlinkCommand.getMacAddr()));
|
||||
} catch (MacFormatException e) {
|
||||
log.warn("Could not initialize BroadlinkDevice device due to Mac (" + broadlinkCommand.getId() + ") format exception: " + e.getMessage());
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to Mac format exception\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not initialize BroadlinkDevice device due to IP Address (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to IP Address exception\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not initialize BroadlinkDevice device due to (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to exception\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
|
||||
if(broadlinkMap == null)
|
||||
broadlinkMap = new HashMap<String, BLDevice>();
|
||||
|
||||
if (theDevice != null) {
|
||||
String newId = theDevice.getHost() + "-" + String.format("%04x", theDevice.getDeviceType());
|
||||
if (broadlinkMap.get(newId) == null) {
|
||||
broadlinkMap.put(newId, theDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theDevice == null) {
|
||||
log.warn("Should not get here, no BroadlinkDevice not available");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no Broadlinks available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
log.debug("calling BroadlinkDevice: " + broadlinkCommand.getName());
|
||||
try {
|
||||
if(!isDevMode) {
|
||||
if(!theDevice.auth()) {
|
||||
log.error("Call to " + broadlinkCommand.getId() + " device authorization failed.");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device auth error.\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
switch (theDevice.getDeviceType()) {
|
||||
case BLDevice.DEV_A1:
|
||||
log.debug("Broadlink A1 device called and not supported. No Action, device name = " + device.getName() + ", id= " + broadlinkCommand.getId());
|
||||
break;
|
||||
case BLDevice.DEV_MP1:
|
||||
if(broadlinkCommand.getCommand().equals("on"))
|
||||
changeState = true;
|
||||
else
|
||||
changeState = false;
|
||||
((MP1Device) theDevice).setState(Integer.parseInt(broadlinkCommand.getData()), changeState);
|
||||
break;
|
||||
case BLDevice.DEV_SP2:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
|
||||
case BLDevice.DEV_SPMINI:
|
||||
case BLDevice.DEV_SP3:
|
||||
case BLDevice.DEV_SPMINI2:
|
||||
case BLDevice.DEV_SPMINI_OEM_ALT1:
|
||||
case BLDevice.DEV_SPMINI_OEM_ALT2:
|
||||
case BLDevice.DEV_SPMINI_PLUS:
|
||||
if(broadlinkCommand.getCommand().equals("on"))
|
||||
changeState = true;
|
||||
else
|
||||
changeState = false;
|
||||
((SP2Device) theDevice).setState(changeState);
|
||||
break;
|
||||
case BLDevice.DEV_SP1:
|
||||
if(broadlinkCommand.getCommand().equals("on"))
|
||||
changeState = true;
|
||||
else
|
||||
changeState = false;
|
||||
((SP1Device) theDevice).setPower(changeState);
|
||||
break;
|
||||
case BLDevice.DEV_RM_2:
|
||||
case BLDevice.DEV_RM_MINI:
|
||||
case BLDevice.DEV_RM_PRO_PHICOMM:
|
||||
case BLDevice.DEV_RM_2_HOME_PLUS:
|
||||
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS_2:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
|
||||
case BLDevice.DEV_RM_MINI_SHATE:
|
||||
if(broadlinkCommand.getData() != null && !broadlinkCommand.getData().trim().isEmpty()) {
|
||||
theStringData = broadlinkCommand.getData().trim();
|
||||
if(targetBri != null || targetBriInc != null) {
|
||||
theStringData = BrightnessDecode.calculateReplaceIntensityValue(theStringData, intensity, targetBri, targetBriInc, true);
|
||||
}
|
||||
if(colorData != null) {
|
||||
theStringData = ColorDecode.replaceColorData(theStringData, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||
}
|
||||
theStringData = DeviceDataDecode.replaceDeviceData(theStringData, device);
|
||||
theStringData = TimeDecode.replaceTimeValue(theStringData);
|
||||
byte[] theData = HexLibrary.decodeHexString(theStringData);
|
||||
SendDataCmdPayload thePayload = new SendDataCmdPayload(theData);
|
||||
|
||||
DatagramPacket thePacket = theDevice.sendCmdPkt(Configuration.BROADLINK_DISCONVER_TIMEOUT, thePayload);
|
||||
String returnData = null;
|
||||
if(thePacket != null)
|
||||
returnData = HexLibrary.encodeHexString(thePacket.getData());
|
||||
else
|
||||
returnData = "No Data - null";
|
||||
log.debug("RM2 Device data return: <<<" + returnData + ">>>");
|
||||
}
|
||||
else {
|
||||
log.error("Call to " + broadlinkCommand.getId() + " with no data, noop");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"" + broadlinkCommand.getId() + " could not call device without data.\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Call to " + broadlinkCommand.getId() + " device failed with exception: " + e.getMessage(), e);
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device call error.\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return theReturn;
|
||||
}
|
||||
|
||||
private BroadlinkEntry toEntry(BLDevice broadlinkObject) {
|
||||
short baseType = 0;
|
||||
switch (broadlinkObject.getDeviceType()) {
|
||||
case BLDevice.DEV_MP1:
|
||||
baseType = BLDevice.DEV_MP1;
|
||||
break;
|
||||
case BLDevice.DEV_SP2:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
|
||||
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
|
||||
case BLDevice.DEV_SPMINI:
|
||||
case BLDevice.DEV_SP3:
|
||||
case BLDevice.DEV_SPMINI2:
|
||||
case BLDevice.DEV_SPMINI_OEM_ALT1:
|
||||
case BLDevice.DEV_SPMINI_OEM_ALT2:
|
||||
case BLDevice.DEV_SPMINI_PLUS:
|
||||
baseType = BLDevice.DEV_SP2;
|
||||
break;
|
||||
case BLDevice.DEV_SP1:
|
||||
baseType = BLDevice.DEV_SP1;
|
||||
break;
|
||||
case BLDevice.DEV_RM_2:
|
||||
case BLDevice.DEV_RM_MINI:
|
||||
case BLDevice.DEV_RM_PRO_PHICOMM:
|
||||
case BLDevice.DEV_RM_2_HOME_PLUS:
|
||||
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS_2:
|
||||
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
|
||||
case BLDevice.DEV_RM_MINI_SHATE:
|
||||
baseType = BLDevice.DEV_RM_2;
|
||||
break;
|
||||
}
|
||||
BroadlinkEntry anEntry = new BroadlinkEntry();
|
||||
anEntry.setId(broadlinkObject.getHost() + "-" + String.format("%04x", broadlinkObject.getDeviceType()));
|
||||
anEntry.setName(broadlinkObject.getDeviceDescription());
|
||||
anEntry.setType(String.format("%04x", broadlinkObject.getDeviceType()));
|
||||
anEntry.setBaseType(String.format("%04x", baseType));
|
||||
anEntry.setDesc(BLDevice.getDescOfType(broadlinkObject.getDeviceType()));
|
||||
anEntry.setIpAddr(broadlinkObject.getHost());
|
||||
anEntry.setMacAddr(broadlinkObject.getMac().getMacString());
|
||||
return anEntry;
|
||||
}
|
||||
|
||||
public BLDevice[] broadlinkDiscover () {
|
||||
BLDevice[] clients = null;
|
||||
int aDiscoverPort = Configuration.BROADLINK_DISCOVER_PORT;
|
||||
broadlinkMap = new HashMap<String, BLDevice>();
|
||||
while(aDiscoverPort > 0) {
|
||||
try {
|
||||
log.info("Broadlink discover....");
|
||||
if(isDevMode) {
|
||||
clients = TestBLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
}
|
||||
else
|
||||
clients = BLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
for(int i = 0; i < clients.length; i++) {
|
||||
if(clients[i].getDeviceType() != BLDevice.DEV_A1 && broadlinkMap.get(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType())) == null) {
|
||||
broadlinkMap.put(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType()), clients[i]);
|
||||
log.debug("Adding Device to Map - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
} else {
|
||||
log.debug("Ignoring Device (already in the list or an A1 Device) - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
}
|
||||
}
|
||||
aDiscoverPort = 0;
|
||||
} catch (BindException e) {
|
||||
log.warn("Could not discover Broadlinks, Port in use, increasing by 11");
|
||||
aDiscoverPort += 11;
|
||||
if(aDiscoverPort > Configuration.BROADLINK_DISCOVER_PORT + 110)
|
||||
aDiscoverPort = 0;
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not discover Broadlinks, with IO Exception", e);
|
||||
broadlinkMap = null;
|
||||
aDiscoverPort = 0;
|
||||
}
|
||||
}
|
||||
if(clients == null || clients.length <= 0) {
|
||||
log.warn("Did not discover any Broadlinks.");
|
||||
broadlinkMap = null;
|
||||
} else {
|
||||
log.info("Broadlink discover found " + clients.length + " clients.");
|
||||
}
|
||||
return clients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
if(!validBroadlink)
|
||||
return;
|
||||
log.debug("Closing Home.");
|
||||
if(broadlinkMap != null) {
|
||||
broadlinkMap.clear();
|
||||
broadlinkMap = null;
|
||||
}
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.BLDevice;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||
|
||||
public class TestBLDevice extends BLDevice {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestBLDevice.class);
|
||||
|
||||
protected TestBLDevice(short deviceType, String deviceDesc, String host, Mac mac) throws IOException {
|
||||
super(deviceType, deviceDesc, host, mac);
|
||||
}
|
||||
|
||||
public void setState(boolean aState) {
|
||||
log.info("setState called with " + aState);
|
||||
}
|
||||
|
||||
public void setState(int anIndex, boolean aState) {
|
||||
log.info("setState called with index " + anIndex + " and state " + aState);
|
||||
}
|
||||
|
||||
public void setPower(boolean aState) {
|
||||
log.info("setPower called with " + aState);
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BLDevice[] discoverDevices(InetAddress theAddress, int aport, int timeout) {
|
||||
TestMP1Device mp1Device = null;
|
||||
TestSP1Device sp1Device = null;
|
||||
TestSP2Device sp2Device = null;
|
||||
TestRM2Device rm2Device = null;
|
||||
try {
|
||||
mp1Device = new TestMP1Device("mp1host", null);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
sp1Device = new TestSP1Device("sp1host", null);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
sp2Device = new TestSP2Device("sp2host", null);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
rm2Device = new TestRM2Device("rm2host", null);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
BLDevice[] devices = { mp1Device, sp1Device, sp2Device, rm2Device };
|
||||
log.info("Created test devices");
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.MP1Device;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||
|
||||
public class TestMP1Device extends MP1Device {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestMP1Device.class);
|
||||
|
||||
protected TestMP1Device(String host, Mac mac) throws IOException {
|
||||
super(host, mac);
|
||||
}
|
||||
|
||||
public void setState(int anIndex, boolean aState) {
|
||||
log.info("setState called with index " + anIndex + " and state " + aState);
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.RM2Device;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
|
||||
|
||||
public class TestRM2Device extends RM2Device {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestRM2Device.class);
|
||||
|
||||
protected TestRM2Device(String host, Mac mac) throws IOException {
|
||||
super(host, mac);
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(((SendDataCmdPayload)aCmd).getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.SP1Device;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||
|
||||
public class TestSP1Device extends SP1Device {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestSP1Device.class);
|
||||
|
||||
protected TestSP1Device(String host, Mac mac) throws IOException {
|
||||
super(host, mac);
|
||||
}
|
||||
|
||||
public void setPower(boolean aState) {
|
||||
log.info("setPower called with " + aState);
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.SP2Device;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.CmdPayload;
|
||||
|
||||
public class TestSP2Device extends SP2Device {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestSP2Device.class);
|
||||
|
||||
protected TestSP2Device(String host, Mac mac) throws IOException {
|
||||
super(host, mac);
|
||||
}
|
||||
|
||||
public void setState(boolean aState) {
|
||||
log.info("setState called with " + aState);
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,10 @@ package com.bwssystems.HABridge.plugins.domoticz;
|
||||
import java.util.ArrayList;
|
||||
import java.util.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;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@ 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 DomoticzHome implements Home {
|
||||
@@ -26,17 +31,20 @@ public class DomoticzHome implements Home {
|
||||
private Map<String, DomoticzHandler> domoticzs;
|
||||
private Boolean validDomoticz;
|
||||
private HTTPHandler httpClient;
|
||||
private boolean closed;
|
||||
|
||||
public DomoticzHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
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>();
|
||||
@@ -58,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();
|
||||
@@ -71,11 +84,11 @@ public class DomoticzHome implements Home {
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
Devices theDomoticzApiResponse = null;
|
||||
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('/'));
|
||||
@@ -90,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"))
|
||||
@@ -99,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;
|
||||
}
|
||||
@@ -128,7 +157,7 @@ public class DomoticzHome implements Home {
|
||||
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
|
||||
if(!validDomoticz)
|
||||
return null;
|
||||
httpClient = new HTTPHandler();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
domoticzs = new HashMap<String, DomoticzHandler>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getDomoticzaddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
@@ -161,8 +190,16 @@ public class DomoticzHome implements Home {
|
||||
}
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if(closed || !validDomoticz) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
if(httpClient != null)
|
||||
httpClient.closeHandler();
|
||||
|
||||
|
||||
domoticzs = null;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bwssystems.HABridge.plugins.exec;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -10,6 +11,8 @@ 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;
|
||||
@@ -17,30 +20,34 @@ import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
public class CommandHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(CommandHome.class);
|
||||
private BridgeSettings theSettings;
|
||||
private boolean closed;
|
||||
|
||||
public CommandHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int itensity, Integer targetBri, Integer targetBriInc, 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()));
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
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 = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
|
||||
intermediate = theItem;
|
||||
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
intermediate = ColorDecode.replaceColorData(intermediate, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
}
|
||||
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
||||
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
||||
String execGarden = theSettings.getBridgeSecurity().getExecGarden();
|
||||
if(execGarden != null && !execGarden.trim().isEmpty()) {
|
||||
if(System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)
|
||||
intermediate = execGarden + "\\" + intermediate;
|
||||
else
|
||||
intermediate = execGarden + "/" + intermediate;
|
||||
intermediate = new File(execGarden.trim(), intermediate).getAbsolutePath();
|
||||
}
|
||||
|
||||
String anError = doExecRequest(intermediate, lightId);
|
||||
@@ -61,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;
|
||||
@@ -86,10 +93,20 @@ public class CommandHome implements Home {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
// noop
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
closed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
public class FHEMCommand {
|
||||
private String url;
|
||||
private String command;
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
public class FHEMDevice {
|
||||
|
||||
private String address;
|
||||
private String name;
|
||||
private Result item;
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Result getItem() {
|
||||
return item;
|
||||
}
|
||||
public void setItem(Result item) {
|
||||
this.item = item;
|
||||
}
|
||||
}
|
||||
218
src/main/java/com/bwssystems/HABridge/plugins/fhem/FHEMHome.java
Normal file
218
src/main/java/com/bwssystems/HABridge/plugins/fhem/FHEMHome.java
Normal file
@@ -0,0 +1,218 @@
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
import com.bwssystems.HABridge.plugins.http.HttpTestHandler;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
public class FHEMHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(FHEMHome.class);
|
||||
private Map<String, FHEMInstance> fhemMap;
|
||||
private Boolean validFhem;
|
||||
private Boolean isDevMode;
|
||||
private HTTPHandler httpClient;
|
||||
private boolean closed;
|
||||
|
||||
public FHEMHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
JsonElement jsonUrl = anItem.getItem();
|
||||
String theUrl = jsonUrl.toString();
|
||||
String responseString = null;
|
||||
|
||||
if(theUrl != null && !theUrl.isEmpty()) {
|
||||
FHEMCommand theCommand = null;
|
||||
try {
|
||||
if(anItem.getItem().isJsonObject())
|
||||
theCommand = new Gson().fromJson(anItem.getItem(), FHEMCommand.class);
|
||||
else
|
||||
theCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), FHEMCommand.class);
|
||||
} catch(Exception e) {
|
||||
log.warn("Cannot parse command to FHEM <<<" + theUrl + ">>>", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
return responseString;
|
||||
}
|
||||
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||
String hostAddr = null;
|
||||
if (hostPortion.contains(":")) {
|
||||
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||
} else
|
||||
hostAddr = hostPortion;
|
||||
FHEMInstance theHandler = findHandlerByAddress(hostAddr);
|
||||
if(theHandler != null) {
|
||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
|
||||
intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
}
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
String aCommand = null;
|
||||
if(theCommand.getCommand() != null && !theCommand.getCommand().isEmpty()) {
|
||||
aCommand = BrightnessDecode.calculateReplaceIntensityValue(theCommand.getCommand(),
|
||||
intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
aCommand = ColorDecode.replaceColorData(aCommand, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
}
|
||||
aCommand = DeviceDataDecode.replaceDeviceData(aCommand, device);
|
||||
aCommand = TimeDecode.replaceTimeValue(aCommand);
|
||||
}
|
||||
try {
|
||||
theHandler.callCommand(anUrl, aCommand, httpClient);
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot send comand to FHEM", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn("FHEM Call could not complete, no address found: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn("FHEM Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
private FHEMInstance findHandlerByAddress(String hostAddress) {
|
||||
FHEMInstance aHandler = null;
|
||||
boolean found = false;
|
||||
Iterator<String> keys = fhemMap.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
aHandler = fhemMap.get(key);
|
||||
if(aHandler != null && aHandler.getFhemAddress().getIp().equals(hostAddress)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
aHandler = null;
|
||||
return aHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
|
||||
if(!validFhem)
|
||||
return null;
|
||||
log.debug("consolidating devices for FHEM");
|
||||
List<FHEMDevice> theResponse = null;
|
||||
Iterator<String> keys = fhemMap.keySet().iterator();
|
||||
List<FHEMDevice> deviceList = new ArrayList<FHEMDevice>();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = fhemMap.get(key).getDevices(httpClient);
|
||||
if(theResponse != null)
|
||||
addFHEMDevices(deviceList, theResponse, key);
|
||||
else {
|
||||
log.warn("Cannot get devices for FHEM: " + key + ", skipping this FHEM.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
private Boolean addFHEMDevices(List<FHEMDevice> theDeviceList, List<FHEMDevice> theSourceList, String theKey) {
|
||||
Iterator<FHEMDevice> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
FHEMDevice theDevice = devices.next();
|
||||
theDeviceList.add(theDevice);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
fhemMap = null;
|
||||
validFhem = bridgeSettings.getBridgeSettingsDescriptor().isValidFhem();
|
||||
log.info("FHEM Home created." + (validFhem ? "" : " No FHEMs configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||
if(validFhem) {
|
||||
fhemMap = new HashMap<String,FHEMInstance>();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
if(isDevMode) {
|
||||
httpClient = new HttpTestHandler();
|
||||
((HttpTestHandler)httpClient).setTheData("cmd=jsonlist2", FHEMTestData.TestData);
|
||||
((HttpTestHandler)httpClient).setTheData("set", "FHEM Command Received");
|
||||
((HttpTestHandler)httpClient).setTheData(null, "FHEM no match");
|
||||
}
|
||||
httpClient.setCallType(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]);
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getFhemaddress().getDevices().iterator();
|
||||
while(theList.hasNext() && validFhem) {
|
||||
NamedIP aFhem = theList.next();
|
||||
try {
|
||||
fhemMap.put(aFhem.getName(), new FHEMInstance(aFhem));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get FHEM (" + aFhem.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
validFhem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if(!closed && validFhem) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
if(httpClient != null)
|
||||
httpClient.closeHandler();
|
||||
|
||||
fhemMap = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class FHEMInstance {
|
||||
private static final Logger log = LoggerFactory.getLogger(FHEMInstance.class);
|
||||
private NamedIP theFhem;
|
||||
|
||||
public FHEMInstance(NamedIP fhemLocation) {
|
||||
super();
|
||||
theFhem = fhemLocation;
|
||||
}
|
||||
|
||||
public NamedIP getFhemAddress() {
|
||||
return theFhem;
|
||||
}
|
||||
|
||||
public void setFhemAddress(NamedIP fhemAddress) {
|
||||
this.theFhem = fhemAddress;
|
||||
}
|
||||
|
||||
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
|
||||
String aUrl = null;
|
||||
NameValue[] headers = null;
|
||||
/* Trying new code helpers
|
||||
if(theFhem.getSecure() != null && theFhem.getSecure())
|
||||
aUrl = "https://";
|
||||
else
|
||||
aUrl = "http://";
|
||||
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
|
||||
aUrl = aUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
|
||||
}
|
||||
aUrl = aUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/" + aCommand + commandData;
|
||||
*/
|
||||
// New style http creation
|
||||
aUrl = theFhem.getHttpPreamble() + "/" + aCommand + commandData;
|
||||
headers = httpClient.addBasicAuthHeader(null, theFhem);
|
||||
log.debug("calling FHEM: " + aUrl);
|
||||
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", null, headers);
|
||||
if(theData != null)
|
||||
log.debug("doHttpRequest returned data: <" + theData + ">");
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<FHEMDevice> getDevices(HTTPHandler httpClient) {
|
||||
List<FHEMDevice> deviceList = null;
|
||||
FHEMItem theFhemStates;
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
NameValue[] headers = null;
|
||||
/* Trying new code helpers
|
||||
if(theFhem.getSecure() != null && theFhem.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
|
||||
theUrl = theUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
|
||||
}
|
||||
theUrl = theUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/fhem?cmd=jsonlist2";
|
||||
*/
|
||||
theUrl = theFhem.getHttpPreamble() + "/fhem?cmd=jsonlist2";
|
||||
headers = httpClient.addBasicAuthHeader(null, theFhem);
|
||||
if(theFhem.getWebhook() != null && !theFhem.getWebhook().trim().isEmpty())
|
||||
theUrl = theUrl + "%20room=" + theFhem.getWebhook().trim();
|
||||
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||
if(theData != null) {
|
||||
log.debug("GET FHEM States - data: " + theData);
|
||||
theData = getJSONData(theData);
|
||||
theFhemStates = new Gson().fromJson(theData, FHEMItem.class);
|
||||
if(theFhemStates == null) {
|
||||
log.warn("Cannot get any devices for FHEM " + theFhem.getName() + " as response is not parsable.");
|
||||
}
|
||||
else {
|
||||
deviceList = new ArrayList<FHEMDevice>();
|
||||
|
||||
for (Result aResult:theFhemStates.getResults()) {
|
||||
String name = aResult.getName();
|
||||
if(name.contains("<a href=")) {
|
||||
name = name.substring(name.indexOf("<a href=") + name.indexOf(">"));
|
||||
name = name.substring(1, name.indexOf("</a"));
|
||||
aResult.setName(name);
|
||||
}
|
||||
FHEMDevice aNewFhemDeviceDevice = new FHEMDevice();
|
||||
aNewFhemDeviceDevice.setItem(aResult);
|
||||
aNewFhemDeviceDevice.setAddress(theFhem.getIp() + ":" + theFhem.getPort());
|
||||
aNewFhemDeviceDevice.setName(theFhem.getName());
|
||||
deviceList.add(aNewFhemDeviceDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log.warn("Cannot get an devices for FHEM " + theFhem.getName() + " http call failed.");
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public String getJSONData(String response) {
|
||||
String theData;
|
||||
theData = response.substring(response.indexOf("<pre>") + 4);
|
||||
theData = theData.substring(1, theData.indexOf("</pre>") - 1);
|
||||
theData = theData.replace("\n", "");
|
||||
theData = theData.replace("\r", "");
|
||||
theData = theData.replace("<a href=\"", "<a href=\\\"");
|
||||
theData = theData.replace("\">", "\\\">");
|
||||
return theData;
|
||||
}
|
||||
|
||||
protected void closeClient() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class FHEMItem {
|
||||
|
||||
@SerializedName("Arg")
|
||||
@Expose
|
||||
private String arg;
|
||||
@SerializedName("Results")
|
||||
@Expose
|
||||
private List<Result> results = null;
|
||||
@SerializedName("totalResultsReturned")
|
||||
@Expose
|
||||
private Integer totalResultsReturned;
|
||||
|
||||
public String getArg() {
|
||||
return arg;
|
||||
}
|
||||
|
||||
public void setArg(String arg) {
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
public List<Result> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public void setResults(List<Result> results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public Integer getTotalResultsReturned() {
|
||||
return totalResultsReturned;
|
||||
}
|
||||
|
||||
public void setTotalResultsReturned(Integer totalResultsReturned) {
|
||||
this.totalResultsReturned = totalResultsReturned;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
public class FHEMTestData {
|
||||
public final static String TestData = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
|
||||
" <head root=\"/fhem\">\n" +
|
||||
" <title>Home, Sweet Home</title>\n" +
|
||||
" <link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
|
||||
" <link href=\"/fhem/pgm2/style.css?v=1513026539\" rel=\"stylesheet\"/>\n" +
|
||||
" <link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_colorpicker.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_fbcalllist.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_knob.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsHistory.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_sortable.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_uzsu.js\"></script>\n" +
|
||||
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_weekprofile.js\"></script>\n" +
|
||||
" </head>\n" +
|
||||
" <body name='Home, Sweet Home' fw_id='7880' generated=\"1513272732\" longpoll=\"1\" data-confirmDelete='1' data-confirmJSError='1' data-webName='haBridgeWeb '>\n" +
|
||||
" <div id=\"menuScrollArea\">\n" +
|
||||
" <div>\n" +
|
||||
" <a href=\"/fhem?\">\n" +
|
||||
" <div id=\"logo\"></div>\n" +
|
||||
" </a>\n" +
|
||||
" </div>\n" +
|
||||
" <div id=\"menu\">\n" +
|
||||
" <table>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <table class=\"room roomBlock1\">\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Save_config\">\n" +
|
||||
" <a href=\"/fhem?cmd=save\">Save config</a>\n" +
|
||||
" <a id=\"saveCheck\" class=\"changed\" style=\"visibility:visible\">?</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <table class=\"room roomBlock2\">\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Alexa\">\n" +
|
||||
" <a href=\"/fhem?room=Alexa\">Alexa</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_System\">\n" +
|
||||
" <a href=\"/fhem?room=System\">System</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_WG_Zimmer\">\n" +
|
||||
" <a href=\"/fhem?room=WG%2dZimmer\">WG-Zimmer</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_habridge\">\n" +
|
||||
" <a href=\"/fhem?room=habridge\">habridge</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Everything\">\n" +
|
||||
" <a href=\"/fhem?room=all\">\n" +
|
||||
" <img class='icon icoEverything' src=\"/fhem/images/default/icoEverything.png\" alt=\"icoEverything\" title=\"icoEverything\"> Everything\n" +
|
||||
" </a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <table class=\"room roomBlock3\">\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Logfile\">\n" +
|
||||
" <a href=\"/fhem/FileLog_logWrapper?dev=Logfile&type=text&file=fhem-2017-12.log\">Logfile</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div>\n" +
|
||||
" <a href=\"/fhem/docs/commandref.html\" target=\"_blank\" >Commandref</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div>\n" +
|
||||
" <a href=\"http://fhem.de/fhem.html#Documentation\" target=\"_blank\" >Remote doc</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Edit_files\">\n" +
|
||||
" <a href=\"/fhem?cmd=style%20list\">Edit files</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Select_style\">\n" +
|
||||
" <a href=\"/fhem?cmd=style%20select\">Select style</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>\n" +
|
||||
" <div class=\"menu_Event_monitor\">\n" +
|
||||
" <a href=\"/fhem?cmd=style%20eventMonitor\">Event monitor</a>\n" +
|
||||
" </div>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" <div id=\"hdr\">\n" +
|
||||
" <table border=\"0\" class=\"header\">\n" +
|
||||
" <tr>\n" +
|
||||
" <td style=\"padding:0\">\n" +
|
||||
" <form method=\"post\" action=\"/fhem\">\n" +
|
||||
" <input type=\"hidden\" name=\"fw_id\" value=\"7880\"/>\n" +
|
||||
" <input type=\"text\" name=\"cmd\" class=\"maininput\" size=\"40\" value=\"\"/>\n" +
|
||||
" </form>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
" </div>\n" +
|
||||
" <div id='content' >\n" +
|
||||
" <pre>{ \n" +
|
||||
" \"Arg\":\"room=habridge\", \n" +
|
||||
" \"Results\": [ \n" +
|
||||
" { \n" +
|
||||
" \"Name\":\"Arbeitslicht\", \n" +
|
||||
" \"PossibleSets\":\"on off\", \n" +
|
||||
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 readingList setList useSetExtensions disable disabledForIntervals event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride userattr\", \n" +
|
||||
" \"Internals\": { \n" +
|
||||
" \"NAME\": \"Arbeitslicht\", \n" +
|
||||
" \"NR\": \"28\", \n" +
|
||||
" \"STATE\": \"-\", \n" +
|
||||
" \"TYPE\": \"dummy\" \n" +
|
||||
" }, \n" +
|
||||
" \"Readings\": { \"state\": { \"Value\":\"on\", \"Time\":\"2017-12-14 15:41:05\" } }, \n" +
|
||||
" \"Attributes\": { \n" +
|
||||
" \"alexaName\": \"Arbeitslicht\", \n" +
|
||||
" \"alexaRoom\": \"alexaroom\", \n" +
|
||||
" \"fhem_widget_command\": \"{ \\u0022allowed_values\\u0022 : [ \\u0022on\\u0022 ], \\u0022order\\u0022 : 0}\", \n" +
|
||||
" \"icon\": \"scene_office\", \n" +
|
||||
" \"room\": \"Alexa,habridge\", \n" +
|
||||
" \"setList\": \"on off\", \n" +
|
||||
" \"stateFormat\": \"-\", \n" +
|
||||
" \"webCmd\": \"on\" \n" +
|
||||
" } \n" +
|
||||
" }, \n" +
|
||||
" { \n" +
|
||||
" \"Name\":\"DeckenlampeLinks\", \n" +
|
||||
" \"PossibleSets\":\"on off dim dimup dimdown HSV RGB sync pair unpair\", \n" +
|
||||
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 gamma dimStep defaultColor defaultRamp colorCast whitePoint event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride \n" +
|
||||
" <a href=\"/fhem?detail=AlleLampen\">AlleLampen</a> AlleLampen_map\n" +
|
||||
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude userattr\", \n" +
|
||||
" \"Internals\": { \n" +
|
||||
" \"CONNECTION\": \"bridge-V3\", \n" +
|
||||
" \"DEF\": \"RGBW2 bridge-V3:10.2.3.3\", \n" +
|
||||
" \"IP\": \"10.2.3.3\", \n" +
|
||||
" \"LEDTYPE\": \"RGBW2\", \n" +
|
||||
" \"NAME\": \"DeckenlampeLinks\", \n" +
|
||||
" \"NR\": \"18\", \n" +
|
||||
" \"NTFY_ORDER\": \"50-DeckenlampeLinks\", \n" +
|
||||
" \"PORT\": \"8899\", \n" +
|
||||
" \"PROTO\": \"0\", \n" +
|
||||
" \"SLOT\": \"5\", \n" +
|
||||
" \"STATE\": \"off\", \n" +
|
||||
" \"TYPE\": \"WifiLight\" \n" +
|
||||
" }, \n" +
|
||||
" \"Readings\": { \n" +
|
||||
" \"RGB\": { \"Value\":\"000000\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||
" \"brightness\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||
" \"hue\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||
" \"saturation\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
|
||||
" \"state\": { \"Value\":\"off\", \"Time\":\"2017-12-14 15:41:10\" } \n" +
|
||||
" }, \n" +
|
||||
" \"Attributes\": { \n" +
|
||||
" \"AlleLampen\": \"AlleLampen\", \n" +
|
||||
" \"DeckenLampen\": \"DeckenLampen\", \n" +
|
||||
" \"fhem_widget_command\": \"{ \\u0022locations\\u0022 : [ \\u0022APP\\u0022, \\u0022WATCH\\u0022, \\u0022WIDGET\\u0022 ], \\u0022allowed_values\\u0022 : [ \\u0022off\\u0022, \\u0022on\\u0022 ], \\u0022order\\u0022 : 6}\", \n" +
|
||||
" \"room\": \"habridge,Alexa,WG-Zimmer\", \n" +
|
||||
" \"userattr\": \"AlleLampen AlleLampen_map\n" +
|
||||
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude\", \n" +
|
||||
" \"webCmd\": \"RGB\", \n" +
|
||||
" \"widgetOverride\": \"RGB:colorpicker,RGB\" \n" +
|
||||
" } \n" +
|
||||
" } ], \n" +
|
||||
" \"totalResultsReturned\":2 \n" +
|
||||
"}\n" +
|
||||
" </pre>\n" +
|
||||
" </div>\n" +
|
||||
" </body>\n" +
|
||||
"</html>";
|
||||
|
||||
public final static String TestData2 = " <div id='content' >\n" +
|
||||
" <pre>\n" + "{ \"Arg\":\"room=HaBridge\", \"Results\": [ { \"Name\":\"wifi_steckdose3\", \"PossibleSets\":\"on:noArg off:noArg off on toggle\", \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\", \"Internals\": { \"CHANGED\": \"null\", \"NAME\": \"wifi_steckdose3\", \"NR\": \"270\", \"STATE\": \"off\", \"TYPE\": \"MQTT_DEVICE\", \"retain\": \"*:1 \" }, \"Readings\": { \"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-01 23:01:21\" }, \"transmission-state\": { \"Value\":\"subscription acknowledged\", \"Time\":\"2018-01-03 22:34:00\" } }, \"Attributes\": { \"IODev\": \"myBroker\", \"alias\": \"Stecki\", \"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\", \"event-on-change-reading\": \"state\", \"eventMap\": \"ON:on OFF:off\", \"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\", \"retain\": \"1\", \"room\": \"HaBridge,Arbeitszimmer,mqtt\", \"stateFormat\": \"state\", \"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\", \"webCmd\": \"on:off:toggle\" } } ], \"totalResultsReturned\":1 }" +
|
||||
" </pre>\n" +
|
||||
" </div>\n" +
|
||||
" </body>\n" +
|
||||
"</html>";
|
||||
public final static String TestData3 ="DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
|
||||
"<head root=\"/fhem\">\n" +
|
||||
"<title>Home, Sweet Home</title>\n" +
|
||||
"<link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
|
||||
"<meta charset=\"UTF-8\">\n" +
|
||||
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
|
||||
"<link href=\"/fhem/pgm2/style.css?v=1515015198\" rel=\"stylesheet\"/>\n" +
|
||||
"<link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/doif.js\"></script>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fronthemEditor.js\"></script>\n" +
|
||||
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
|
||||
"</head>\n" +
|
||||
"<body name='Home, Sweet Home' fw_id='1490' generated=\"1515770038\" longpoll=\"websocket\" data-confirmDelete='1' data-confirmJSError='1' data-addHtmlTitle='1' data-availableJs='sortable,iconLabel,readingsHistory,colorpicker,iconButtons,fbcalllist,knob,weekprofile,iconRadio,readingsGroup,iconSwitch,uzsu' data-webName='WEB '>\n" +
|
||||
"<div id=\"menuScrollArea\">\n" +
|
||||
"</div>\n" +
|
||||
"<div id='content' >\n" +
|
||||
"<pre>{\n" +
|
||||
"\"Arg\":\"room=HaBridge\",\n" +
|
||||
"\"Results\": [\n" +
|
||||
"{\n" +
|
||||
"\"Name\":\"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
|
||||
"\"PossibleSets\":\"on:noArg off:noArg off on toggle\",\n" +
|
||||
"\"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\",\n" +
|
||||
"\"Internals\": {\n" +
|
||||
"\"NAME\": \"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
|
||||
"\"NR\": \"270\",\n" +
|
||||
"\"STATE\": \"off\",\n" +
|
||||
"\"TYPE\": \"MQTT_DEVICE\",\n" +
|
||||
"\"retain\": \"*:1 \"\n" +
|
||||
"},\n" +
|
||||
"\"Readings\": {\n" +
|
||||
"\"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-07 05:16:01\" },\n" +
|
||||
"\"transmission-state\": { \"Value\":\"incoming publish received\", \"Time\":\"2018-01-07 05:16:01\" }\n" +
|
||||
"},\n" +
|
||||
"\"Attributes\": {\n" +
|
||||
"\"IODev\": \"<a href='/fhem?detail=myBroker'>myBroker</a>\",\n" +
|
||||
"\"alias\": \"Stecki\",\n" +
|
||||
"\"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\",\n" +
|
||||
"\"event-on-change-reading\": \"state\",\n" +
|
||||
"\"eventMap\": \"ON:on OFF:off\",\n" +
|
||||
"\"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\",\n" +
|
||||
"\"retain\": \"1\",\n" +
|
||||
"\"room\": \"HaBridge,Arbeitszimmer,mqtt\",\n" +
|
||||
"\"stateFormat\": \"state\",\n" +
|
||||
"\"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\",\n" +
|
||||
"\"webCmd\": \"on:off:toggle\"\n" +
|
||||
"}\n" +
|
||||
"} ],\n" +
|
||||
"\"totalResultsReturned\":1\n" +
|
||||
"}\n" +
|
||||
"</pre>\n" +
|
||||
"</div>\n" +
|
||||
"</body></html>";
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.fhem;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Result {
|
||||
|
||||
@SerializedName("Name")
|
||||
@Expose
|
||||
private String name;
|
||||
@SerializedName("PossibleSets")
|
||||
@Expose
|
||||
private String possibleSets;
|
||||
@SerializedName("PossibleAttrs")
|
||||
@Expose
|
||||
private String possibleAttrs;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPossibleSets() {
|
||||
return possibleSets;
|
||||
}
|
||||
|
||||
public void setPossibleSets(String possibleSets) {
|
||||
this.possibleSets = possibleSets;
|
||||
}
|
||||
|
||||
public String getPossibleAttrs() {
|
||||
return possibleAttrs;
|
||||
}
|
||||
|
||||
public void setPossibleAttrs(String possibleAttrs) {
|
||||
this.possibleAttrs = possibleAttrs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro;
|
||||
|
||||
public class FibaroFilter {
|
||||
boolean useSaveLogs;
|
||||
boolean useUserDescription;
|
||||
boolean scenesLiliCmddOnly;
|
||||
boolean replaceTrash;
|
||||
|
||||
public boolean isUseSaveLogs() {
|
||||
return useSaveLogs;
|
||||
}
|
||||
public void setUseSaveLogs(boolean useSaveLogs) {
|
||||
this.useSaveLogs = useSaveLogs;
|
||||
}
|
||||
public boolean isUseUserDescription() {
|
||||
return useUserDescription;
|
||||
}
|
||||
public void setUseUserDescription(boolean useUserDescription) {
|
||||
this.useUserDescription = useUserDescription;
|
||||
}
|
||||
public boolean isReplaceTrash() {
|
||||
return replaceTrash;
|
||||
}
|
||||
public void setReplaceTrash(boolean replaceTrash) {
|
||||
this.replaceTrash = replaceTrash;
|
||||
}
|
||||
public boolean isScenesLiliCmddOnly() {
|
||||
return scenesLiliCmddOnly;
|
||||
}
|
||||
public void setScenesLiliCmddOnly(boolean scenesLiliCmddOnly) {
|
||||
this.scenesLiliCmddOnly = scenesLiliCmddOnly;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.plugins.fibaro.json.Device;
|
||||
import com.bwssystems.HABridge.plugins.fibaro.json.Scene;
|
||||
|
||||
public class FibaroHome implements Home
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(FibaroHome.class);
|
||||
private Map<String, FibaroInfo> fibaros;
|
||||
private Boolean validFibaro;
|
||||
private boolean closed;
|
||||
|
||||
public FibaroHome(BridgeSettings bridgeSettings)
|
||||
{
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
public List<Device> getDevices()
|
||||
{
|
||||
log.debug("consolidating devices for fibaros");
|
||||
Iterator<String> keys = fibaros.keySet().iterator();
|
||||
ArrayList<Device> deviceList = new ArrayList<>();
|
||||
while(keys.hasNext())
|
||||
{
|
||||
String key = keys.next();
|
||||
for(Device device : fibaros.get(key).getDevices())
|
||||
deviceList.add(device);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public List<Scene> getScenes()
|
||||
{
|
||||
log.debug("consolidating scenes for fibaros");
|
||||
Iterator<String> keys = fibaros.keySet().iterator();
|
||||
ArrayList<Scene> sceneList = new ArrayList<>();
|
||||
while(keys.hasNext())
|
||||
{
|
||||
String key = keys.next();
|
||||
for(Scene scene : fibaros.get(key).getScenes())
|
||||
sceneList.add(scene);
|
||||
}
|
||||
return sceneList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body)
|
||||
{
|
||||
// Not a device handler
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type)
|
||||
{
|
||||
if(validFibaro)
|
||||
{
|
||||
if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]))
|
||||
return getDevices();
|
||||
if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex]))
|
||||
return getScenes();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings)
|
||||
{
|
||||
validFibaro = bridgeSettings.getBridgeSettingsDescriptor().isValidFibaro();
|
||||
log.info("Fibaro Home created." + (validFibaro ? "" : " No Fibaros configured."));
|
||||
if(validFibaro)
|
||||
{
|
||||
fibaros = new HashMap<String, FibaroInfo>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getFibaroAddress().getDevices().iterator();
|
||||
while(theList.hasNext())
|
||||
{
|
||||
NamedIP aFibaro = theList.next();
|
||||
fibaros.put(aFibaro.getName(), new FibaroInfo(aFibaro));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome()
|
||||
{
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
fibaros = null;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.plugins.fibaro.json.Device;
|
||||
import com.bwssystems.HABridge.plugins.fibaro.json.Room;
|
||||
import com.bwssystems.HABridge.plugins.fibaro.json.Scene;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class FibaroInfo
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(FibaroInfo.class);
|
||||
|
||||
private final NamedIP fibaroAddress;
|
||||
private final String fibaroAuth;
|
||||
private final Gson gson;
|
||||
private Boolean isDevMode;
|
||||
private FibaroFilter theFilters;
|
||||
|
||||
public FibaroInfo(NamedIP addressName)
|
||||
{
|
||||
super();
|
||||
fibaroAddress = addressName;
|
||||
fibaroAuth = "Basic " + addressName.getUserPass64();
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
gson = new Gson();
|
||||
theFilters = null;
|
||||
if(fibaroAddress.getExtensions() != null) {
|
||||
try {
|
||||
theFilters = gson.fromJson(fibaroAddress.getExtensions(), FibaroFilter.class);
|
||||
} catch(Exception e) {
|
||||
log.warn("Could not read fibaro filters - continuing with defaults.");
|
||||
theFilters = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(theFilters == null) {
|
||||
theFilters = new FibaroFilter();
|
||||
theFilters.setUseSaveLogs(false);
|
||||
theFilters.setUseUserDescription(false);
|
||||
theFilters.setScenesLiliCmddOnly(false);
|
||||
theFilters.setReplaceTrash(true);
|
||||
}
|
||||
}
|
||||
|
||||
private String request(String request)
|
||||
{
|
||||
String result = null;
|
||||
try
|
||||
{
|
||||
URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("Authorization", fibaroAuth);
|
||||
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||
connection.connect();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
while((line = br.readLine()) != null)
|
||||
{
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
br.close();
|
||||
result = buffer.toString();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
log.warn("Error while get getJson: {} ", request, e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String replaceTrash(String name)
|
||||
{
|
||||
String sanitizedName = name.replaceAll("[0-9:/-]", "");
|
||||
sanitizedName = name.replaceAll("\\s+", " ");
|
||||
return sanitizedName.trim();
|
||||
}
|
||||
|
||||
private Room[] getRooms()
|
||||
{
|
||||
String result = null;
|
||||
if(isDevMode)
|
||||
result = FibaroTestData.RoomTestData;
|
||||
else
|
||||
result = request("/api/rooms");
|
||||
log.debug("getRooms response: <<<" + result + ">>>");
|
||||
Room[] rooms = result == null ? new Room[0] : gson.fromJson(result, Room[].class);
|
||||
if(theFilters.isReplaceTrash())
|
||||
for(Room r : rooms)
|
||||
r.setName(replaceTrash(r.getName()));
|
||||
return rooms;
|
||||
}
|
||||
|
||||
public Device[] getDevices()
|
||||
{
|
||||
Room[] rooms = getRooms();
|
||||
|
||||
log.debug("getDevices Found: " + rooms.length + " rooms");
|
||||
|
||||
String result = null;
|
||||
if(isDevMode)
|
||||
result = FibaroTestData.DeviceTestData;
|
||||
else
|
||||
result = request("/api/devices?enabled=true&visible=true");
|
||||
log.debug("getDevices response: <<<" + result + ">>>");
|
||||
Device[] all_devices = result == null ? new Device[0] : gson.fromJson(result, Device[].class);
|
||||
|
||||
int count = 0;
|
||||
for(Device d : all_devices)
|
||||
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
|
||||
count++;
|
||||
|
||||
Device[] devices = new Device[count];
|
||||
int i = 0;
|
||||
for(Device d : all_devices)
|
||||
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
|
||||
{
|
||||
if(theFilters.isUseUserDescription() && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
|
||||
d.setName(d.getProperties().getUserDescription());
|
||||
if(theFilters.isReplaceTrash())
|
||||
d.setName(replaceTrash(d.getName()));
|
||||
|
||||
devices[i++] = d;
|
||||
|
||||
for(Room room : rooms)
|
||||
if(d.getRoomID() == room.getId())
|
||||
d.setRoomName(room.getName());
|
||||
|
||||
d.fibaroaddress = fibaroAddress.getIp();
|
||||
d.fibaroport = fibaroAddress.getPort();
|
||||
d.fibaroAuth = fibaroAuth;
|
||||
d.fibaroname = fibaroAddress.getName();
|
||||
}
|
||||
|
||||
log.debug("getDevices Found: " + devices.length + " devices");
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
public Scene[] getScenes()
|
||||
{
|
||||
Room[] rooms = getRooms();
|
||||
|
||||
String result = null;
|
||||
if(isDevMode)
|
||||
result = FibaroTestData.SceneTestData;
|
||||
else
|
||||
result = request("/api/scenes?enabled=true&visible=true");
|
||||
log.debug("getScenes response: <<<" + result + ">>>");
|
||||
Scene[] all_scenes = result == null ? new Scene[0] : gson.fromJson(result, Scene[].class);
|
||||
|
||||
int count = 0;
|
||||
for(Scene s : all_scenes)
|
||||
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
|
||||
count++;
|
||||
Scene[] scenes = new Scene[count];
|
||||
int i = 0;
|
||||
for(Scene s : all_scenes)
|
||||
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
|
||||
{
|
||||
if(theFilters.isReplaceTrash())
|
||||
s.setName(replaceTrash(s.getName()));
|
||||
|
||||
scenes[i++] = s;
|
||||
|
||||
for(Room room : rooms)
|
||||
if(s.getRoomID() == room.getId())
|
||||
s.setRoomName(room.getName());
|
||||
|
||||
s.fibaroaddress = fibaroAddress.getIp();
|
||||
s.fibaroport = fibaroAddress.getPort();
|
||||
s.fibaroAuth = fibaroAuth;
|
||||
s.fibaroname = fibaroAddress.getName();
|
||||
}
|
||||
log.debug("getScenes Found: " + count + " scenes");
|
||||
return scenes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro;
|
||||
|
||||
public class FibaroTestData {
|
||||
public final static String DeviceTestData = "[{\"id\":7,\"name\":\"Deckenspots\",\"roomID\":12,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":5,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"7.23\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"2\",\"parametersTemplate\":\"796\",\"power\":\"5.80\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"25\",\"serialNumber\":\"h'000000000001c1b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"5\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":1},{\"id\":13,\"name\":\"Licht Küche\",\"roomID\":13,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":fals" +
|
||||
"e,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"9.51\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"16.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":2},{\"id\":14,\"name\":\"Lampe Tisch\",\"roomID\":14,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"2\",\"energy\":\"29.15\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":" +
|
||||
"\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"11.50\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":3},{\"id\":18,\"name\":\"Licht\",\"roomID\":16,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":15,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"2.70\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"4\",\"parametersTemplate\":\"781\",\"power\":\"0.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'00000000000044b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTempl" +
|
||||
"ate\":\"true\",\"userDescription\":\"\",\"value\":\"false\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":4},{\"id\":26,\"name\":\"Licht\",\"roomID\":5,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":24,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"28.02\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"7\",\"parametersTemplate\":\"796\",\"power\":\"0.00\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"h'0000000000001fec\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":5},{\"id\":57,\"name\":\"Fenster rechts\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":56,\"remoteGatewayId\"" +
|
||||
":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.78\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"19\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":12},{\"id\":60,\"name\":\"Fenster mitte\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":59,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlT" +
|
||||
"ype\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.71\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"20\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"26\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":13},{\"id\":74,\"name\":\"Fenster links\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":73,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.64\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"21\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0" +
|
||||
",25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":14},{\"id\":77,\"name\":\"Fenster Sideboard\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":76,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.63\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"22\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneAc" +
|
||||
"tivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":15},{\"id\":112,\"name\":\"Stehlampe\",\"roomID\":12,\"type\":\"com.fibaro.multilevelSwitch\",\"baseType\":\"com.fibaro.binarySwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":111,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Domitech Products\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"5.14\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"5.14\\\"}\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"27\",\"parametersTemplate\":\"807\",\"productInfo\":\"2,14,76,66,49,52,5,14\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"retryUpdate\":1,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":6},{\"id\":114,\"name\":\"RGBW\",\"roomID\":12,\"type\":\"com.fibaro.FGRGBW441M\",\"baseType\":\"com.fibaro.colorController\",\"enabled\":true,\"visible\":tr" +
|
||||
"ue,\"isPlugin\":false,\"parentId\":113,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"26.25\",\"associationMode\":\"0\",\"brightness\":\"0\",\"buttonType\":\"0\",\"color\":\"0,0,0,0\",\"configured\":true,\"currentProgram\":\"0\",\"currentProgramID\":\"0\",\"dead\":\"false\",\"deviceControlType\":\"50\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"1.72\",\"favoriteProgram\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"26.25\\\"}\",\"isLight\":\"true\",\"lastColorSet\":\"0,0,0,0\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"mode\":\"0\",\"model\":\"\",\"nodeId\":\"28\",\"parametersTemplate\":\"231\",\"power\":\"0.00\",\"productInfo\":\"1,15,9,0,16,0,26,25\",\"programsSortOrder\":\"1,2,3,4,5\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"rememberColor\":\"false\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"setB\":1,\"setBrightness\":1,\"setColor\":1,\"setFavoriteProgram\":2,\"setG\":1,\"setR\":1,\"setValue\":1,\"setW\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startProgram\":1,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":7},{\"id\":122,\"name\":\"Fenster\",\"roomID\":12,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":121,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"powe" +
|
||||
"r\",\"zwave\",\"zwaveConfiguration\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"24.24\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.17\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"24.24\\\"}\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"29\",\"parametersTemplate\":\"249\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,1,16,1,24,24\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"abortUpdate\":1,\"close\":0,\"getParameter\":1,\"open\":0,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"sceneActivationSet\":0,\"setParameter\":2,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stop\":0,\"stopLevelChange\":0,\"updateFirmware\":1},\"created\":1516643108,\"modified\":1516643108,\"sortOrder\":16}]";
|
||||
|
||||
public final static String RoomTestData = "[{\"id\":4,\"name\":\"Dachboden\",\"sectionID\":4,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":1},{\"id\":5,\"name\":\"Badezimmer\",\"sectionID\":5,\"icon\":\"room_wanna\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":2},{\"id\":6,\"name\":\"Büro\",\"sectionID\":5,\"icon\":\"room_office\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":3},{\"id\":7,\"name\":\"Flur\",\"sectionID\":5,\"icon\":\"room_schody2\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":4},{\"id\":8,\"name\":\"Schlafzimmer\",\"sectionID\":5,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":5},{\"id\":9,\"name\":\"Emelie\",\"sectionID\":5,\"icon\":\"room_wardrobe\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":6},{\"id\":10,\"name\":\"Mino\",\"sectionID\":5,\"icon\":\"room_garage\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":7},{\"id\":11,\"name\":\"Flur\",\"sectionID\":6,\"icon\":\"room_drzwiwejsciowe\",\"defaultSensors\":{\"temperature\":181,\"humidity\":0,\"light\":182},\"defaultThermostat\":0,\"sortOrder\":8},{\"id\":12,\"name\":\"Wohnzimmer\",\"sectionID\":6,\"icon\":\"room_sofa\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":9},{\"id\":13,\"name\":\"Küche\",\"sectionID\":6,\"icon\":\"room_dining\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":10},{\"id\":14,\"name\":\"Esszimmer\",\"sectionID\":6,\"icon\":\"room_jadalnia\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":11},{\"id\":15,\"name\":\"HWR\",\"sectionID\":6,\"icon\":\"room_laundry\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":12},{\"id\":16,\"name\":\"Gäste WC\",\"sectionID\":6," +
|
||||
"\"icon\":\"room_toilet\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":13},{\"id\":17,\"name\":\"Haus\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":14},{\"id\":18,\"name\":\"Terrasse\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":15}]";
|
||||
|
||||
public final static String SceneTestData = "[" +
|
||||
"{\"id\":33,\"name\":\"Fernsehlicht aus\",\"type\":\"com.fibaro.luaScene\",\"roomID\":12,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":4,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":17}," +
|
||||
"{\"id\":68,\"name\":\"Rollos runterfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":8}," +
|
||||
"{\"id\":69,\"name\":\"Rollos hochfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":9}," +
|
||||
"{\"id\":93,\"name\":\"Alles aus Haus\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent1HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 1 HeldDown\\\\n163 CentralSceneEvent 1 Released\\\",\\\"actionDeviceId\\\":92,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_92\\\",\\\"actionLua\\\":\\\"fibaro:startScene(92);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"1\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[92],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":18}," +
|
||||
"{\"id\":94,\"name\":\"Fernsehlicht an\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":10}," +
|
||||
"{\"id\":95,\"name\":\"Fernsehlicht + aus\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,57,60,74,77,97,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":19}," +
|
||||
"{\"id\":96,\"name\":\"Fernsehlicht Wohnzim\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent2Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 2 Pressed\\\",\\\"actionDeviceId\\\":94,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_94\\\",\\\"actionLua\\\":\\\"fibaro:startScene(94);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"2\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[94],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":20}," +
|
||||
"{\"id\":98,\"name\":\"Fersehlicht blau\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":11}," +
|
||||
"{\"id\":99,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":21}," +
|
||||
"{\"id\":100,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 HeldDown\\\\n163 CentralSceneEvent 3 Released\\\",\\\"actionDeviceId\\\":99,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_99\\\",\\\"actionLua\\\":\\\"fibaro:startScene(99);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[99],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":22}," +
|
||||
"{\"id\":101,\"name\":\"Fersehlicht blau Woh\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 Pressed\\\",\\\"actionDeviceId\\\":98,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_98\\\",\\\"actionLua\\\":\\\"fibaro:startScene(98);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[98],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":23}" +
|
||||
"]";
|
||||
|
||||
public final static String CallActionTestData = "Fiabro action received";
|
||||
public final static String SceneControlTestData = "Fiabro scene control received";
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Device {
|
||||
private String roomName;
|
||||
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("roomID")
|
||||
private int roomID;
|
||||
|
||||
@SerializedName("type")
|
||||
private String type;
|
||||
|
||||
@SerializedName("properties")
|
||||
private DeviceProperties properties;
|
||||
|
||||
public String getRoomName() {
|
||||
return roomName;
|
||||
}
|
||||
|
||||
public void setRoomName(String roomName) {
|
||||
this.roomName = roomName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getRoomID() {
|
||||
return roomID;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public DeviceProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public boolean isThermostat() {
|
||||
return type.equals("com.fibaro.setPoint") || type.equals("com.fibaro.thermostatDanfoss")
|
||||
|| type.equals("com.fibaro.thermostatHorstmann");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + id + ", " + name + "}";
|
||||
}
|
||||
|
||||
public String fibaroaddress;
|
||||
public String fibaroport;
|
||||
public String fibaroAuth;
|
||||
public String fibaroname;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class DeviceProperties {
|
||||
@SerializedName("value")
|
||||
private String value;
|
||||
|
||||
@SerializedName("saveLogs")
|
||||
private String saveLogs;
|
||||
|
||||
@SerializedName("userDescription")
|
||||
private String userDescription;
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public String getSaveLogs() {
|
||||
return saveLogs;
|
||||
}
|
||||
public String getUserDescription() {
|
||||
return userDescription;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Room {
|
||||
@SerializedName("id")
|
||||
private int id;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("sectionID")
|
||||
private int sectionID;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getSectionID()
|
||||
{
|
||||
return sectionID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.bwssystems.HABridge.plugins.fibaro.json;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Scene {
|
||||
private String roomName;
|
||||
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("type")
|
||||
private String type;
|
||||
|
||||
@SerializedName("roomID")
|
||||
private int roomID;
|
||||
|
||||
@SerializedName("liliStartCommand")
|
||||
private String liliStartCommand;
|
||||
|
||||
public String getRoomName() {
|
||||
return roomName;
|
||||
}
|
||||
|
||||
public void setRoomName(String roomName) {
|
||||
this.roomName = roomName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getRoomID() {
|
||||
return roomID;
|
||||
}
|
||||
|
||||
public String getLiliStartCommand()
|
||||
{
|
||||
return liliStartCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + id + ", " + name + "}";
|
||||
}
|
||||
|
||||
public String fibaroaddress;
|
||||
public String fibaroport;
|
||||
public String fibaroAuth;
|
||||
public String fibaroname;
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.bwssystems.HABridge.plugins.hal;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class HalDevice {
|
||||
private String haldevicetype;
|
||||
private String haldevicename;
|
||||
private String haladdress;
|
||||
private String halname;
|
||||
private NamedIP haladdress;
|
||||
private DeviceElements buttons;
|
||||
public String getHaldevicetype() {
|
||||
return haldevicetype;
|
||||
@@ -18,18 +19,12 @@ public class HalDevice {
|
||||
public void setHaldevicename(String haldevicename) {
|
||||
this.haldevicename = haldevicename;
|
||||
}
|
||||
public String getHaladdress() {
|
||||
public NamedIP getHaladdress() {
|
||||
return haladdress;
|
||||
}
|
||||
public void setHaladdress(String haladdress) {
|
||||
public void setHaladdress(NamedIP haladdress) {
|
||||
this.haladdress = haladdress;
|
||||
}
|
||||
public String getHalname() {
|
||||
return halname;
|
||||
}
|
||||
public void setHalname(String halname) {
|
||||
this.halname = halname;
|
||||
}
|
||||
public DeviceElements getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -13,24 +13,34 @@ 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.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HalHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||
private Map<String, HalInfo> hals;
|
||||
private Boolean validHal;
|
||||
private boolean closed;
|
||||
|
||||
public HalHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
if(!validHal)
|
||||
return null;
|
||||
log.debug("consolidating devices for hues");
|
||||
log.debug("consolidating devices for HALs");
|
||||
List<HalDevice> theResponse = null;
|
||||
Iterator<String> keys = hals.keySet().iterator();
|
||||
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||
@@ -94,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();
|
||||
@@ -103,11 +113,71 @@ 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, DeviceDescriptor device, String body) {
|
||||
// Not a device handler
|
||||
return null;
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
boolean halFound = false;
|
||||
String responseString = null;
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.contains("http")) {
|
||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
// String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||
// String hostAddr = null;
|
||||
// String port = null;
|
||||
// if (hostPortion.contains(":")) {
|
||||
// hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||
// port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||
// } else
|
||||
// hostAddr = hostPortion;
|
||||
log.debug("executing HUE api request to Http "
|
||||
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
||||
+ anItem.getItem().getAsString());
|
||||
|
||||
String anUrl = null;
|
||||
|
||||
anUrl = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
for (Map.Entry<String, HalInfo> entry : hals.entrySet())
|
||||
{
|
||||
if(entry.getValue().getHalAddress().getIp().equals(hostPortion)) {
|
||||
halFound = true;
|
||||
if(entry.getValue().getHalAddress().getSecure()!= null && entry.getValue().getHalAddress().getSecure())
|
||||
anUrl = "https://" + anUrl;
|
||||
else
|
||||
anUrl = "http://" + anUrl;
|
||||
|
||||
if(!anUrl.contains("?Token="))
|
||||
anUrl = anUrl + "?Token=" + entry.getValue().getHalAddress().getPassword();
|
||||
|
||||
log.debug("executing HUE api request to Http "
|
||||
+ (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
|
||||
+ anUrl);
|
||||
|
||||
if (entry.getValue().deviceCommand(anUrl) == null) {
|
||||
log.warn("Error on calling hal to change device state: " + anUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!halFound) {
|
||||
log.warn("No HAL found to call: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"No HAL found.", "/lights/"
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,7 +202,13 @@ public class HalHome implements Home {
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
// noop
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
hals = null;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
import com.bwssystems.HABridge.util.TextStringFormatter;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@@ -35,13 +36,13 @@ public class HalInfo {
|
||||
private static final String IRDATA_TYPE = "IrData";
|
||||
private HTTPHandler httpClient;
|
||||
private NamedIP halAddress;
|
||||
private String theToken;
|
||||
|
||||
public HalInfo(NamedIP addressName, String aGivenToken) {
|
||||
super();
|
||||
httpClient = new HTTPHandler();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
halAddress = addressName;
|
||||
theToken = aGivenToken;
|
||||
if(halAddress.getPassword() == null || halAddress.getPassword().trim().isEmpty())
|
||||
halAddress.setPassword(aGivenToken);
|
||||
}
|
||||
|
||||
public List<HalDevice> getLights() {
|
||||
@@ -98,12 +99,16 @@ public class HalInfo {
|
||||
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
||||
if(halAddress.getSecure()!= null && halAddress.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
theUrl = theUrl + halAddress.getIp() + apiType + halAddress.getPassword();
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
if(theData != null) {
|
||||
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||
if(theHalApiResponse.getDeviceElements() == null) {
|
||||
if(theHalApiResponse == null || theHalApiResponse.getDeviceElements() == null) {
|
||||
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||
if(theStatus.getStatus() == null) {
|
||||
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
||||
@@ -121,8 +126,10 @@ public class HalInfo {
|
||||
HalDevice aNewHalDevice = new HalDevice();
|
||||
aNewHalDevice.setHaldevicetype(deviceType);
|
||||
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||
aNewHalDevice.setHaladdress(halAddress.getIp());
|
||||
aNewHalDevice.setHalname(halAddress.getName());
|
||||
NamedIP theaddress = new NamedIP();
|
||||
theaddress.setIp(halAddress.getIp());
|
||||
theaddress.setName(halAddress.getName());
|
||||
aNewHalDevice.setHaladdress(theaddress);
|
||||
deviceList.add(aNewHalDevice);
|
||||
|
||||
}
|
||||
@@ -145,7 +152,11 @@ public class HalInfo {
|
||||
deviceList = new ArrayList<HalDevice>();
|
||||
while (theHalDevices.hasNext()) {
|
||||
HalDevice theHalDevice = theHalDevices.next();
|
||||
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||
if(halAddress.getSecure()!= null && halAddress.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
theUrl = theUrl + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + halAddress.getPassword();
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
if (theData != null) {
|
||||
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||
@@ -177,6 +188,12 @@ public class HalInfo {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public String deviceCommand(String theUrl) {
|
||||
String theData = null;
|
||||
theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
|
||||
return theData;
|
||||
}
|
||||
|
||||
public NamedIP getHalAddress() {
|
||||
return halAddress;
|
||||
}
|
||||
@@ -190,6 +207,5 @@ public class HalInfo {
|
||||
httpClient.closeHandler();
|
||||
httpClient = null;
|
||||
halAddress = null;
|
||||
theToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ public class ButtonPress {
|
||||
private Integer delay;
|
||||
private Integer count;
|
||||
private String hub;
|
||||
private Integer pressTime;
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
@@ -43,4 +44,10 @@ public class ButtonPress {
|
||||
public void setHub(String hub) {
|
||||
this.hub = hub;
|
||||
}
|
||||
public Integer getPressTime() {
|
||||
return pressTime;
|
||||
}
|
||||
public void setPressTime(Integer pressTime) {
|
||||
this.pressTime = pressTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.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,19 +70,33 @@ 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) {
|
||||
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls);
|
||||
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub() + " noop mode: " + noopCalls);
|
||||
if (anActivity.isValid()) {
|
||||
try {
|
||||
if (noopCalls || devMode) {
|
||||
@@ -72,7 +106,7 @@ public class HarmonyHandler {
|
||||
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
||||
}
|
||||
|
||||
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName());
|
||||
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||
}
|
||||
else
|
||||
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
||||
@@ -81,39 +115,56 @@ public class HarmonyHandler {
|
||||
if (!noopCalls)
|
||||
harmonyClient.startActivityByName(anActivity.getName());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding activity: " + anActivity.getName());
|
||||
return false;
|
||||
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding activity: " + anActivity.getName());
|
||||
return false;
|
||||
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean pressButton(ButtonPress aDeviceButton) {
|
||||
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls);
|
||||
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " with pressTime of: " + aDeviceButton.getPressTime() + " for a hub: " + aDeviceButton.getHub() + " noop mode: " + noopCalls);
|
||||
if (aDeviceButton.isValid()) {
|
||||
try {
|
||||
if (noopCalls || devMode) {
|
||||
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton());
|
||||
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() +
|
||||
" with a pressTime of: " + aDeviceButton.getPressTime() + " for a hub: " + aDeviceButton.getHub());
|
||||
}
|
||||
else
|
||||
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||
|
||||
else {
|
||||
if(aDeviceButton.getPressTime() != null && aDeviceButton.getPressTime() > 0)
|
||||
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton(), aDeviceButton.getPressTime());
|
||||
else
|
||||
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||
return false;
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
|
||||
} 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());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -124,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -26,98 +27,152 @@ 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;
|
||||
private Gson aGsonHandler;
|
||||
private boolean closed;
|
||||
|
||||
public HarmonyHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
if(!validHarmony)
|
||||
if (!validHarmony)
|
||||
return;
|
||||
if(isDevMode || hubs == null)
|
||||
log.debug("Closing Home.");
|
||||
if (closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
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;
|
||||
@@ -125,36 +180,47 @@ public class HarmonyHome implements Home {
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String responseString = null;
|
||||
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();
|
||||
@@ -162,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() + " - 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;
|
||||
@@ -198,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");
|
||||
@@ -216,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);
|
||||
@@ -236,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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import static java.lang.String.format;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
|
||||
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;
|
||||
@@ -44,15 +45,14 @@ public class HarmonyServer {
|
||||
dummyProvider = null;
|
||||
myNameAndIP = theHarmonyAddress;
|
||||
isDevMode = false;
|
||||
httpClient = new HTTPHandler();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -63,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 = "";
|
||||
@@ -108,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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -25,10 +26,13 @@ public class HassHome implements Home {
|
||||
private Map<String, HomeAssistant> hassMap;
|
||||
private Boolean validHass;
|
||||
private Gson aGsonHandler;
|
||||
private boolean closed;
|
||||
|
||||
public HassHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,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();
|
||||
@@ -113,31 +117,35 @@ 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, DeviceDescriptor device, String body) {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String theReturn = null;
|
||||
log.debug("executing HUE api request to send message to HomeAssistant: " + anItem.getItem().toString());
|
||||
if(!validHass) {
|
||||
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.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(),
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
|
||||
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class);
|
||||
hassCommand.setBri(BrightnessDecode.calculateReplaceIntensityValue(hassCommand.getBri(), intensity, targetBri, targetBriInc, false));
|
||||
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
|
||||
if (homeAssistant == null) {
|
||||
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());
|
||||
@@ -151,6 +159,11 @@ public class HassHome implements Home {
|
||||
public void closeHome() {
|
||||
if(!validHass)
|
||||
return;
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
if(hassMap == null)
|
||||
return;
|
||||
Iterator<String> keys = hassMap.keySet().iterator();
|
||||
@@ -160,5 +173,6 @@ public class HassHome implements Home {
|
||||
}
|
||||
|
||||
hassMap = null;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,23 @@ import org.slf4j.LoggerFactory;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
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 = new HTTPHandler();
|
||||
hassAddress = addressName;
|
||||
anHttpHandler = HTTPHome.getHandler();
|
||||
hassAddress = addressName;
|
||||
theAuthType = null;
|
||||
headers = null;
|
||||
isLegacyAuth();
|
||||
}
|
||||
|
||||
public NamedIP getHassAddress() {
|
||||
@@ -34,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;
|
||||
}
|
||||
|
||||
@@ -77,39 +71,69 @@ 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);
|
||||
if(theAuthType == null) {
|
||||
theAuthType = new HassAuth();
|
||||
theAuthType.setLegacyauth(false);
|
||||
}
|
||||
} 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[2];
|
||||
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());
|
||||
}
|
||||
headers[1] = new NameValue();
|
||||
headers[1].setName("Accept-Encoding");
|
||||
headers[1].setValue("gzip");
|
||||
}
|
||||
} else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) {
|
||||
headers = null;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class HomeGenieCommand {
|
||||
@SerializedName("moduleType")
|
||||
@Expose
|
||||
private String moduleType;
|
||||
@SerializedName("deviceId")
|
||||
@Expose
|
||||
private String deviceId;
|
||||
@SerializedName("command")
|
||||
@Expose
|
||||
private HomeGenieCommandDetail command;
|
||||
|
||||
public String getModuleType() {
|
||||
return moduleType;
|
||||
}
|
||||
|
||||
public void setModuleType(String moduleType) {
|
||||
this.moduleType = moduleType;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public HomeGenieCommandDetail getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(HomeGenieCommandDetail command) {
|
||||
this.command = command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class HomeGenieCommandDetail {
|
||||
@SerializedName("command")
|
||||
@Expose
|
||||
private String command;
|
||||
@SerializedName("level")
|
||||
@Expose
|
||||
private String level;
|
||||
@SerializedName("color")
|
||||
@Expose
|
||||
private String color;
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class HomeGenieDevice {
|
||||
@SerializedName("gatewayName")
|
||||
@Expose
|
||||
private String gatewayName;
|
||||
@SerializedName("deviceDetail")
|
||||
@Expose
|
||||
private Module deviceDetail;
|
||||
|
||||
public String getGatewayName() {
|
||||
return gatewayName;
|
||||
}
|
||||
|
||||
public void setGatewayName(String gatewayName) {
|
||||
this.gatewayName = gatewayName;
|
||||
}
|
||||
|
||||
public Module getDeviceDetail() {
|
||||
return deviceDetail;
|
||||
}
|
||||
|
||||
public void setDeviceDetail(Module deviceDetail) {
|
||||
this.deviceDetail = deviceDetail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HomeGenieHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeGenieHome.class);
|
||||
private Map<String, HomeGenieInstance> homegenieMap;
|
||||
private Boolean validHomeGenie;
|
||||
private HTTPHandler httpClient;
|
||||
private boolean closed;
|
||||
|
||||
public HomeGenieHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
String responseString = null;
|
||||
|
||||
if (theUrl != null && !theUrl.isEmpty()) {
|
||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl, intensity, targetBri, targetBriInc,
|
||||
false);
|
||||
if (colorData != null) {
|
||||
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||
}
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
anUrl = BrightnessDecode.calculateReplaceIntensityValue(anUrl, intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
}
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
HomeGenieCommand theCommand = null;
|
||||
try {
|
||||
theCommand = new Gson().fromJson(anUrl, HomeGenieCommand.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot parse command to HomeGenie <<<" + theUrl + ">>>", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
return responseString;
|
||||
}
|
||||
|
||||
HomeGenieInstance theHandler = homegenieMap.get(device.getTargetDevice());
|
||||
if (theHandler != null) {
|
||||
try {
|
||||
boolean success = theHandler.callCommand(theCommand.getDeviceId(), theCommand.getModuleType(), theCommand.getCommand(), httpClient);
|
||||
if (!success) {
|
||||
log.warn("Comand had error to HomeGenie");
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null,
|
||||
null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot send comand to HomeGenie", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn("HomeGenie Call could not complete, no address found: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn(
|
||||
"HomeGenie Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: "
|
||||
+ theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
|
||||
if (!validHomeGenie)
|
||||
return null;
|
||||
log.debug("consolidating devices for HomeGenie");
|
||||
List<Module> theResponse = null;
|
||||
Iterator<String> keys = homegenieMap.keySet().iterator();
|
||||
List<HomeGenieDevice> deviceList = new ArrayList<HomeGenieDevice>();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = homegenieMap.get(key).getDevices(httpClient);
|
||||
if (theResponse != null)
|
||||
addHomeGenieDevices(deviceList, theResponse, key);
|
||||
else {
|
||||
log.warn("Cannot get devices for HomeGenie with name: " + key + ", skipping this HomeGenie.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private Boolean addHomeGenieDevices(List<HomeGenieDevice> theDeviceList, List<Module> theSourceList,
|
||||
String theKey) {
|
||||
Iterator<Module> hgModules = theSourceList.iterator();
|
||||
while (hgModules.hasNext()) {
|
||||
Module aModule = hgModules.next();
|
||||
HomeGenieDevice theDevice = new HomeGenieDevice();
|
||||
theDevice.setDeviceDetail(aModule);
|
||||
theDevice.setGatewayName(theKey);
|
||||
theDeviceList.add(theDevice);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
homegenieMap = null;
|
||||
validHomeGenie = bridgeSettings.getBridgeSettingsDescriptor().isValidHomeGenie();
|
||||
log.info("HomeGenie Home created." + (validHomeGenie ? "" : " No HomeGenies configured."));
|
||||
if (validHomeGenie) {
|
||||
homegenieMap = new HashMap<String, HomeGenieInstance>();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHomegenieaddress().getDevices()
|
||||
.iterator();
|
||||
while (theList.hasNext() && validHomeGenie) {
|
||||
NamedIP aHomeGenie = theList.next();
|
||||
try {
|
||||
homegenieMap.put(aHomeGenie.getName(), new HomeGenieInstance(aHomeGenie, httpClient));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get HomeGenie (" + aHomeGenie.getName() + ") setup, Exiting with message: "
|
||||
+ e.getMessage(), e);
|
||||
validHomeGenie = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if (!closed && validHomeGenie) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
if (httpClient != null)
|
||||
httpClient.closeHandler();
|
||||
|
||||
homegenieMap = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class HomeGenieInstance {
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeGenieInstance.class);
|
||||
private NamedIP homegenieIP;
|
||||
|
||||
public HomeGenieInstance(NamedIP theNamedIp, HTTPHandler httpClient) {
|
||||
homegenieIP = theNamedIp;
|
||||
}
|
||||
|
||||
public Boolean callCommand(String deviceId, String moduleType, HomeGenieCommandDetail commandData,
|
||||
HTTPHandler httpClient) {
|
||||
log.debug("calling HomeGenie: {}:{}{}{}", homegenieIP.getIp(), homegenieIP.getPort(), moduleType,
|
||||
commandData.getCommand());
|
||||
String aUrl = null;
|
||||
|
||||
aUrl = homegenieIP.getHttpPreamble() + "/api/" + moduleType + "/" + deviceId + "/" + commandData.getCommand();
|
||||
|
||||
String theLevel = commandData.getLevel();
|
||||
if (commandData.getCommand().contains("Level")) {
|
||||
if (theLevel != null && theLevel.length() > 0)
|
||||
aUrl = aUrl + "/" + theLevel;
|
||||
else
|
||||
aUrl = aUrl + "100";
|
||||
}
|
||||
|
||||
String theData = httpClient.doHttpRequest(aUrl, HttpPut.METHOD_NAME, "application/json", null, httpClient.addBasicAuthHeader(null, homegenieIP));
|
||||
log.debug("call Command return is: <<<{}>>>", theData);
|
||||
if (theData.toLowerCase().contains("error"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Module> getDevices(HTTPHandler httpClient) {
|
||||
log.debug("calling HomeGenie: " + homegenieIP.getIp() + ":" + homegenieIP.getPort());
|
||||
List<Module> deviceList = null;
|
||||
Module[] hgModules;
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
|
||||
theUrl = homegenieIP.getHttpPreamble() + "/api/HomeAutomation.HomeGenie/Config/Modules.List";
|
||||
|
||||
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, httpClient.addBasicAuthHeader(null, homegenieIP));
|
||||
if (theData != null) {
|
||||
log.debug("GET HomeGenie Devices - data: " + theData);
|
||||
try {
|
||||
hgModules = new Gson().fromJson(theData, Module[].class);
|
||||
if (hgModules != null && hgModules.length > 0) {
|
||||
deviceList = new ArrayList<Module>();
|
||||
for (int i = 0; i < hgModules.length; i++) {
|
||||
if (hgModules[i].isModuleValid(homegenieIP.getExtensions()))
|
||||
deviceList.add(hgModules[i]);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot get devices for Homegenie {} Gson Parse Error.", homegenieIP.getName(), e);
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public NamedIP getHomegenieIP() {
|
||||
return homegenieIP;
|
||||
}
|
||||
|
||||
public void setHomegenieIP(NamedIP homegenieIP) {
|
||||
this.homegenieIP = homegenieIP;
|
||||
}
|
||||
|
||||
protected void closeClient() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class Module {
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeGenieInstance.class);
|
||||
|
||||
@SerializedName("Name")
|
||||
@Expose
|
||||
private String name;
|
||||
@SerializedName("Description")
|
||||
@Expose
|
||||
private String description;
|
||||
@SerializedName("DeviceType")
|
||||
@Expose
|
||||
private String deviceType;
|
||||
@SerializedName("Domain")
|
||||
@Expose
|
||||
private String domain;
|
||||
@SerializedName("Address")
|
||||
@Expose
|
||||
private String address;
|
||||
/*
|
||||
* @SerializedName("Properties")
|
||||
*
|
||||
* @Expose private List<Property> properties = null;
|
||||
*/
|
||||
@SerializedName("RoutingNode")
|
||||
@Expose
|
||||
private String routingNode;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/*
|
||||
* public List<Property> getProperties() { return properties; }
|
||||
*
|
||||
* public void setProperties(List<Property> properties) { this.properties =
|
||||
* properties; }
|
||||
*/
|
||||
public String getRoutingNode() {
|
||||
return routingNode;
|
||||
}
|
||||
|
||||
public void setRoutingNode(String routingNode) {
|
||||
this.routingNode = routingNode;
|
||||
}
|
||||
|
||||
public boolean isSwitch() {
|
||||
return isDeviceType("Switch");
|
||||
}
|
||||
|
||||
public boolean isDimmer() {
|
||||
return isDeviceType("Dimmer");
|
||||
}
|
||||
|
||||
public boolean isLight() {
|
||||
return isDeviceType("Light");
|
||||
}
|
||||
|
||||
private boolean isDeviceType(String theType) {
|
||||
if (deviceType.equals(theType)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isModuleValid(JsonObject theExtensions) {
|
||||
ModuleTypes moduleTypes = null;
|
||||
if (this.name == null || this.name.trim().isEmpty())
|
||||
return false;
|
||||
|
||||
if (isSwitch())
|
||||
return true;
|
||||
|
||||
if (isDimmer())
|
||||
return true;
|
||||
|
||||
if (isLight())
|
||||
return true;
|
||||
|
||||
if (theExtensions != null && theExtensions.isJsonObject() && theExtensions.get("moduleTypes").isJsonArray()) {
|
||||
try {
|
||||
moduleTypes = new Gson().fromJson(theExtensions, ModuleTypes.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not parse extensions for {} with {}", this.name, theExtensions);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moduleTypes == null)
|
||||
return false;
|
||||
|
||||
for (ModuleType moduleType : moduleTypes.getModuleTypes()) {
|
||||
if (isDeviceType(moduleType.getModuleType()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class ModuleType {
|
||||
|
||||
@SerializedName("moduleType")
|
||||
@Expose
|
||||
private String moduleType;
|
||||
|
||||
public String getModuleType() {
|
||||
return moduleType;
|
||||
}
|
||||
|
||||
public void setModuleType(String moduleType) {
|
||||
this.moduleType = moduleType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class ModuleTypes {
|
||||
|
||||
@SerializedName("moduleTypes")
|
||||
@Expose
|
||||
private List<ModuleType> moduleTypes = null;
|
||||
|
||||
public List<ModuleType> getModuleTypes() {
|
||||
return moduleTypes;
|
||||
}
|
||||
|
||||
public void setModuleTypes(List<ModuleType> moduleTypes) {
|
||||
this.moduleTypes = moduleTypes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.homegenie;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Property {
|
||||
|
||||
@SerializedName("Name")
|
||||
@Expose
|
||||
private String name;
|
||||
@SerializedName("Value")
|
||||
@Expose
|
||||
private String value;
|
||||
@SerializedName("Description")
|
||||
@Expose
|
||||
private String description;
|
||||
@SerializedName("FieldType")
|
||||
@Expose
|
||||
private String fieldType;
|
||||
@SerializedName("UpdateTime")
|
||||
@Expose
|
||||
private String updateTime;
|
||||
@SerializedName("NeedsUpdate")
|
||||
@Expose
|
||||
private Boolean needsUpdate;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getFieldType() {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
public void setFieldType(String fieldType) {
|
||||
this.fieldType = fieldType;
|
||||
}
|
||||
|
||||
public String getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(String updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public Boolean getNeedsUpdate() {
|
||||
return needsUpdate;
|
||||
}
|
||||
|
||||
public void setNeedsUpdate(Boolean needsUpdate) {
|
||||
this.needsUpdate = needsUpdate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.bwssystems.HABridge.plugins.homewizard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
|
||||
/**
|
||||
* Control HomeWizard devices over HomeWizard Cloud
|
||||
*
|
||||
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||
*
|
||||
*/
|
||||
public class HomeWizardHome implements Home {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeWizardHome.class);
|
||||
|
||||
private Map<String, HomeWizzardSmartPlugInfo> plugGateways;
|
||||
private Boolean validHomeWizard;
|
||||
private boolean closed;
|
||||
|
||||
public HomeWizardHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
String responseString = null;
|
||||
if (!validHomeWizard) {
|
||||
|
||||
log.warn("Should not get here, no HomeWizard smart plug available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
|
||||
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
|
||||
String jsonToPost = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
log.debug("Executing HUE api request to change activity to HomeWizard smart plug: {}", jsonToPost);
|
||||
|
||||
HomeWizzardSmartPlugInfo homeWizzardHandler = getHomeWizzardHandler(device.getTargetDevice());
|
||||
if(homeWizzardHandler == null) {
|
||||
log.warn("Should not get here, no HomeWizard smart plug configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
try {
|
||||
homeWizzardHandler.execApply(jsonToPost);
|
||||
} catch (Exception e) {
|
||||
|
||||
log.warn("Error posting request to HomeWizard smart plug");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error posting request to HomeWizard smart plug\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return responseString;
|
||||
}
|
||||
|
||||
public HomeWizzardSmartPlugInfo getHomeWizzardHandler(String plugName) {
|
||||
return plugGateways.get(plugName);
|
||||
}
|
||||
|
||||
public List<HomeWizardSmartPlugDevice> getDevices() {
|
||||
|
||||
log.debug("consolidating devices for HomeWizard plug gateways");
|
||||
Iterator<String> keys = plugGateways.keySet().iterator();
|
||||
ArrayList<HomeWizardSmartPlugDevice> deviceList = new ArrayList<>();
|
||||
|
||||
while(keys.hasNext())
|
||||
{
|
||||
String key = keys.next();
|
||||
for(HomeWizardSmartPlugDevice device : plugGateways.get(key).getDevices())
|
||||
deviceList.add(device);
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
|
||||
if (validHomeWizard)
|
||||
{
|
||||
if (type.equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex]))
|
||||
{
|
||||
return getDevices();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
|
||||
validHomeWizard = bridgeSettings.getBridgeSettingsDescriptor().isValidHomeWizard();
|
||||
log.info("HomeWizard Home created. " + (validHomeWizard ? "" : "No HomeWizard gateways configured."));
|
||||
|
||||
if (validHomeWizard)
|
||||
{
|
||||
plugGateways = new HashMap<>();
|
||||
Iterator<NamedIP> gatewaysList = bridgeSettings.getBridgeSettingsDescriptor().getHomeWizardAddress().getDevices().iterator();
|
||||
|
||||
while(gatewaysList.hasNext()) {
|
||||
|
||||
NamedIP gateway = gatewaysList.next();
|
||||
plugGateways.put(gateway.getName(), new HomeWizzardSmartPlugInfo(gateway, gateway.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
plugGateways = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.bwssystems.HABridge.plugins.homewizard;
|
||||
|
||||
/**
|
||||
* Control HomeWizard devices over HomeWizard Cloud
|
||||
*
|
||||
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||
*
|
||||
*/
|
||||
public class HomeWizardSmartPlugDevice {
|
||||
|
||||
private String name;
|
||||
private String gateway;
|
||||
private String id;
|
||||
private String typeName;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
public void setGateway(String gateway) {
|
||||
this.gateway = gateway;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.bwssystems.HABridge.plugins.homewizard;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.plugins.homewizard.json.Device;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* Control HomeWizard devices over HomeWizard Cloud
|
||||
*
|
||||
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||
*
|
||||
*/
|
||||
public class HomeWizzardSmartPlugInfo {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeWizardHome.class);
|
||||
|
||||
private static final String HOMEWIZARD_LOGIN_URL = "https://cloud.homewizard.com/account/login";
|
||||
private static final String HOMEWIZARD_API_URL = "https://plug.homewizard.com/plugs";
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
private final String cloudAuth;
|
||||
private final Gson gson;
|
||||
|
||||
private String cloudSessionId;
|
||||
private String cloudPlugName;
|
||||
private String cloudPlugId;
|
||||
|
||||
public HomeWizzardSmartPlugInfo(NamedIP gateway, String name) {
|
||||
|
||||
super();
|
||||
|
||||
cloudAuth = "Basic " + gateway.getUserPass64();
|
||||
cloudPlugName = name;
|
||||
gson = new Gson();
|
||||
}
|
||||
|
||||
public boolean login()
|
||||
{
|
||||
try
|
||||
{
|
||||
URL url = new URL(HOMEWIZARD_LOGIN_URL);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("Authorization", cloudAuth);
|
||||
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||
connection.connect();
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while((line = br.readLine()) != null)
|
||||
{
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
br.close();
|
||||
|
||||
// Get session id from result JSON
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject json = parser.parse(buffer.toString()).getAsJsonObject();
|
||||
|
||||
cloudSessionId = json.get("session").getAsString();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn("Error while login to cloud service ", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private String requestJson(String request)
|
||||
{
|
||||
String result = null;
|
||||
|
||||
// Check login was successful
|
||||
if (login()) {
|
||||
|
||||
// Request JSON from Cloud service
|
||||
try
|
||||
{
|
||||
URL url = new URL(HOMEWIZARD_API_URL + request);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("X-Session-Token", cloudSessionId);
|
||||
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||
connection.connect();
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while((line = br.readLine()) != null)
|
||||
{
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
br.close();
|
||||
|
||||
result = buffer.toString();
|
||||
result = StringUtils.strip(result, "[]");
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
log.warn("Error while get json request: {} ", request, e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean sendAction(String request, String action)
|
||||
{
|
||||
boolean result = true;
|
||||
|
||||
// Check login was successful
|
||||
if (login()) {
|
||||
|
||||
// Post action into Cloud service
|
||||
try
|
||||
{
|
||||
URL url = new URL(HOMEWIZARD_API_URL + request);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
JsonObject actionJson = new JsonObject();
|
||||
actionJson.addProperty("action", StringUtils.capitalize(action));
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("X-Session-Token", cloudSessionId);
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
|
||||
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(actionJson.toString().getBytes("UTF-8"));
|
||||
os.close();
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while((line = br.readLine()) != null)
|
||||
{
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
br.close();
|
||||
connection.disconnect();
|
||||
|
||||
// Check if request was Ok
|
||||
if (!buffer.toString().contains("Success"))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
log.warn("Error while post json action: {} ", request, e);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<HomeWizardSmartPlugDevice> getDevices()
|
||||
{
|
||||
List<HomeWizardSmartPlugDevice> homewizardDevices = new ArrayList<>();
|
||||
try {
|
||||
|
||||
String result = requestJson(EMPTY_STRING);
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject resultJson = parser.parse(result).getAsJsonObject();
|
||||
cloudPlugId = resultJson.get("id").getAsString();
|
||||
|
||||
String all_devices_json = resultJson.get("devices").toString();
|
||||
Device[] devices = gson.fromJson(all_devices_json, Device[].class);
|
||||
|
||||
// Fix names from JSON
|
||||
for (Device device : devices) {
|
||||
device.setTypeName(StringUtils.capitalize(device.getTypeName().replace("_", " ")));
|
||||
homewizardDevices.add(mapDeviceToHomeWizardSmartPlugDevice(device));
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
log.warn("Error while get devices from cloud service ", e);
|
||||
}
|
||||
|
||||
log.info("Found: " + homewizardDevices.size() + " devices");
|
||||
return homewizardDevices;
|
||||
}
|
||||
|
||||
public void execApply(String jsonToPost) throws Exception {
|
||||
|
||||
// Extract
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject resultJson = parser.parse(jsonToPost).getAsJsonObject();
|
||||
String deviceId = resultJson.get("deviceid").getAsString();
|
||||
String action = resultJson.get("action").getAsString();
|
||||
|
||||
// Check if we have an plug id stored
|
||||
if (StringUtils.isBlank(cloudPlugId)) {
|
||||
getDevices();
|
||||
}
|
||||
|
||||
// Send request to HomeWizard cloud
|
||||
if (!sendAction("/" + cloudPlugId + "/devices/" + deviceId + "/action", action))
|
||||
{
|
||||
throw new IOException("Send action to HomeWizard Cloud failed.");
|
||||
}
|
||||
}
|
||||
|
||||
protected HomeWizardSmartPlugDevice mapDeviceToHomeWizardSmartPlugDevice(Device device) {
|
||||
HomeWizardSmartPlugDevice homewizardDevice = new HomeWizardSmartPlugDevice();
|
||||
homewizardDevice.setId(device.getId());
|
||||
homewizardDevice.setGateway(cloudPlugName);
|
||||
homewizardDevice.setName(device.getName());
|
||||
homewizardDevice.setTypeName(device.getTypeName());
|
||||
|
||||
return homewizardDevice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.bwssystems.HABridge.plugins.homewizard.json;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Control HomeWizard devices over HomeWizard Cloud
|
||||
*
|
||||
* @author Björn Rennfanz (bjoern@fam-rennfanz.de)
|
||||
*
|
||||
*/
|
||||
public class Device {
|
||||
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
private String id;
|
||||
|
||||
@SerializedName("name")
|
||||
@Expose
|
||||
private String name;
|
||||
|
||||
@SerializedName("typeName")
|
||||
@Expose
|
||||
private String typeName;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
}
|
||||
@@ -5,55 +5,72 @@ import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.config.CookieSpecs;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.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 CloseableHttpClient httpClient;
|
||||
private RequestConfig globalConfig;
|
||||
|
||||
|
||||
private String callType;
|
||||
|
||||
public HTTPHandler() {
|
||||
globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
||||
httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
|
||||
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) {
|
||||
log.warn("Error creating URI http request: " + url + " with message: " + e1.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (httpVerb == null || httpVerb.trim().isEmpty() || HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb)) {
|
||||
request = new HttpGet(theURI);
|
||||
@@ -67,93 +84,124 @@ public class HTTPHandler {
|
||||
if (requestBody != null)
|
||||
putRequest.setEntity(requestBody);
|
||||
request = putRequest;
|
||||
}
|
||||
else
|
||||
} else
|
||||
request = new HttpGet(theURI);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Error creating outbound http request: IllegalArgumentException in log", e);
|
||||
return null;
|
||||
}
|
||||
log.debug("Making outbound call in doHttpRequest: " + request);
|
||||
log.debug("Making outbound call in doHttpRequest: <<<" + request.toString() + ">>>");
|
||||
if (headers != null && headers.length > 0) {
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
request.setHeader(headers[i].getName(), headers[i].getValue());
|
||||
}
|
||||
}
|
||||
HttpResponse response;
|
||||
try {
|
||||
for(int retryCount = 0; retryCount < 2; retryCount++) {
|
||||
response = httpClient.execute(request);
|
||||
CloseableHttpResponse response = null;
|
||||
for (int retryCount = 0; retryCount < 2; retryCount++) {
|
||||
try {
|
||||
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.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
|
||||
if (response.getEntity() != null) {
|
||||
try {
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
||||
// content
|
||||
// for
|
||||
// data
|
||||
EntityUtils.consume(response.getEntity()); // close out
|
||||
// inputstream
|
||||
// ignore
|
||||
// content
|
||||
} catch (Exception e) {
|
||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||
}
|
||||
retryCount = 2;
|
||||
} else {
|
||||
log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
|
||||
if (response != null && response.getEntity() != null) {
|
||||
try {
|
||||
String someContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
||||
// content
|
||||
// for
|
||||
// data
|
||||
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
|
||||
// content
|
||||
// for
|
||||
// data
|
||||
|
||||
EntityUtils.consume(response.getEntity()); // close out
|
||||
// inputstream
|
||||
// ignore
|
||||
// content
|
||||
log.debug("Unsuccessfull response - The http response is <<<" + someContent + ">>>");
|
||||
// inputstream
|
||||
// ignore
|
||||
// content
|
||||
} catch (Exception e) {
|
||||
//noop
|
||||
log.debug(
|
||||
"Error ocurred in handling response entity after successful call, still responding success. "
|
||||
+ e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
if (response != null && response.getStatusLine().getStatusCode() >= 200
|
||||
&& response.getStatusLine().getStatusCode() < 300) {
|
||||
if (theContent == null)
|
||||
theContent = "";
|
||||
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||
retryCount = 2;
|
||||
} else if (DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex].equals(callType)
|
||||
&& response.getStatusLine().getStatusCode() == 302) {
|
||||
if (theContent == null)
|
||||
theContent = "";
|
||||
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
|
||||
retryCount = 2;
|
||||
} else if (response != null) {
|
||||
log.warn(
|
||||
"HTTP response code was not an expected successful response of between 200 - 299, the code was: "
|
||||
+ response.getStatusLine() + " with the content of <<<" + theContent + ">>>");
|
||||
if (response.getStatusLine().getStatusCode() == 504) {
|
||||
log.warn("HTTP response code was 504, retrying...");
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e1) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
else
|
||||
log.debug("The 504 error content is <<<" + theContent + ">>>");
|
||||
theContent = null;
|
||||
} else
|
||||
retryCount = 2;
|
||||
}
|
||||
|
||||
} catch (ClientProtocolException e) {
|
||||
log.warn("Client Protocol Exception received, retyring....");
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage(), e);
|
||||
retryCount = 2;
|
||||
}
|
||||
|
||||
if (retryCount < 2) {
|
||||
theContent = null;
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e1) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||
}
|
||||
return theContent;
|
||||
}
|
||||
|
||||
// public HttpClient getHttpClient() {
|
||||
// return httpClient;
|
||||
// }
|
||||
|
||||
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 CloseableHttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public void setCallType(String callType) {
|
||||
this.callType = callType;
|
||||
}
|
||||
|
||||
public void closeHandler() {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException e) {
|
||||
// noop
|
||||
}
|
||||
httpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,26 +11,40 @@ 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.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 HTTPHandler anHttpHandler;
|
||||
private static HTTPHandler anHttpHandler = null;
|
||||
private Boolean isDevMode;
|
||||
private boolean closed;
|
||||
|
||||
public HTTPHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
public static HTTPHandler getHandler() {
|
||||
if(anHttpHandler == null)
|
||||
anHttpHandler = new HTTPHandler();
|
||||
return anHttpHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String responseString = null;
|
||||
|
||||
String 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())
|
||||
@@ -50,6 +64,9 @@ public class HTTPHome implements Home {
|
||||
|
||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
|
||||
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);
|
||||
|
||||
@@ -57,22 +74,28 @@ public class HTTPHome implements Home {
|
||||
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);
|
||||
}
|
||||
// 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;
|
||||
@@ -80,8 +103,21 @@ public class HTTPHome implements Home {
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
anHttpHandler = new HTTPHandler();
|
||||
log.info("Http Home created.");
|
||||
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();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -93,9 +129,19 @@ public class HTTPHome implements Home {
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
if(anHttpHandler != null)
|
||||
anHttpHandler.closeHandler();
|
||||
anHttpHandler = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.bwssystems.HABridge.plugins.http;
|
||||
|
||||
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;
|
||||
|
||||
public final class HttpClientPool {
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpClientPool.class);
|
||||
|
||||
// Single-element enum to implement Singleton.
|
||||
private static enum Singleton {
|
||||
// Just one of me so constructor will be called once.
|
||||
Client;
|
||||
// The thread-safe client.
|
||||
private final CloseableHttpClient threadSafeClient;
|
||||
// The pool monitor.
|
||||
private final IdleConnectionMonitorThread monitor;
|
||||
|
||||
// The constructor creates it - thus late
|
||||
private Singleton() {
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
// 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().setConnectionManager(cm).build();
|
||||
// Start up an eviction thread.
|
||||
monitor = new IdleConnectionMonitorThread(cm);
|
||||
// Don't stop quitting.
|
||||
monitor.setDaemon(true);
|
||||
monitor.start();
|
||||
}
|
||||
|
||||
public CloseableHttpClient get() {
|
||||
return threadSafeClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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.
|
||||
private final PoolingHttpClientConnectionManager cm;
|
||||
// Use a BlockingQueue to stop everything.
|
||||
private final BlockingQueue<Stop> stopSignal = new ArrayBlockingQueue<Stop>(1);
|
||||
|
||||
// Pushed up the queue.
|
||||
private static class Stop {
|
||||
// The return queue.
|
||||
private final BlockingQueue<Stop> stop = new ArrayBlockingQueue<Stop>(1);
|
||||
|
||||
// Called by the process that is being told to stop.
|
||||
public void stopped() {
|
||||
// Push me back up the queue to indicate we are now stopped.
|
||||
stop.add(this);
|
||||
}
|
||||
|
||||
// Called by the process requesting the stop.
|
||||
public void waitForStopped() throws InterruptedException {
|
||||
// Wait until the callee acknowledges that it has stopped.
|
||||
stop.take();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IdleConnectionMonitorThread(PoolingHttpClientConnectionManager cm) {
|
||||
super();
|
||||
this.cm = cm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Holds the stop request that stopped the process.
|
||||
Stop stopRequest;
|
||||
// Every 5 seconds.
|
||||
while ((stopRequest = stopSignal.poll(5, TimeUnit.SECONDS)) == null) {
|
||||
// Close expired connections
|
||||
cm.closeExpiredConnections();
|
||||
// Optionally, close connections that have been idle too long.
|
||||
cm.closeIdleConnections(60, TimeUnit.SECONDS);
|
||||
// Look at pool stats.
|
||||
log.debug("Stats: {}", cm.getTotalStats());
|
||||
}
|
||||
// Acknowledge the stop request.
|
||||
stopRequest.stopped();
|
||||
} catch (InterruptedException ex) {
|
||||
// terminate
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() throws InterruptedException, IOException {
|
||||
log.info("Shutting down client pool");
|
||||
// Signal the stop to the thread.
|
||||
Stop stop = new Stop();
|
||||
stopSignal.add(stop);
|
||||
// Wait for the stop to complete.
|
||||
stop.waitForStopped();
|
||||
// Close the pool - Added
|
||||
Singleton.Client.threadSafeClient.close();
|
||||
// Close the connection manager.
|
||||
cm.close();
|
||||
log.info("Client pool shut down");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void shutdown() throws InterruptedException, IOException {
|
||||
// Shutdown the monitor.
|
||||
Singleton.Client.monitor.shutdown();
|
||||
SingletonSSL.SSLClient.monitor.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user