mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
104 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
dc28eb2984 | ||
|
|
b8acb4a52c | ||
|
|
21fdaf4545 | ||
|
|
db192df2c6 | ||
|
|
4a24d263c1 | ||
|
|
3394559539 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -12,6 +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>
|
||||
262
pom.xml
262
pom.xml
@@ -1,105 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>5.2.1</version>
|
||||
<version>5.3.1RC3</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>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>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>harmony-java-client</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>nest-controller</artifactId>
|
||||
<version>1.0.14</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>nest-controller</artifactId>
|
||||
<version>1.0.14</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>4.4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.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.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>
|
||||
<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>
|
||||
@@ -107,59 +104,105 @@
|
||||
<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.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</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>com.github.mob41</groupId>
|
||||
<artifactId>broadlink-java-api</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.5</version>
|
||||
<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>
|
||||
@@ -221,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>
|
||||
@@ -232,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) {
|
||||
@@ -306,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) {
|
||||
@@ -324,7 +401,7 @@ public class BridgeSecurity {
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -336,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");
|
||||
@@ -355,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,10 +59,10 @@ public class BridgeSettings extends BackupHandler {
|
||||
public BridgeSecurity getBridgeSecurity() {
|
||||
return bridgeSecurity;
|
||||
}
|
||||
public static String getCurrentDate() {
|
||||
return dateFormat.format(new Date());
|
||||
}
|
||||
|
||||
public String getCurrentDate() {
|
||||
return LocalDateTime.now().format(dateTimeFormat);
|
||||
}
|
||||
|
||||
public void buildSettings() {
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
@@ -76,7 +77,6 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
String serverPortOverride = System.getProperty("server.port");
|
||||
String serverIpOverride = System.getProperty("server.ip");
|
||||
String upnpStrictOverride = System.getProperty("upnp.strict", "true");
|
||||
if(configFileProperty != null)
|
||||
{
|
||||
log.info("reading from config file: " + configFileProperty);
|
||||
@@ -159,15 +159,16 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
theBridgeSettings.setSomfyAddress(theSomfyList);
|
||||
|
||||
theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||
// theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
|
||||
theBridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(System.getProperty("button.sleep", Configuration.DEFAULT_BUTTON_SLEEP)));
|
||||
theBridgeSettings.setNestuser(System.getProperty("nest.user"));
|
||||
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
|
||||
}
|
||||
|
||||
ParseRoute aDefaultRoute = ParseRoute.getInstance();
|
||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().trim().equals("") || theBridgeSettings.getUpnpConfigAddress().trim().equals("0.0.0.0")) {
|
||||
addressString = checkIpAddress(null, true);
|
||||
addressString = aDefaultRoute.getLocalIPAddress();
|
||||
if(addressString != null) {
|
||||
theBridgeSettings.setUpnpConfigAddress(addressString);
|
||||
log.info("Adding " + addressString + " as our default upnp config address.");
|
||||
@@ -177,8 +178,10 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
else {
|
||||
addressString = checkIpAddress(theBridgeSettings.getUpnpConfigAddress(), false);
|
||||
if(addressString == null)
|
||||
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host.");
|
||||
if(addressString == null) {
|
||||
addressString = aDefaultRoute.getLocalIPAddress();
|
||||
log.warn("The upnp config address, " + theBridgeSettings.getUpnpConfigAddress() + ", does not match any known IP's on this host. Using default address: " + addressString);
|
||||
}
|
||||
}
|
||||
|
||||
if(theBridgeSettings.getUpnpResponsePort() == null)
|
||||
@@ -194,7 +197,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setUpnpGroupDb(Configuration.GROUP_DB_DIRECTORY);
|
||||
|
||||
if(theBridgeSettings.getNumberoflogmessages() == null || theBridgeSettings.getNumberoflogmessages() <= 0)
|
||||
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||
theBridgeSettings.setNumberoflogmessages(Integer.valueOf(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||
|
||||
if(theBridgeSettings.getButtonsleep() == null || theBridgeSettings.getButtonsleep() < 0)
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||
@@ -212,13 +215,16 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setHomeWizardConfigured(theBridgeSettings.isValidHomeWizard());
|
||||
theBridgeSettings.setOpenhabconfigured(theBridgeSettings.isValidOpenhab());
|
||||
theBridgeSettings.setFhemconfigured(theBridgeSettings.isValidFhem());
|
||||
theBridgeSettings.setMoziotconfigured(theBridgeSettings.isValidMozIot());
|
||||
theBridgeSettings.setHomegenieconfigured(theBridgeSettings.isValidHomeGenie());
|
||||
// Lifx is either configured or not, so it does not need an update.
|
||||
if(serverPortOverride != null)
|
||||
theBridgeSettings.setServerPort(serverPortOverride);
|
||||
if(serverIpOverride != null)
|
||||
if(serverIpOverride != null) {
|
||||
theBridgeSettings.setWebaddress(serverIpOverride);
|
||||
if(upnpStrictOverride != null)
|
||||
theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(upnpStrictOverride));
|
||||
theBridgeSettings.setUpnpConfigAddress(serverIpOverride);
|
||||
}
|
||||
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
|
||||
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());
|
||||
@@ -244,10 +250,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ public class BridgeSettingsDescriptor {
|
||||
@SerializedName("openhabaddress")
|
||||
@Expose
|
||||
private IpList openhabaddress;
|
||||
@SerializedName("moziotaddress")
|
||||
@Expose
|
||||
private IpList moziotaddress;
|
||||
@SerializedName("hubversion")
|
||||
@Expose
|
||||
private String hubversion;
|
||||
@@ -108,16 +111,34 @@ public class BridgeSettingsDescriptor {
|
||||
@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("activeloggers")
|
||||
// @Expose
|
||||
// private List<NameValue> activeloggers;
|
||||
|
||||
@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("activeloggers")
|
||||
// @Expose
|
||||
// private List<NameValue> activeloggers;
|
||||
|
||||
private boolean settingsChanged;
|
||||
private boolean veraconfigured;
|
||||
private boolean fibaroconfigured;
|
||||
@@ -132,14 +153,16 @@ public class BridgeSettingsDescriptor {
|
||||
private boolean homewizardconfigured;
|
||||
private boolean openhabconfigured;
|
||||
private boolean fhemconfigured;
|
||||
|
||||
private boolean moziotconfigured;
|
||||
private boolean homegenieconfigured;
|
||||
|
||||
// Deprecated settings
|
||||
private String haltoken;
|
||||
private boolean upnpstrict;
|
||||
|
||||
// private boolean upnpstrict;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
this.upnpstrict = true;
|
||||
// this.upnpstrict = true;
|
||||
this.useupnpiface = false;
|
||||
this.userooms = false;
|
||||
this.traceupnp = false;
|
||||
@@ -156,6 +179,8 @@ public class BridgeSettingsDescriptor {
|
||||
this.homewizardconfigured = false;
|
||||
this.lifxconfigured = false;
|
||||
this.openhabconfigured = false;
|
||||
this.moziotconfigured = false;
|
||||
this.homegenieconfigured = false;
|
||||
this.farenheit = true;
|
||||
this.securityData = null;
|
||||
this.settingsChanged = false;
|
||||
@@ -163,456 +188,676 @@ public class BridgeSettingsDescriptor {
|
||||
this.webaddress = "0.0.0.0";
|
||||
this.hubversion = HueConstants.HUB_VERSION;
|
||||
this.hubmac = null;
|
||||
// this.activeloggers = 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;
|
||||
}
|
||||
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
}
|
||||
|
||||
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
||||
this.upnpconfigaddress = upnpConfigAddress;
|
||||
}
|
||||
|
||||
public boolean isUseupnpiface() {
|
||||
return useupnpiface;
|
||||
}
|
||||
|
||||
public void setUseupnpiface(boolean useupnpiface) {
|
||||
this.useupnpiface = useupnpiface;
|
||||
}
|
||||
|
||||
public boolean isUserooms() {
|
||||
return userooms;
|
||||
}
|
||||
|
||||
public void setUserooms(boolean userooms) {
|
||||
this.userooms = userooms;
|
||||
}
|
||||
public Integer getServerPort() {
|
||||
|
||||
public Integer getServerPort() {
|
||||
return serverport;
|
||||
}
|
||||
|
||||
public void setServerPort(Integer serverPort) {
|
||||
this.serverport = serverPort;
|
||||
}
|
||||
|
||||
public void setServerPort(String serverPort) {
|
||||
this.serverport = Integer.valueOf(serverPort);
|
||||
}
|
||||
|
||||
public Integer getUpnpResponsePort() {
|
||||
return upnpresponseport;
|
||||
}
|
||||
|
||||
public void setUpnpResponsePort(Integer upnpResponsePort) {
|
||||
this.upnpresponseport = upnpResponsePort;
|
||||
}
|
||||
|
||||
public void setUpnpResponsePort(String upnpResponsePort) {
|
||||
this.upnpresponseport = Integer.valueOf(upnpResponsePort);
|
||||
}
|
||||
|
||||
public String getUpnpDeviceDb() {
|
||||
return upnpdevicedb;
|
||||
}
|
||||
|
||||
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
||||
this.upnpdevicedb = upnpDeviceDb;
|
||||
}
|
||||
|
||||
public String getUpnpGroupDb() {
|
||||
return upnpgroupdb;
|
||||
}
|
||||
|
||||
public void setUpnpGroupDb(String upnpGroupDb) {
|
||||
this.upnpgroupdb = upnpGroupDb;
|
||||
}
|
||||
|
||||
public IpList getVeraAddress() {
|
||||
|
||||
return veraaddress;
|
||||
}
|
||||
|
||||
public IpList getFibaroAddress() {
|
||||
return fibaroaddress;
|
||||
}
|
||||
|
||||
public IpList getSomfyAddress() {
|
||||
return somfyaddress;
|
||||
}
|
||||
|
||||
public IpList getHomeWizardAddress() {
|
||||
return homewizardaddress;
|
||||
}
|
||||
}
|
||||
|
||||
public void setVeraAddress(IpList veraAddress) {
|
||||
this.veraaddress = veraAddress;
|
||||
}
|
||||
|
||||
public void setFibaroAddress(IpList fibaroAddress) {
|
||||
this.fibaroaddress = fibaroAddress;
|
||||
}
|
||||
|
||||
public void setSomfyAddress(IpList somfyAddress) {
|
||||
this.somfyaddress = somfyAddress;
|
||||
}
|
||||
|
||||
public void setHomeWizardAddress(IpList homewizardaddress) {
|
||||
this.homewizardaddress = homewizardaddress;
|
||||
}
|
||||
|
||||
public IpList getHarmonyAddress() {
|
||||
return harmonyaddress;
|
||||
}
|
||||
|
||||
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||
this.harmonyaddress = harmonyaddress;
|
||||
}
|
||||
/*
|
||||
public boolean isUpnpStrict() {
|
||||
return upnpstrict;
|
||||
}
|
||||
|
||||
public void setUpnpStrict(boolean upnpStrict) {
|
||||
this.upnpstrict = upnpStrict;
|
||||
}
|
||||
*/
|
||||
public boolean isTraceupnp() {
|
||||
return traceupnp;
|
||||
}
|
||||
|
||||
public void setTraceupnp(boolean traceupnp) {
|
||||
this.traceupnp = traceupnp;
|
||||
}
|
||||
|
||||
public String getNestuser() {
|
||||
return nestuser;
|
||||
}
|
||||
|
||||
public void setNestuser(String nestuser) {
|
||||
this.nestuser = nestuser;
|
||||
}
|
||||
|
||||
public String getNestpwd() {
|
||||
return nestpwd;
|
||||
}
|
||||
|
||||
public void setNestpwd(String nestpwd) {
|
||||
this.nestpwd = nestpwd;
|
||||
}
|
||||
|
||||
public boolean isVeraconfigured() {
|
||||
return veraconfigured;
|
||||
}
|
||||
|
||||
public boolean isFibaroconfigured() {
|
||||
return fibaroconfigured;
|
||||
}
|
||||
|
||||
public boolean isSomfyconfigured() {
|
||||
return somfyconfigured;
|
||||
}
|
||||
|
||||
public boolean isHomeWizardConfigured() {
|
||||
return homewizardconfigured;
|
||||
}
|
||||
}
|
||||
|
||||
public void setVeraconfigured(boolean veraconfigured) {
|
||||
this.veraconfigured = veraconfigured;
|
||||
}
|
||||
|
||||
public void setFibaroconfigured(boolean fibaroconfigured) {
|
||||
this.fibaroconfigured = fibaroconfigured;
|
||||
}
|
||||
|
||||
public void setSomfyconfigured(boolean somfyconfigured) {
|
||||
this.somfyconfigured = somfyconfigured;
|
||||
}
|
||||
|
||||
public void setHomeWizardConfigured(boolean homewizardconfigured) {
|
||||
this.homewizardconfigured = homewizardconfigured;
|
||||
}
|
||||
|
||||
public boolean isHarmonyconfigured() {
|
||||
return harmonyconfigured;
|
||||
}
|
||||
|
||||
public void setHarmonyconfigured(boolean harmonyconfigured) {
|
||||
this.harmonyconfigured = harmonyconfigured;
|
||||
}
|
||||
|
||||
public boolean isNestConfigured() {
|
||||
return nestconfigured;
|
||||
}
|
||||
|
||||
public void setNestConfigured(boolean isNestConfigured) {
|
||||
this.nestconfigured = isNestConfigured;
|
||||
}
|
||||
|
||||
public Integer getButtonsleep() {
|
||||
return buttonsleep;
|
||||
}
|
||||
|
||||
public void setButtonsleep(Integer buttonsleep) {
|
||||
this.buttonsleep = buttonsleep;
|
||||
}
|
||||
|
||||
public String getConfigfile() {
|
||||
return configfile;
|
||||
}
|
||||
|
||||
public void setConfigfile(String configfile) {
|
||||
this.configfile = configfile;
|
||||
}
|
||||
|
||||
public Integer getNumberoflogmessages() {
|
||||
return numberoflogmessages;
|
||||
}
|
||||
|
||||
public void setNumberoflogmessages(Integer numberoflogmessages) {
|
||||
this.numberoflogmessages = numberoflogmessages;
|
||||
}
|
||||
|
||||
public boolean isFarenheit() {
|
||||
return farenheit;
|
||||
}
|
||||
|
||||
public void setFarenheit(boolean farenheit) {
|
||||
this.farenheit = farenheit;
|
||||
}
|
||||
|
||||
public IpList getHueaddress() {
|
||||
return hueaddress;
|
||||
}
|
||||
|
||||
public void setHueaddress(IpList hueaddress) {
|
||||
this.hueaddress = hueaddress;
|
||||
}
|
||||
|
||||
public boolean isHueconfigured() {
|
||||
return hueconfigured;
|
||||
}
|
||||
|
||||
public void setHueconfigured(boolean hueconfigured) {
|
||||
this.hueconfigured = hueconfigured;
|
||||
}
|
||||
|
||||
public IpList getHaladdress() {
|
||||
return haladdress;
|
||||
}
|
||||
|
||||
public void setHaladdress(IpList haladdress) {
|
||||
this.haladdress = haladdress;
|
||||
}
|
||||
|
||||
public String getHaltoken() {
|
||||
return haltoken;
|
||||
}
|
||||
|
||||
public void setHaltoken(String haltoken) {
|
||||
this.haltoken = haltoken;
|
||||
}
|
||||
|
||||
public boolean isHalconfigured() {
|
||||
return halconfigured;
|
||||
}
|
||||
|
||||
public void setHalconfigured(boolean halconfigured) {
|
||||
this.halconfigured = halconfigured;
|
||||
}
|
||||
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
|
||||
protected void removeWhitelist() {
|
||||
whitelist = null;
|
||||
}
|
||||
|
||||
public boolean isSettingsChanged() {
|
||||
return settingsChanged;
|
||||
}
|
||||
|
||||
public void setSettingsChanged(boolean settingsChanged) {
|
||||
this.settingsChanged = settingsChanged;
|
||||
}
|
||||
|
||||
public String getMyechourl() {
|
||||
return myechourl;
|
||||
}
|
||||
|
||||
public void setMyechourl(String myechourl) {
|
||||
this.myechourl = myechourl;
|
||||
}
|
||||
|
||||
public String getWebaddress() {
|
||||
return webaddress;
|
||||
}
|
||||
|
||||
public void setWebaddress(String webaddress) {
|
||||
this.webaddress = webaddress;
|
||||
}
|
||||
|
||||
public IpList getMqttaddress() {
|
||||
return mqttaddress;
|
||||
}
|
||||
|
||||
public void setMqttaddress(IpList mqttaddress) {
|
||||
this.mqttaddress = mqttaddress;
|
||||
}
|
||||
|
||||
public boolean isMqttconfigured() {
|
||||
return mqttconfigured;
|
||||
}
|
||||
|
||||
public void setMqttconfigured(boolean mqttconfigured) {
|
||||
this.mqttconfigured = mqttconfigured;
|
||||
}
|
||||
|
||||
public IpList getHassaddress() {
|
||||
return hassaddress;
|
||||
}
|
||||
|
||||
public void setHassaddress(IpList hassaddress) {
|
||||
this.hassaddress = hassaddress;
|
||||
}
|
||||
|
||||
public boolean isHassconfigured() {
|
||||
return hassconfigured;
|
||||
}
|
||||
|
||||
public void setHassconfigured(boolean hassconfigured) {
|
||||
this.hassconfigured = hassconfigured;
|
||||
}
|
||||
|
||||
public IpList getOpenhabaddress() {
|
||||
return openhabaddress;
|
||||
}
|
||||
|
||||
public void setOpenhabaddress(IpList openhabaddress) {
|
||||
this.openhabaddress = openhabaddress;
|
||||
}
|
||||
|
||||
public boolean isOpenhabconfigured() {
|
||||
return openhabconfigured;
|
||||
}
|
||||
|
||||
public void setOpenhabconfigured(boolean openhabconfigured) {
|
||||
this.openhabconfigured = openhabconfigured;
|
||||
}
|
||||
|
||||
public String getHubversion() {
|
||||
return hubversion;
|
||||
}
|
||||
|
||||
public void setHubversion(String hubversion) {
|
||||
this.hubversion = hubversion;
|
||||
}
|
||||
|
||||
public String getHubmac() {
|
||||
return hubmac;
|
||||
}
|
||||
|
||||
public void setHubmac(String hubmac) {
|
||||
this.hubmac = hubmac;
|
||||
}
|
||||
|
||||
public IpList getDomoticzaddress() {
|
||||
return domoticzaddress;
|
||||
}
|
||||
|
||||
public void setDomoticzaddress(IpList domoticzaddress) {
|
||||
this.domoticzaddress = domoticzaddress;
|
||||
}
|
||||
|
||||
public boolean isDomoticzconfigured() {
|
||||
return domoticzconfigured;
|
||||
}
|
||||
|
||||
public void setDomoticzconfigured(boolean domoticzconfigured) {
|
||||
this.domoticzconfigured = domoticzconfigured;
|
||||
}
|
||||
|
||||
public boolean isLifxconfigured() {
|
||||
return lifxconfigured;
|
||||
}
|
||||
|
||||
public void setLifxconfigured(boolean lifxconfigured) {
|
||||
this.lifxconfigured = lifxconfigured;
|
||||
}
|
||||
|
||||
public String getSecurityData() {
|
||||
return securityData;
|
||||
}
|
||||
|
||||
public void setSecurityData(String securityData) {
|
||||
this.securityData = securityData;
|
||||
}
|
||||
|
||||
public Integer getUpnpsenddelay() {
|
||||
return upnpsenddelay;
|
||||
}
|
||||
|
||||
public void setUpnpsenddelay(Integer upnpsenddelay) {
|
||||
this.upnpsenddelay = upnpsenddelay;
|
||||
}
|
||||
|
||||
public IpList getFhemaddress() {
|
||||
return fhemaddress;
|
||||
}
|
||||
|
||||
public void setFhemaddress(IpList fhemaddress) {
|
||||
this.fhemaddress = fhemaddress;
|
||||
}
|
||||
|
||||
public boolean isFhemconfigured() {
|
||||
return fhemconfigured;
|
||||
}
|
||||
|
||||
public void setFhemconfigured(boolean fhemconfigured) {
|
||||
this.fhemconfigured = fhemconfigured;
|
||||
}
|
||||
// public List<NameValue> getActiveloggers() {
|
||||
// return activeloggers;
|
||||
// }
|
||||
// public void setActiveloggers(List<NameValue> activeloggers) {
|
||||
// this.activeloggers = activeloggers;
|
||||
// }
|
||||
|
||||
// public List<NameValue> getActiveloggers() {
|
||||
// return activeloggers;
|
||||
// }
|
||||
// public void setActiveloggers(List<NameValue> activeloggers) {
|
||||
// this.activeloggers = activeloggers;
|
||||
// }
|
||||
public boolean isBroadlinkconfigured() {
|
||||
return broadlinkconfigured;
|
||||
}
|
||||
|
||||
public void setBroadlinkconfigured(boolean broadlinkconfigured) {
|
||||
this.broadlinkconfigured = broadlinkconfigured;
|
||||
}
|
||||
|
||||
public Boolean isValidVera() {
|
||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
if (this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getVeraAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidFibaro() {
|
||||
if(this.getFibaroAddress() == null || this.getFibaroAddress().getDevices().size() <= 0)
|
||||
if (this.getFibaroAddress() == null || this.getFibaroAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getFibaroAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidHarmony() {
|
||||
if(this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
if (this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getHarmonyAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidNest() {
|
||||
if(this.getNestpwd() == null || this.getNestpwd().equals(""))
|
||||
if (this.getNestpwd() == null || this.getNestpwd().equals(""))
|
||||
return false;
|
||||
if(this.getNestuser() == null || this.getNestuser().equals(""))
|
||||
if (this.getNestuser() == null || this.getNestuser().equals(""))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidHue() {
|
||||
if(this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
|
||||
if (this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getHueaddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidHal() {
|
||||
if(this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getHaladdress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
|
||||
return false;
|
||||
if(devicesList.get(0).getPassword() == null || devicesList.get(0).getPassword().trim().isEmpty()) {
|
||||
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||
List<NamedIP> devicesList = this.getHaladdress().getDevices();
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
if (devicesList.get(0).getPassword() == null || devicesList.get(0).getPassword().trim().isEmpty()) {
|
||||
if (this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidMQTT() {
|
||||
if(this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
if (this.getMqttaddress() == null || this.getMqttaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getMqttaddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidHass() {
|
||||
if(this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
if (this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getHassaddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidDomoticz() {
|
||||
if(this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
if (this.getDomoticzaddress() == null || this.getDomoticzaddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getDomoticzaddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidSomfy() {
|
||||
if(this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
|
||||
if (this.getSomfyAddress() == null || this.getSomfyAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getSomfyAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidLifx() {
|
||||
return this.isLifxconfigured();
|
||||
}
|
||||
|
||||
public void updateHue(NamedIP aHue) {
|
||||
int indexHue = -1;
|
||||
for( int i = 0; i < hueaddress.getDevices().size(); i++) {
|
||||
if(hueaddress.getDevices().get(i).getName().equals(aHue.getName()))
|
||||
for (int i = 0; i < hueaddress.getDevices().size(); i++) {
|
||||
if (hueaddress.getDevices().get(i).getName().equals(aHue.getName()))
|
||||
indexHue = i;
|
||||
}
|
||||
if(indexHue >= 0) {
|
||||
if (indexHue >= 0) {
|
||||
hueaddress.getDevices().set(indexHue, aHue);
|
||||
this.setSettingsChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean isValidHomeWizard() {
|
||||
if(this.getHomeWizardAddress() == null || this.getHomeWizardAddress().getDevices().size() <= 0)
|
||||
if (this.getHomeWizardAddress() == null || this.getHomeWizardAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
|
||||
|
||||
List<NamedIP> devicesList = this.getHomeWizardAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
if (devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isValidOpenhab() {
|
||||
if(this.getOpenhabaddress() == null || this.getOpenhabaddress().getDevices().size() <= 0)
|
||||
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))
|
||||
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)
|
||||
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))
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ public class DeviceMapTypes {
|
||||
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;
|
||||
@@ -69,6 +71,8 @@ public class DeviceMapTypes {
|
||||
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;
|
||||
|
||||
@@ -15,6 +15,7 @@ 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:
|
||||
@@ -39,12 +40,12 @@ public class HABridge {
|
||||
UDPDatagramSender udpSender;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
SystemControl theSystem;
|
||||
BridgeSettings bridgeSettings;
|
||||
Version theVersion;
|
||||
@SuppressWarnings("unused")
|
||||
HttpClientPool thePool;
|
||||
|
||||
ShutdownHook shutdownHook = null;
|
||||
|
||||
log.info("HA Bridge startup sequence...");
|
||||
theVersion = new Version();
|
||||
// Singleton initialization
|
||||
@@ -53,9 +54,13 @@ public class HABridge {
|
||||
bridgeSettings = new BridgeSettings();
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
bridgeSettings.buildSettings();
|
||||
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();
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") initializing....");
|
||||
// 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
|
||||
@@ -68,6 +73,14 @@ public class HABridge {
|
||||
// setup system control api first
|
||||
theSystem = new SystemControl(bridgeSettings, theVersion);
|
||||
theSystem.setupServer();
|
||||
|
||||
// Add shutdown hook to be able to properly stop server
|
||||
if (shutdownHook != null) {
|
||||
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||
}
|
||||
shutdownHook = new ShutdownHook(bridgeSettings, theSystem);
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
|
||||
// setup the UDP Datagram socket to be used by the HueMulator and the upnpListener
|
||||
udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort());
|
||||
if(udpSender == null) {
|
||||
@@ -85,10 +98,13 @@ public class HABridge {
|
||||
// wait for the sparkjava initialization of the rest api classes to be complete
|
||||
awaitInitialization();
|
||||
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp())
|
||||
log.info("Traceupnp: upnp config address: " + bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress() + "-useIface:" +
|
||||
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface() + " on web server: " +
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress() + ":" + bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp()) {
|
||||
log.info("Traceupnp: upnp config address: {} -useIface: {} on web server: {}:{}",
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress(),
|
||||
bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
}
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||
theSettingResponder.setupServer();
|
||||
@@ -96,13 +112,13 @@ public class HABridge {
|
||||
// start the upnp ssdp discovery listener
|
||||
theUpnpListener = null;
|
||||
try {
|
||||
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender);
|
||||
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" + theVersion.getVersion() + ") reinitialization requessted....");
|
||||
log.info("HA Bridge (v{}) reinitialization requessted....", theVersion.getVersion());
|
||||
else
|
||||
bridgeSettings.getBridgeControl().setStop(true);
|
||||
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
||||
@@ -117,7 +133,7 @@ public class HABridge {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Sleep error: " + e.getMessage());
|
||||
log.error("Sleep error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,18 +143,24 @@ public class HABridge {
|
||||
try {
|
||||
HttpClientPool.shutdown();
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Error shutting down http pool: " + e.getMessage());;
|
||||
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||
} catch (IOException e) {
|
||||
log.warn("Error shutting down http pool: " + e.getMessage());;
|
||||
log.warn("Error shutting down http pool: {}", e.getMessage());;
|
||||
}
|
||||
thePool = null;
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||
log.info("HA Bridge (v{}) exiting....", theVersion.getVersion());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static void theExceptionHandler(Exception e, Integer thePort) {
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
log.error("Could not start ha-bridge webservice on port [" + thePort + "] due to: " + e.getMessage());
|
||||
System.exit(0);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ 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;
|
||||
@@ -27,6 +28,7 @@ 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 {
|
||||
@@ -120,7 +122,7 @@ public class HomeManager {
|
||||
aHome = new OpenHABHome(bridgeSettings);
|
||||
resourceList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
homeList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
|
||||
//setup the OpenHAB configuration if available
|
||||
//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);
|
||||
@@ -128,6 +130,14 @@ public class HomeManager {
|
||||
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) {
|
||||
|
||||
@@ -2,6 +2,8 @@ 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;
|
||||
@@ -11,53 +13,101 @@ public class NamedIP {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -243,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);
|
||||
@@ -296,8 +314,7 @@ 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");
|
||||
@@ -419,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");
|
||||
@@ -546,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();
|
||||
@@ -558,4 +615,5 @@ public class SystemControl {
|
||||
pingListener();
|
||||
return "{\"control\":\"stopping\"}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public class DeviceResponse {
|
||||
private String swversion;
|
||||
private String swconfigid;
|
||||
private String productid;
|
||||
private String productname;
|
||||
|
||||
public DeviceState getState() {
|
||||
return state;
|
||||
@@ -90,6 +91,14 @@ public class DeviceResponse {
|
||||
this.productid = productid;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productname;
|
||||
}
|
||||
|
||||
public void setProductName(String productname) {
|
||||
this.productname = productname;
|
||||
}
|
||||
|
||||
|
||||
public String getLuminaireuniqueid() {
|
||||
return luminaireuniqueid;
|
||||
@@ -109,10 +118,11 @@ public class DeviceResponse {
|
||||
|
||||
if (device.isColorDevice()) {
|
||||
response.setType("Extended color light");
|
||||
response.setModelid("LCT010");
|
||||
response.setSwversion("1.15.2_r19181");
|
||||
response.setSwconfigid("F921C859");
|
||||
response.setProductid("Philips-LCT010-1-A19ECLv4");
|
||||
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");
|
||||
@@ -129,13 +139,14 @@ public class DeviceResponse {
|
||||
response.setState(group.getAction());
|
||||
|
||||
response.setName(group.getName());
|
||||
response.setUniqueid("00:17:88:5E:D3:FF-" + String.format("%02X", Integer.parseInt(group.getId())));
|
||||
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("LCT010");
|
||||
response.setSwversion("1.15.2_r19181");
|
||||
response.setSwconfigid("F921C859");
|
||||
response.setProductid("Philips-LCT010-1-A19ECLv4");
|
||||
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);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
public class HueConstants {
|
||||
public final static String HUB_VERSION = "9999999999";
|
||||
public final static String API_VERSION = "1.19.0";
|
||||
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-";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +83,16 @@ public class DeviceDescriptor{
|
||||
@SerializedName("onFirstDim")
|
||||
@Expose
|
||||
private boolean onFirstDim;
|
||||
|
||||
@SerializedName("onWhenDimPresent")
|
||||
@Expose
|
||||
private boolean onWhenDimPresent;
|
||||
@SerializedName("lockDeviceId")
|
||||
@Expose
|
||||
private boolean lockDeviceId;
|
||||
@SerializedName("startupActions")
|
||||
@Expose
|
||||
private String startupActions;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -286,6 +295,14 @@ public class DeviceDescriptor{
|
||||
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;
|
||||
@@ -322,4 +339,20 @@ public class DeviceDescriptor{
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public boolean isLockDeviceId() {
|
||||
return lockDeviceId;
|
||||
}
|
||||
|
||||
public void setLockDeviceId(boolean lockDeviceId) {
|
||||
this.lockDeviceId = lockDeviceId;
|
||||
}
|
||||
|
||||
public String getStartupActions() {
|
||||
return startupActions;
|
||||
}
|
||||
|
||||
public void setStartupActions(String startupActions) {
|
||||
this.startupActions = startupActions;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.bwssystems.HABridge.dao;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -13,18 +11,18 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.plugins.hue.HueHome;
|
||||
import com.bwssystems.HABridge.util.BackupHandler;
|
||||
import com.bwssystems.HABridge.util.JsonTransformer;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
@@ -32,6 +30,8 @@ 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
|
||||
@@ -39,45 +39,49 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class DeviceRepository extends BackupHandler {
|
||||
private Map<String, DeviceDescriptor> devices;
|
||||
private Path repositoryPath;
|
||||
private Path repositoryPath;
|
||||
private Gson gson;
|
||||
private Integer nextId;
|
||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
|
||||
public DeviceRepository(String deviceDb) {
|
||||
private Integer nextId;
|
||||
private Integer seedId;
|
||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
|
||||
public DeviceRepository(String deviceDb, Integer seedid) {
|
||||
super();
|
||||
gson =
|
||||
new GsonBuilder()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
|
||||
repositoryPath = null;
|
||||
repositoryPath = Paths.get(deviceDb);
|
||||
setupParams(repositoryPath, ".bk", "device.db-");
|
||||
nextId = 0;
|
||||
nextId = seedid;
|
||||
seedId = seedid;
|
||||
_loadRepository(repositoryPath);
|
||||
}
|
||||
|
||||
public void loadRepository() {
|
||||
if(repositoryPath != null)
|
||||
_loadRepository(repositoryPath);
|
||||
}
|
||||
private void _loadRepository(Path aPath){
|
||||
|
||||
public void loadRepository() {
|
||||
if (repositoryPath != null)
|
||||
_loadRepository(repositoryPath);
|
||||
}
|
||||
|
||||
private void _loadRepository(Path aPath) {
|
||||
String jsonContent = repositoryReader(aPath);
|
||||
devices = new HashMap<String, DeviceDescriptor>();
|
||||
|
||||
if(jsonContent != null)
|
||||
{
|
||||
|
||||
if (jsonContent != null) {
|
||||
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
list[i].setDeviceState(null);
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i].getColorUrl() == null || list[i].getColorUrl().isEmpty())
|
||||
list[i].setDeviceState(DeviceState.createDeviceState(false));
|
||||
else
|
||||
list[i].setDeviceState(DeviceState.createDeviceState(true));
|
||||
put(list[i].getId(), list[i]);
|
||||
if(Integer.decode(list[i].getId()) > nextId) {
|
||||
if (Integer.decode(list[i].getId()) > nextId) {
|
||||
nextId = Integer.decode(list[i].getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nextId = nextId + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DeviceDescriptor> findAll() {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
return list;
|
||||
@@ -85,8 +89,8 @@ public class DeviceRepository extends BackupHandler {
|
||||
|
||||
public List<DeviceDescriptor> findActive() {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>();
|
||||
for(DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
|
||||
if(!aDevice.isInactive())
|
||||
for (DeviceDescriptor aDevice : new ArrayList<DeviceDescriptor>(devices.values())) {
|
||||
if (!aDevice.isInactive())
|
||||
list.add(aDevice);
|
||||
}
|
||||
return list;
|
||||
@@ -103,12 +107,12 @@ public class DeviceRepository extends BackupHandler {
|
||||
DeviceDescriptor theDevice;
|
||||
String theRequesterAddress;
|
||||
|
||||
HashMap<String,String > addressMap;
|
||||
HashMap<String, String> addressMap;
|
||||
while (anIterator.hasNext()) {
|
||||
theDevice = anIterator.next();
|
||||
theRequesterAddress = theDevice.getRequesterAddress();
|
||||
addressMap = new HashMap<String, String>();
|
||||
if(theRequesterAddress != null) {
|
||||
if (theRequesterAddress != null) {
|
||||
if (theRequesterAddress.contains(",")) {
|
||||
String[] theArray = theRequesterAddress.split(",");
|
||||
for (String v : theArray) {
|
||||
@@ -123,155 +127,222 @@ public class DeviceRepository extends BackupHandler {
|
||||
return theReturnList;
|
||||
}
|
||||
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) {
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||
HueHome myHueHome, Gson aGsonBuilder) {
|
||||
return findAllByGroupWithState(lightsInGroup, anAddress, myHueHome, aGsonBuilder, false);
|
||||
}
|
||||
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) {
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress,
|
||||
HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) {
|
||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||
Map<String, DeviceDescriptor> lights = new HashMap<String, DeviceDescriptor>(devices);
|
||||
lights.keySet().retainAll(Arrays.asList(lightsInGroup));
|
||||
for (DeviceDescriptor light : (ignoreAddress ? lights.values() : findAllByRequester(anAddress, lights.values()))) {
|
||||
for (DeviceDescriptor light : (ignoreAddress ? lights.values()
|
||||
: findAllByRequester(anAddress, lights.values()))) {
|
||||
DeviceResponse deviceResponse = null;
|
||||
if(!light.isInactive()) {
|
||||
if (!light.isInactive()) {
|
||||
if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
CallItem[] callItems = null;
|
||||
try {
|
||||
if(light.getOnUrl() != null)
|
||||
if (light.getOnUrl() != null)
|
||||
callItems = aGsonBuilder.fromJson(light.getOnUrl(), CallItem[].class);
|
||||
} catch(JsonSyntaxException e) {
|
||||
log.warn("Could not decode Json for url items to get Hue state for device: " + light.getName());
|
||||
} catch (JsonSyntaxException e) {
|
||||
log.warn("Could not decode Json for url items to get Hue state for device: {}",
|
||||
light.getName());
|
||||
callItems = null;
|
||||
}
|
||||
|
||||
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||
if((callItems[i].getType() != null && callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) ||
|
||||
(callItems[i].getItem() != null && callItems[i].getItem().getAsString() != null && callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||
if ((callItems[i].getType() != null
|
||||
&& callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex]))
|
||||
|| (callItems[i].getItem() != null && callItems[i].getItem().getAsString() != null
|
||||
&& callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], light);
|
||||
i = callItems.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (deviceResponse == null) {
|
||||
deviceResponse = DeviceResponse.createResponse(light);
|
||||
}
|
||||
deviceResponseMap.put(light.getId(), deviceResponse);
|
||||
deviceResponseMap.put(light.getId(), deviceResponse);
|
||||
}
|
||||
}
|
||||
return (deviceResponseMap.size() == 0) ? null : deviceResponseMap;
|
||||
}
|
||||
|
||||
public DeviceDescriptor findOne(String id) {
|
||||
return devices.get(id);
|
||||
}
|
||||
|
||||
return devices.get(id);
|
||||
}
|
||||
|
||||
private void put(String id, DeviceDescriptor aDescriptor) {
|
||||
devices.put(id, aDescriptor);
|
||||
}
|
||||
|
||||
devices.put(id, aDescriptor);
|
||||
}
|
||||
|
||||
public void save(DeviceDescriptor[] descriptors) {
|
||||
String theNames = "";
|
||||
for(int i = 0; i < descriptors.length; i++) {
|
||||
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||
devices.remove(descriptors[i].getId());
|
||||
else {
|
||||
nextId++;
|
||||
descriptors[i].setId(String.valueOf(nextId));
|
||||
}
|
||||
if(descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
|
||||
BigInteger bigInt = BigInteger.valueOf(Integer.decode(descriptors[i].getId()));
|
||||
byte[] theBytes = bigInt.toByteArray();
|
||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,11 +201,15 @@ public class GroupRepository extends BackupHandler {
|
||||
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)){
|
||||
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));
|
||||
|
||||
@@ -44,13 +44,15 @@ public class DeviceResource {
|
||||
private BridgeSettings bridgeSettings;
|
||||
private Gson aGsonHandler;
|
||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||
private String errorMessage;
|
||||
|
||||
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
|
||||
bridgeSettings = theSettings;
|
||||
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb());
|
||||
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb(), bridgeSettings.getBridgeSettingsDescriptor().getSeedid());
|
||||
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
|
||||
homeManager = aHomeManager;
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
errorMessage = null;
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ public class DeviceResource {
|
||||
return "";
|
||||
});
|
||||
post(API_CONTEXT, "application/json", (request, response) -> {
|
||||
log.debug("Create a Device(s) - request body: " + request.body());
|
||||
log.debug("Create a Device(s) - request body: {}", request.body());
|
||||
DeviceDescriptor devices[];
|
||||
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
|
||||
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
|
||||
@@ -93,13 +95,12 @@ public class DeviceResource {
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
CallItem[] callItems = null;
|
||||
String errorMessage = null;
|
||||
for(int i = 0; i < devices.length; i++) {
|
||||
if(devices[i].getContentBody() != null ) {
|
||||
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
|
||||
log.debug(errorMessage);
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -109,7 +110,7 @@ public class DeviceResource {
|
||||
} catch(JsonSyntaxException e) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
|
||||
log.debug(errorMessage);
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
try {
|
||||
@@ -118,7 +119,7 @@ public class DeviceResource {
|
||||
} catch(JsonSyntaxException e) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
|
||||
log.debug(errorMessage);
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
try {
|
||||
@@ -127,7 +128,7 @@ public class DeviceResource {
|
||||
} catch(JsonSyntaxException e) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
|
||||
log.debug(errorMessage);
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
try {
|
||||
@@ -136,13 +137,13 @@ public class DeviceResource {
|
||||
} catch(JsonSyntaxException e) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "Bad color URL JSON in create device(s) for name: " + devices[i].getName() + " with color URL: " + devices[i].getColorUrl();
|
||||
log.debug(errorMessage);
|
||||
log.warn(errorMessage);
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
deviceRepository.save(devices);
|
||||
log.debug("Created a Device(s): " + request.body());
|
||||
log.debug("Created a Device(s): {}", request.body());
|
||||
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.status(HttpStatus.SC_CREATED);
|
||||
@@ -160,16 +161,17 @@ public class DeviceResource {
|
||||
return "";
|
||||
});
|
||||
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||
log.debug("Edit a Device - request body: " + request.body());
|
||||
log.debug("Edit a Device - request body: {}", request.body());
|
||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||
if(deviceRepository.findOne(request.params(":id")) == null){
|
||||
log.debug("Could not save an edited device, Device Id not found: " + request.params(":id"));
|
||||
errorMessage = "Could not save an edited device, Device Id not found: " + request.params(":id");
|
||||
log.warn(errorMessage);
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug("Saving an edited Device: " + device.getName());
|
||||
log.debug("Saving an edited Device: {}", device.getName());
|
||||
|
||||
if (device.getDeviceType() != null)
|
||||
device.setDeviceType(device.getDeviceType());
|
||||
@@ -187,17 +189,19 @@ public class DeviceResource {
|
||||
log.debug("Get all devices");
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
String theStream = aRenderer.render(deviceList);
|
||||
log.debug("The Device List: " + theStream);
|
||||
log.debug("The Device List: {}", theStream);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return deviceList;
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||
log.debug("Get a device");
|
||||
log.debug("Get a device: {}", request.params(":id"));
|
||||
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
||||
if(descriptor == null) {
|
||||
errorMessage = "Could not find, id: " + request.params(":id");
|
||||
log.warn(errorMessage);
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return new ErrorMessage("Could not find, id: " + request.params(":id") + " ");
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
else
|
||||
response.status(HttpStatus.SC_OK);
|
||||
@@ -206,11 +210,13 @@ public class DeviceResource {
|
||||
|
||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||
String anId = request.params(":id");
|
||||
log.debug("Delete a device: " + anId);
|
||||
log.debug("Delete a device: {}", anId);
|
||||
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
||||
if(deleted == null) {
|
||||
errorMessage = "Could not delete, id: " + anId + " not found. ";
|
||||
log.warn(errorMessage);
|
||||
response.status(HttpStatus.SC_NOT_FOUND);
|
||||
return new ErrorMessage("Could not delete, id: " + anId + " not found. ");
|
||||
return new ErrorMessage(errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -333,6 +339,18 @@ public class DeviceResource {
|
||||
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();
|
||||
@@ -340,7 +358,7 @@ public class DeviceResource {
|
||||
|
||||
get (API_CONTEXT + "/refresh/:typeIndex", "application/json", (request, response) -> {
|
||||
String typeIndex = request.params(":typeIndex");
|
||||
log.debug("Refresh Home: " + typeIndex);
|
||||
log.debug("Refresh Home: {}", typeIndex);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
homeManager.findResource(typeIndex).refresh();
|
||||
return null;
|
||||
@@ -362,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);
|
||||
@@ -377,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()));
|
||||
@@ -394,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());
|
||||
@@ -413,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());
|
||||
|
||||
@@ -26,7 +26,7 @@ public class BrightnessDecode {
|
||||
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;
|
||||
@@ -52,11 +52,22 @@ public class BrightnessDecode {
|
||||
boolean notDone = true;
|
||||
String replaceValue = null;
|
||||
String replaceTarget = null;
|
||||
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
|
||||
float decimalBrightness = (float) (intensity / 255.0);
|
||||
int percentBrightness = 0;
|
||||
float decimalBrightness = (float) 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;
|
||||
}
|
||||
|
||||
while(notDone) {
|
||||
notDone = false;
|
||||
if (request.contains(INTENSITY_BYTE)) {
|
||||
|
||||
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
@@ -0,0 +1,963 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
/**
|
||||
* Convert between different color spaces supported.
|
||||
* RGB -> CMYK -> RGB
|
||||
* RGB -> YIQ -> RGB
|
||||
* RGB -> YCbCr -> RGB
|
||||
* RGB -> YUV -> RGB
|
||||
* RGB -> RGChromaticity
|
||||
* RGB -> HSV -> RGB
|
||||
* RGB -> YCC -> RGB
|
||||
* RGB -> YCoCg -> RGB
|
||||
* RGB -> XYZ -> RGB
|
||||
* RGB -> HunterLAB -> RGB
|
||||
* RGB -> HLS -> RGB
|
||||
* RGB -> CIE-LAB -> RGB
|
||||
* XYZ -> HunterLAB -> XYZ
|
||||
* XYZ -> CIE-LAB -> XYZ
|
||||
* @author Diego Catalano
|
||||
*/
|
||||
public class ColorConverter {
|
||||
|
||||
/**
|
||||
* Don't let anyone instantiate this class.
|
||||
*/
|
||||
private ColorConverter() {}
|
||||
|
||||
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
|
||||
|
||||
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
|
||||
|
||||
//2o Observer (CIE 1931)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE2_A = {109.850f, 100f, 35.585f}; //Incandescent
|
||||
public static float[] CIE2_C = {98.074f, 100f, 118.232f};
|
||||
public static float[] CIE2_D50 = {96.422f, 100f, 82.521f};
|
||||
public static float[] CIE2_D55 = {95.682f, 100f, 92.149f};
|
||||
public static float[] CIE2_D65 = {95.047f, 100f, 108.883f}; //Daylight
|
||||
public static float[] CIE2_D75 = {94.972f, 100f, 122.638f};
|
||||
public static float[] CIE2_F2 = {99.187f, 100f, 67.395f}; //Fluorescent
|
||||
public static float[] CIE2_F7 = {95.044f, 100f, 108.755f};
|
||||
public static float[] CIE2_F11 = {100.966f, 100f, 64.370f};
|
||||
|
||||
//10o Observer (CIE 1964)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE10_A = {111.144f, 100f, 35.200f}; //Incandescent
|
||||
public static float[] CIE10_C = {97.285f, 100f, 116.145f};
|
||||
public static float[] CIE10_D50 = {96.720f, 100f, 81.427f};
|
||||
public static float[] CIE10_D55 = {95.799f, 100f, 90.926f};
|
||||
public static float[] CIE10_D65 = {94.811f, 100f, 107.304f}; //Daylight
|
||||
public static float[] CIE10_D75 = {94.416f, 100f, 120.641f};
|
||||
public static float[] CIE10_F2 = {103.280f, 100f, 69.026f}; //Fluorescent
|
||||
public static float[] CIE10_F7 = {95.792f, 100f, 107.687f};
|
||||
public static float[] CIE10_F11 = {103.866f, 100f, 65.627f};
|
||||
|
||||
/**
|
||||
* RFB -> CMYK
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return CMYK color space. Normalized.
|
||||
*/
|
||||
public static float[] RGBtoCMYK(int red, int green, int blue){
|
||||
float[] cmyk = new float[4];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float k = 1.0f - Math.max(r, Math.max(g, b));
|
||||
float c = (1f-r-k) / (1f-k);
|
||||
float m = (1f-g-k) / (1f-k);
|
||||
float y = (1f-b-k) / (1f-k);
|
||||
|
||||
cmyk[0] = c;
|
||||
cmyk[1] = m;
|
||||
cmyk[2] = y;
|
||||
cmyk[3] = k;
|
||||
|
||||
return cmyk;
|
||||
}
|
||||
|
||||
/**
|
||||
* CMYK -> RGB
|
||||
* @param c Cyan.
|
||||
* @param m Magenta.
|
||||
* @param y Yellow.
|
||||
* @param k Black.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] CMYKtoRGB(float c, float m, float y, float k){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
rgb[0] = (int)(255 * (1-c) * (1-k));
|
||||
rgb[1] = (int)(255 * (1-m) * (1-k));
|
||||
rgb[2] = (int)(255 * (1-y) * (1-k));
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YUV.
|
||||
* Y in the range [0..1].
|
||||
* U in the range [-0.5..0.5].
|
||||
* V in the range [-0.5..0.5].
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YUV color space.
|
||||
*/
|
||||
public static float[] RGBtoYUV(int red, int green, int blue){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] yuv = new float[3];
|
||||
float y,u,v;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
u = (float)(-0.14713 * r - 0.28886 * g + 0.436 * b);
|
||||
v = (float)(0.615 * r - 0.51499 * g - 0.10001 * b);
|
||||
|
||||
yuv[0] = y;
|
||||
yuv[1] = u;
|
||||
yuv[2] = v;
|
||||
|
||||
return yuv;
|
||||
}
|
||||
|
||||
/**
|
||||
* YUV -> RGB.
|
||||
* @param y Luma. In the range [0..1].
|
||||
* @param u Chrominance. In the range [-0.5..0.5].
|
||||
* @param v Chrominance. In the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YUVtoRGB(float y, float u, float v){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
r = (float)((y + 0.000 * u + 1.140 * v) * 255);
|
||||
g = (float)((y - 0.396 * u - 0.581 * v) * 255);
|
||||
b = (float)((y + 2.029 * u + 0.000 * v) * 255);
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YIQ.
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YIQ color space.
|
||||
*/
|
||||
public static float[] RGBtoYIQ(int red, int green, int blue){
|
||||
float[] yiq = new float[3];
|
||||
float y,i,q;
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
i = (float)(0.596 * r - 0.275 * g - 0.322 * b);
|
||||
q = (float)(0.212 * r - 0.523 * g + 0.311 * b);
|
||||
|
||||
yiq[0] = y;
|
||||
yiq[1] = i;
|
||||
yiq[2] = q;
|
||||
|
||||
return yiq;
|
||||
}
|
||||
|
||||
/**
|
||||
* YIQ -> RGB.
|
||||
* @param y Luma. Values in the range [0..1].
|
||||
* @param i In-phase. Values in the range [-0.5..0.5].
|
||||
* @param q Quadrature. Values in the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YIQtoRGB(double y, double i, double q){
|
||||
int[] rgb = new int[3];
|
||||
int r,g,b;
|
||||
|
||||
r = (int)((y + 0.956 * i + 0.621 * q) * 255);
|
||||
g = (int)((y - 0.272 * i - 0.647 * q) * 255);
|
||||
b = (int)((y - 1.105 * i + 1.702 * q) * 255);
|
||||
|
||||
r = Math.max(0,Math.min(255,r));
|
||||
g = Math.max(0,Math.min(255,g));
|
||||
b = Math.max(0,Math.min(255,b));
|
||||
|
||||
rgb[0] = r;
|
||||
rgb[1] = g;
|
||||
rgb[2] = b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
public static float[] RGBtoYCbCr(int red, int green, int blue, YCbCrColorSpace colorSpace){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] YCbCr = new float[3];
|
||||
float y,cb,cr;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
cb = (float)(-0.169 * r - 0.331 * g + 0.500 * b);
|
||||
cr = (float)(0.500 * r - 0.419 * g - 0.081 * b);
|
||||
}
|
||||
else{
|
||||
y = (float)(0.2215 * r + 0.7154 * g + 0.0721 * b);
|
||||
cb = (float)(-0.1145 * r - 0.3855 * g + 0.5000 * b);
|
||||
cr = (float)(0.5016 * r - 0.4556 * g - 0.0459 * b);
|
||||
}
|
||||
|
||||
YCbCr[0] = (float)y;
|
||||
YCbCr[1] = (float)cb;
|
||||
YCbCr[2] = (float)cr;
|
||||
|
||||
return YCbCr;
|
||||
}
|
||||
|
||||
public static int[] YCbCrtoRGB(float y, float cb, float cr, YCbCrColorSpace colorSpace){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
r = (float)(y + 0.000 * cb + 1.403 * cr) * 255;
|
||||
g = (float)(y - 0.344 * cb - 0.714 * cr) * 255;
|
||||
b = (float)(y + 1.773 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
else{
|
||||
r = (float)(y + 0.000 * cb + 1.5701 * cr) * 255;
|
||||
g = (float)(y - 0.1870 * cb - 0.4664 * cr) * 255;
|
||||
b = (float)(y + 1.8556 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rg-Chromaticity space is already known to remove ambiguities due to illumination or surface pose.
|
||||
* @see Neural Information Processing - Chi Sing Leung. p. 668
|
||||
* @param red Red coefficient.
|
||||
* @param green Green coefficient.
|
||||
* @param blue Blue coefficient.
|
||||
* @return Normalized RGChromaticity. Range[0..1].
|
||||
*/
|
||||
public static double[] RGChromaticity(int red, int green, int blue){
|
||||
double[] color = new double[5];
|
||||
|
||||
double sum = red + green + blue;
|
||||
|
||||
//red
|
||||
color[0] = red / sum;
|
||||
|
||||
//green
|
||||
color[1] = green / sum;
|
||||
|
||||
//blue
|
||||
color[2] = 1 - color[0] - color[1];
|
||||
|
||||
double rS = color[0] - 0.333;
|
||||
double gS = color[1] - 0.333;
|
||||
|
||||
//saturation
|
||||
color[3] = Math.sqrt(rS * rS + gS * gS);
|
||||
|
||||
//hue
|
||||
color[4] = Math.atan(rS / gS);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HSV.
|
||||
* Adds (hue + 360) % 360 for represent hue in the range [0..359].
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HSV color space.
|
||||
*/
|
||||
public static float[] RGBtoHSV(int red, int green, int blue){
|
||||
float[] hsv = new float[3];
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float max = Math.max(r, Math.max(g, b));
|
||||
float min = Math.min(r, Math.min(g, b));
|
||||
float delta = max - min;
|
||||
|
||||
// Hue
|
||||
if (max == min){
|
||||
hsv[0] = 0;
|
||||
}
|
||||
else if (max == r){
|
||||
hsv[0] = ((g - b) / delta) * 60f;
|
||||
}
|
||||
else if (max == g){
|
||||
hsv[0] = ((b - r) / delta + 2f) * 60f;
|
||||
}
|
||||
else if (max == b){
|
||||
hsv[0] = ((r - g) / delta + 4f) * 60f;
|
||||
}
|
||||
|
||||
// Saturation
|
||||
if (delta == 0)
|
||||
hsv[1] = 0;
|
||||
else
|
||||
hsv[1] = delta / max;
|
||||
|
||||
//Value
|
||||
hsv[2] = max;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
/**
|
||||
* HSV -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation. In the range[0..1].
|
||||
* @param value Value. In the range[0..1].
|
||||
* @return RGB color space. In the range[0..255].
|
||||
*/
|
||||
public static int[] HSVtoRGB(float hue, float saturation, float value){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float hi = (float)Math.floor(hue / 60.0) % 6;
|
||||
float f = (float)((hue / 60.0) - Math.floor(hue / 60.0));
|
||||
float p = (float)(value * (1.0 - saturation));
|
||||
float q = (float)(value * (1.0 - (f * saturation)));
|
||||
float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));
|
||||
|
||||
if (hi == 0){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(t * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 1){
|
||||
rgb[0] = (int)(q * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 2){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(t * 255);
|
||||
}
|
||||
else if (hi == 3){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
else if (hi == 4){
|
||||
rgb[0] = (int)(t * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 5){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(p * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCC.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCC color space. In the range [0..1].
|
||||
*/
|
||||
public static float[] RGBtoYCC(int red, int green, int blue){
|
||||
float[] ycc = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = 0.213f * r + 0.419f * g + 0.081f * b;
|
||||
float c1 = -0.131f * r - 0.256f * g + 0.387f * b + 0.612f;
|
||||
float c2 = 0.373f * r - 0.312f * r - 0.061f * b + 0.537f;
|
||||
|
||||
ycc[0] = y;
|
||||
ycc[1] = c1;
|
||||
ycc[2] = c2;
|
||||
|
||||
return ycc;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCC -> RGB.
|
||||
* @param y Y coefficient.
|
||||
* @param c1 C coefficient.
|
||||
* @param c2 C coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCCtoRGB(float y, float c1, float c2){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = 0.981f * y + 1.315f * (c2 - 0.537f);
|
||||
float g = 0.981f * y - 0.311f * (c1 - 0.612f)- 0.669f * (c2 - 0.537f);
|
||||
float b = 0.981f * y + 1.601f * (c1 - 0.612f);
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCoCg.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCoCg color space.
|
||||
*/
|
||||
public static float[] RGBtoYCoCg(int red, int green, int blue){
|
||||
float[] yCoCg = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = r / 4f + g / 2f + b / 4f;
|
||||
float co = r / 2f - b / 2f;
|
||||
float cg = -r / 4f + g / 2f - b / 4f;
|
||||
|
||||
yCoCg[0] = y;
|
||||
yCoCg[1] = co;
|
||||
yCoCg[2] = cg;
|
||||
|
||||
return yCoCg;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCoCg -> RGB.
|
||||
* @param y Pseudo luminance, or intensity.
|
||||
* @param co Orange chrominance.
|
||||
* @param cg Green chrominance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCoCgtoRGB(float y, float co, float cg){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = y + co - cg;
|
||||
float g = y + cg;
|
||||
float b = y - co - cg;
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> XYZ
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] RGBtoXYZ(int red, int green, int blue){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
//R
|
||||
if ( r > 0.04045)
|
||||
r = (float)Math.pow(( ( r + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
r /= 12.92f;
|
||||
|
||||
//G
|
||||
if ( g > 0.04045)
|
||||
g = (float)Math.pow(( ( g + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
g /= 12.92f;
|
||||
|
||||
//B
|
||||
if ( b > 0.04045)
|
||||
b = (float)Math.pow(( ( b + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
b /= 12.92f;
|
||||
|
||||
r *= 100;
|
||||
g *= 100;
|
||||
b *= 100;
|
||||
|
||||
float x = 0.412453f * r + 0.35758f * g + 0.180423f * b;
|
||||
float y = 0.212671f * r + 0.71516f * g + 0.072169f * b;
|
||||
float z = 0.019334f * r + 0.119193f * g + 0.950227f * b;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> RGB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] XYZtoRGB(float x, float y, float z){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
x /= 100;
|
||||
y /= 100;
|
||||
z /= 100;
|
||||
|
||||
float r = 3.240479f * x - 1.53715f * y - 0.498535f * z;
|
||||
float g = -0.969256f * x + 1.875991f * y + 0.041556f * z;
|
||||
float b = 0.055648f * x - 0.204043f * y + 1.057311f * z;
|
||||
|
||||
if ( r > 0.0031308 )
|
||||
r = 1.055f * ( (float)Math.pow(r, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
r = 12.92f * r;
|
||||
|
||||
if ( g > 0.0031308 )
|
||||
g = 1.055f * ( (float)Math.pow(g, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
g = 12.92f * g;
|
||||
|
||||
if ( b > 0.0031308 )
|
||||
b = 1.055f * ( (float)Math.pow(b, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
b = 12.92f * b;
|
||||
|
||||
rgb[0] = (int)(r * 255);
|
||||
rgb[1] = (int)(g * 255);
|
||||
rgb[2] = (int)(b * 255);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> HunterLAB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return HunterLab coefficient.
|
||||
*/
|
||||
public static float[] XYZtoHunterLAB(float x, float y, float z){
|
||||
float[] hunter = new float[3];
|
||||
|
||||
|
||||
float sqrt = (float)Math.sqrt(y);
|
||||
|
||||
float l = 10 * sqrt;
|
||||
float a = 17.5f * (((1.02f * x) - y) / sqrt);
|
||||
float b = 7f * ((y - (0.847f * z)) / sqrt);
|
||||
|
||||
hunter[0] = l;
|
||||
hunter[1] = a;
|
||||
hunter[2] = b;
|
||||
|
||||
return hunter;
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> XYZ
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] HunterLABtoXYZ(float l, float a, float b){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
|
||||
float tempY = l / 10f;
|
||||
float tempX = a / 17.5f * l / 10f;
|
||||
float tempZ = b / 7f * l / 10f;
|
||||
|
||||
float y = tempY * tempY;
|
||||
float x = (tempX + y) / 1.02f;
|
||||
float z = -(tempZ - y) / 0.847f;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HunterLAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HunterLAB color space.
|
||||
*/
|
||||
public static float[] RGBtoHunterLAB(int red, int green, int blue){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
return XYZtoHunterLAB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HunterLABtoRGB(float l, float a, float b){
|
||||
float[] xyz = HunterLABtoXYZ(l, a, b);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HLS.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HLS color space.
|
||||
*/
|
||||
public static float[] RGBtoHLS(int red, int green, int blue){
|
||||
float[] hsl = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float max = Math.max(r,Math.max(r,b));
|
||||
float min = Math.min(r,Math.min(r,b));
|
||||
float delta = max - min;
|
||||
|
||||
//HSK
|
||||
float h = 0;
|
||||
float s = 0;
|
||||
float l = (max + min) / 2;
|
||||
|
||||
if ( delta == 0 ){
|
||||
// gray color
|
||||
h = 0;
|
||||
s = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get saturation value
|
||||
s = ( l <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) );
|
||||
|
||||
// get hue value
|
||||
float hue;
|
||||
|
||||
if ( r == max )
|
||||
{
|
||||
hue = ( ( g - b ) / 6 ) / delta;
|
||||
}
|
||||
else if ( g == max )
|
||||
{
|
||||
hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta;
|
||||
}
|
||||
|
||||
// correct hue if needed
|
||||
if ( hue < 0 )
|
||||
hue += 1;
|
||||
if ( hue > 1 )
|
||||
hue -= 1;
|
||||
|
||||
h = (int) ( hue * 360 );
|
||||
}
|
||||
|
||||
hsl[0] = h;
|
||||
hsl[1] = s;
|
||||
hsl[2] = l;
|
||||
|
||||
return hsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* HLS -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation.
|
||||
* @param luminance Luminance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HSLtoRGB(float hue, float saturation, float luminance){
|
||||
int[] rgb = new int[3];
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
if ( saturation == 0 )
|
||||
{
|
||||
// gray values
|
||||
r = g = b = (int) ( luminance * 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
float v1, v2;
|
||||
float h = (float) hue / 360;
|
||||
|
||||
v2 = ( luminance < 0.5 ) ?
|
||||
( luminance * ( 1 + saturation ) ) :
|
||||
( ( luminance + saturation ) - ( luminance * saturation ) );
|
||||
v1 = 2 * luminance - v2;
|
||||
|
||||
r = (int) ( 255 * Hue_2_RGB( v1, v2, h + ( 1.0f / 3 ) ) );
|
||||
g = (int) ( 255 * Hue_2_RGB( v1, v2, h ) );
|
||||
b = (int) ( 255 * Hue_2_RGB( v1, v2, h - ( 1.0f / 3 ) ) );
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static float Hue_2_RGB( float v1, float v2, float vH ){
|
||||
if ( vH < 0 )
|
||||
vH += 1;
|
||||
if ( vH > 1 )
|
||||
vH -= 1;
|
||||
if ( ( 6 * vH ) < 1 )
|
||||
return ( v1 + ( v2 - v1 ) * 6 * vH );
|
||||
if ( ( 2 * vH ) < 1 )
|
||||
return v2;
|
||||
if ( ( 3 * vH ) < 2 )
|
||||
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
|
||||
return v1;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> CIE-LAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] RGBtoLAB(int red, int green, int blue, float[] tristimulus){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
float[] lab = XYZtoLAB(xyz[0], xyz[1], xyz[2], tristimulus);
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] LABtoRGB(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = LABtoXYZ(l, a, b, tristimulus);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> CIE-LAB.
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] XYZtoLAB(float x, float y, float z, float[] tristimulus){
|
||||
float[] lab = new float[3];
|
||||
|
||||
x /= tristimulus[0];
|
||||
y /= tristimulus[1];
|
||||
z /= tristimulus[2];
|
||||
|
||||
if (x > 0.008856)
|
||||
x = (float)Math.pow(x,0.33f);
|
||||
else
|
||||
x = (7.787f * x) + ( 0.1379310344827586f );
|
||||
|
||||
if (y > 0.008856)
|
||||
y = (float)Math.pow(y,0.33f);
|
||||
else
|
||||
y = (7.787f * y) + ( 0.1379310344827586f );
|
||||
|
||||
if (z > 0.008856)
|
||||
z = (float)Math.pow(z,0.33f);
|
||||
else
|
||||
z = (7.787f * z) + ( 0.1379310344827586f );
|
||||
|
||||
lab[0] = ( 116 * y ) - 16;
|
||||
lab[1] = 500 * ( x - y );
|
||||
lab[2] = 200 * ( y - z );
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> XYZ.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] LABtoXYZ(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float y = ( l + 16f ) / 116f;
|
||||
float x = a / 500f + y;
|
||||
float z = y - b / 200f;
|
||||
|
||||
//Y
|
||||
if ( Math.pow(y,3) > 0.008856 )
|
||||
y = (float)Math.pow(y,3);
|
||||
else
|
||||
y = (float)(( y - 16 / 116 ) / 7.787);
|
||||
|
||||
//X
|
||||
if ( Math.pow(x,3) > 0.008856 )
|
||||
x = (float)Math.pow(x,3);
|
||||
else
|
||||
x = (float)(( x - 16 / 116 ) / 7.787);
|
||||
|
||||
// Z
|
||||
if ( Math.pow(z,3) > 0.008856 )
|
||||
z = (float)Math.pow(z,3);
|
||||
else
|
||||
z = (float)(( z - 16 / 116 ) / 7.787);
|
||||
|
||||
xyz[0] = x * tristimulus[0];
|
||||
xyz[1] = y * tristimulus[1];
|
||||
xyz[2] = z * tristimulus[2];
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> C1C2C3.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return C1C2C3 color space.
|
||||
*/
|
||||
public static float[] RGBtoC1C2C3(int r, int g, int b){
|
||||
|
||||
float[] c = new float[3];
|
||||
|
||||
c[0] = (float)Math.atan(r / Math.max(g, b));
|
||||
c[1] = (float)Math.atan(g / Math.max(r, b));
|
||||
c[2] = (float)Math.atan(b / Math.max(r, g));
|
||||
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> O1O2.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return O1O2 color space.
|
||||
*/
|
||||
public static float[] RGBtoO1O2(int r, int g, int b){
|
||||
|
||||
float[] o = new float[2];
|
||||
|
||||
o[0] = (r - g) / 2f;
|
||||
o[1] = (r + g) / 4f - (b / 2f);
|
||||
|
||||
return o;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> Grayscale.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return Grayscale color space.
|
||||
*/
|
||||
public static float RGBtoGrayscale(int r, int g, int b){
|
||||
|
||||
return r*0.2125f + g*0.7154f + b*0.0721f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> Philips Hue XY
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return Hue xy array
|
||||
*/
|
||||
public static XYColorSpace XYZtoXY(float x, float y, float z){
|
||||
float[] xy = new float[2];
|
||||
|
||||
xy[0] = x / (x + y + z);
|
||||
xy[1] = y / (x + y + z);
|
||||
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness((int)Math.round(y * 254.0f));
|
||||
xyColor.setXy(xy);
|
||||
return xyColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Philips Hue XY -> XYZ
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @return XYZ array
|
||||
*/
|
||||
public static float[] XYtoXYZ(XYColorSpace xy){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
|
||||
xyz[1] = xy.getBrightnessAdjusted();
|
||||
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
public static int[] normalizeRGB(int[] rgb) {
|
||||
int[] newRGB = new int[3];
|
||||
|
||||
newRGB[0] = assureBounds(rgb[0]);
|
||||
newRGB[1] = assureBounds(rgb[1]);
|
||||
newRGB[2] = assureBounds(rgb[2]);
|
||||
|
||||
|
||||
return newRGB;
|
||||
}
|
||||
|
||||
private static int assureBounds(int value) {
|
||||
if (value < 0.0) {
|
||||
value = 0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,4 +19,10 @@ public class ColorData {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String formatString;
|
||||
|
||||
formatString = "Color Data mode: " + mode + ", data: " + data;
|
||||
return formatString;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -20,93 +20,134 @@ public class ColorDecode {
|
||||
private static final String COLOR_GX = "${color.gx}";
|
||||
private static final String COLOR_BX = "${color.bx}";
|
||||
private static final String COLOR_RGBX = "${color.rgbx}";
|
||||
private static final String COLOR_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 List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
|
||||
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
|
||||
List<Integer> rgb;
|
||||
double x = xy.get(0); // the given x value
|
||||
double y = xy.get(1); // the given y value
|
||||
double z = 1.0 - x - y;
|
||||
double Y = (double)brightness/(double)254.00; // The given brightness value
|
||||
double X = (Y / y) * x;
|
||||
double Z = (Y / y) * z;
|
||||
|
||||
double r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
|
||||
double g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
|
||||
double b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;
|
||||
|
||||
if (r > b && r > g && r > 1.0) {
|
||||
|
||||
g = g / r;
|
||||
b = b / r;
|
||||
r = 1.0;
|
||||
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;
|
||||
//Bri and Sat must be values from 0-1 (~percentage)
|
||||
brightness = brightness / 255.0f;
|
||||
saturation = saturation / 255.0f;
|
||||
|
||||
Float r = 0f;
|
||||
Float g = 0f;
|
||||
Float b = 0f;
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
r = g = b = brightness;
|
||||
}
|
||||
else if (g > b && g > r && g > 1.0) {
|
||||
|
||||
r = r / g;
|
||||
b = b / g;
|
||||
g = 1.0;
|
||||
else
|
||||
{
|
||||
// the color wheel consists of 6 sectors.
|
||||
Float sectorPos = hue / 60.0f;
|
||||
int sectorNumber = (int)(Math.floor(sectorPos));
|
||||
// get the fractional part of the sector
|
||||
Float fractionalSector = sectorPos - sectorNumber;
|
||||
|
||||
// calculate values for the three axes of the color.
|
||||
Float p = brightness * (1.0f - saturation);
|
||||
Float q = brightness * (1.0f - (saturation * fractionalSector));
|
||||
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
|
||||
|
||||
// assign the fractional colors to r, g, and b based on the sector the angle is in.
|
||||
switch (sectorNumber)
|
||||
{
|
||||
case 0:
|
||||
r = brightness;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = brightness;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = brightness;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = brightness;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = brightness;
|
||||
break;
|
||||
case 5:
|
||||
r = brightness;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (b > r && b > g && b > 1.0) {
|
||||
|
||||
r = r / b;
|
||||
g = g / b;
|
||||
b = 1.0;
|
||||
|
||||
//Check if any value is out of byte range
|
||||
if (r < 0f)
|
||||
{
|
||||
r = 0f;
|
||||
}
|
||||
|
||||
|
||||
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
||||
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
||||
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
||||
|
||||
if (r > b && r > g) {
|
||||
// red is biggest
|
||||
if (r > 1.0) {
|
||||
g = g / r;
|
||||
b = b / r;
|
||||
r = 1.0;
|
||||
}
|
||||
}
|
||||
else if (g > b && g > r) {
|
||||
// green is biggest
|
||||
if (g > 1.0) {
|
||||
r = r / g;
|
||||
b = b / g;
|
||||
g = 1.0;
|
||||
}
|
||||
}
|
||||
else if (b > r && b > g) {
|
||||
// blue is biggest
|
||||
if (b > 1.0) {
|
||||
r = r / b;
|
||||
g = g / b;
|
||||
b = 1.0;
|
||||
}
|
||||
}
|
||||
if(r < 0.0)
|
||||
r = 0;
|
||||
if(g < 0.0)
|
||||
g = 0;
|
||||
if(b < 0.0)
|
||||
b = 0;
|
||||
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add((int)Math.round(r * 255));
|
||||
rgb.add((int)Math.round(g * 255));
|
||||
rgb.add((int)Math.round(b * 255));
|
||||
log.debug("Color change with XY: " + x + " " + y + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
|
||||
if (g < 0f)
|
||||
{
|
||||
g = 0f;
|
||||
}
|
||||
if (b < 0f)
|
||||
{
|
||||
b = 0f;
|
||||
}
|
||||
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add((int)Math.round(r*255));
|
||||
rgb.add((int)Math.round(g*255));
|
||||
rgb.add((int)Math.round(b*255));
|
||||
log.debug("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
// took that approximation from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
|
||||
List<Integer> rgb;
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness(brightness);
|
||||
float[] xyFloat = new float[2];
|
||||
xyFloat[0] = xy.get(0).floatValue();
|
||||
xyFloat[1] = xy.get(1).floatValue();
|
||||
xyColor.setXy(xyFloat);
|
||||
float[] xyz = ColorConverter.XYtoXYZ(xyColor);
|
||||
int[] rgbInt = ColorConverter.normalizeRGB(ColorConverter.XYZtoRGB(xyz[0], xyz[1], xyz[2]));
|
||||
rgb = new ArrayList<Integer>();
|
||||
rgb.add(rgbInt[0]);
|
||||
rgb.add(rgbInt[1]);
|
||||
rgb.add(rgbInt[2]);
|
||||
log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||
+ " " + rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
// took that approximation from
|
||||
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
public static List<Integer> convertCTtoRGB(Integer ct) {
|
||||
double temperature = 1000000.0 / (double)ct;
|
||||
double temperature = 1000000.0 / (double) ct;
|
||||
temperature /= 100;
|
||||
double r,g,b;
|
||||
double r, g, b;
|
||||
if (temperature <= 66) {
|
||||
r = 255;
|
||||
g = temperature;
|
||||
g = 99.4708025861 * Math.log(g) - 161.1195681661;
|
||||
g = 99.4708025861 * Math.log(g) - 161.1195681661;
|
||||
} else {
|
||||
r = temperature - 60;
|
||||
r = 329.698727446 * (Math.pow(r, -0.1332047592));
|
||||
@@ -124,25 +165,26 @@ public class ColorDecode {
|
||||
b = 138.5177312231 * Math.log(b) - 305.0447927307;
|
||||
}
|
||||
}
|
||||
r = assureBounds(r);
|
||||
g = assureBounds(g);
|
||||
b = assureBounds(b);
|
||||
List<Integer> rgb = new ArrayList<Integer>();
|
||||
rgb.add((int)Math.round(r));
|
||||
rgb.add((int)Math.round(g));
|
||||
rgb.add((int)Math.round(b));
|
||||
log.debug("Color change with CT: " + ct + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
|
||||
return rgb;
|
||||
r = assureBounds(r);
|
||||
g = assureBounds(g);
|
||||
b = assureBounds(b);
|
||||
List<Integer> rgb = new ArrayList<Integer>();
|
||||
rgb.add((int) Math.round(r));
|
||||
rgb.add((int) Math.round(g));
|
||||
rgb.add((int) Math.round(b));
|
||||
log.debug("Color change with CT: " + ct + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static double assureBounds(double value) {
|
||||
if (value < 0.0) {
|
||||
value = 0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
value = 0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -157,25 +199,30 @@ public class ColorDecode {
|
||||
ColorData.ColorMode colorMode = colorData.getColorMode();
|
||||
List<Integer> rgb = null;
|
||||
if (colorMode == ColorData.ColorMode.XY) {
|
||||
rgb = convertCIEtoRGB((List<Double>)colorData.getData(), setIntensity);
|
||||
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
|
||||
} else if (colorMode == ColorData.ColorMode.CT) {
|
||||
rgb = convertCTtoRGB((Integer)colorData.getData());
|
||||
rgb = convertCTtoRGB((Integer) colorData.getData());
|
||||
} else if (colorMode == ColorData.ColorMode.HS) {
|
||||
rgb = convertHSBtoRGB((HueSatBri) colorData.getData());
|
||||
}
|
||||
|
||||
while(notDone) {
|
||||
|
||||
while (notDone) {
|
||||
notDone = false;
|
||||
if (request.contains(COLOR_R)) {
|
||||
request = request.replace(COLOR_R, isHex ? String.format("%02X", rgb.get(0)) : String.valueOf(rgb.get(0)));
|
||||
request = request.replace(COLOR_R,
|
||||
isHex ? String.format("%02X", rgb.get(0)) : String.valueOf(rgb.get(0)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_G)) {
|
||||
request = request.replace(COLOR_G, isHex ? String.format("%02X", rgb.get(1)) : String.valueOf(rgb.get(1)));
|
||||
request = request.replace(COLOR_G,
|
||||
isHex ? String.format("%02X", rgb.get(1)) : String.valueOf(rgb.get(1)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_B)) {
|
||||
request = request.replace(COLOR_B, isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
|
||||
request = request.replace(COLOR_B,
|
||||
isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
@@ -195,65 +242,131 @@ public class ColorDecode {
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_RGBX)) {
|
||||
request = request.replace(COLOR_RGBX, String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)));
|
||||
request = request.replace(COLOR_RGBX,
|
||||
String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)));
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
|
||||
if (request.contains(COLOR_XY)) {
|
||||
if (colorMode == ColorData.ColorMode.XY) {
|
||||
List<Double> xyData = (List<Double>) colorData.getData();
|
||||
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||
} else {
|
||||
List<Double> xyData = (List<Double>) colorData.getData();
|
||||
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_H)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float hue = hsb[0] * (float) 360.0;
|
||||
request = request.replace(COLOR_H, String.format("%f", hue));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_S)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
request = request.replace(COLOR_S, String.format("%f", sat));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_BRI)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
|
||||
} else {
|
||||
request = request.replace(COLOR_BRI, String.format("%f", setIntensity));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_HSB)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_HSB,
|
||||
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float hue = hsb[0] * (float) 360.0;
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
float bright = hsb[2] * (float) 100.0;
|
||||
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
Matcher m = COLOR_MILIGHT.matcher(request);
|
||||
while (m.find()) {
|
||||
int group = Integer.parseInt(m.group(1));
|
||||
request = m.replaceFirst(getMilightV5FromRgb(rgb, group));
|
||||
m.reset(request);
|
||||
int group = Integer.parseInt(m.group(1));
|
||||
request = m.replaceFirst(getMilightV5FromRgb(rgb, group));
|
||||
m.reset(request);
|
||||
}
|
||||
|
||||
|
||||
log.debug("Request <<" + request + ">>, not done: " + notDone);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private static String getMilightV5FromRgb(List<Integer> rgb, int group) {
|
||||
double r = (double)rgb.get(0);
|
||||
double g = (double)rgb.get(1);
|
||||
double b = (double)rgb.get(2);
|
||||
if (r > 245 && g > 245 && b > 245) { // it's white
|
||||
String retVal = "";
|
||||
if (group == 0) {
|
||||
retVal += "C2";
|
||||
} else if (group == 1) {
|
||||
retVal += "C5";
|
||||
} else if (group == 2) {
|
||||
retVal += "C7";
|
||||
} else if (group == 3) {
|
||||
retVal += "C9";
|
||||
} else if (group == 4) {
|
||||
retVal += "CB";
|
||||
}
|
||||
log.debug("Convert RGB to Milight. Result: WHITE. RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
|
||||
return retVal + "0055";
|
||||
} else { // normal color
|
||||
r /= (double)0xFF;
|
||||
g /= (double)0xFF;
|
||||
b /= (double)0xFF;
|
||||
double max = Math.max(Math.max(r, g), b), min = Math.min(Math.min(r, g), b);
|
||||
double h = 0;
|
||||
double d = max - min;
|
||||
double r = (double) rgb.get(0);
|
||||
double g = (double) rgb.get(1);
|
||||
double b = (double) rgb.get(2);
|
||||
if (r > 245 && g > 245 && b > 245) { // it's white
|
||||
String retVal = "";
|
||||
if (group == 0) {
|
||||
retVal += "C2";
|
||||
} else if (group == 1) {
|
||||
retVal += "C5";
|
||||
} else if (group == 2) {
|
||||
retVal += "C7";
|
||||
} else if (group == 3) {
|
||||
retVal += "C9";
|
||||
} else if (group == 4) {
|
||||
retVal += "CB";
|
||||
}
|
||||
log.debug("Convert RGB to Milight. Result: WHITE. RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
|
||||
+ rgb.get(2));
|
||||
return retVal + "0055";
|
||||
} else { // normal color
|
||||
r /= (double) 0xFF;
|
||||
g /= (double) 0xFF;
|
||||
b /= (double) 0xFF;
|
||||
double max = Math.max(Math.max(r, g), b), min = Math.min(Math.min(r, g), b);
|
||||
double h = 0;
|
||||
double d = max - min;
|
||||
|
||||
if (max == min) {
|
||||
h = 0;
|
||||
} else {
|
||||
if (max == r) {
|
||||
h = ((g - b) / d + (g < b ? 6 : 0));
|
||||
} else if (max == g) {
|
||||
h = ((b - r) / d + 2);
|
||||
} else if (max == b){
|
||||
h = ((r - g) / d + 4);
|
||||
}
|
||||
h = Math.round(h * 60);
|
||||
}
|
||||
int milight = (int)((256 + 176 - Math.floor(h / 360.0 * 255.0)) % 256);
|
||||
log.debug("Convert RGB to Milight. Result: " + milight + " RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
|
||||
return "40" + String.format("%02X", milight) + "55";
|
||||
}
|
||||
if (max == min) {
|
||||
h = 0;
|
||||
} else {
|
||||
if (max == r) {
|
||||
h = ((g - b) / d + (g < b ? 6 : 0));
|
||||
} else if (max == g) {
|
||||
h = ((b - r) / d + 2);
|
||||
} else if (max == b) {
|
||||
h = ((r - g) / d + 4);
|
||||
}
|
||||
h = Math.round(h * 60);
|
||||
}
|
||||
int milight = (int) ((256 + 176 - Math.floor(h / 360.0 * 255.0)) % 256);
|
||||
log.debug("Convert RGB to Milight. Result: " + milight + " RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||
+ " " + rgb.get(2));
|
||||
return "40" + String.format("%02X", milight) + "55";
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -119,13 +119,13 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
log.warn("Should not get here, no Nest available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no Nest available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_HOMEAWAY[DeviceMapTypes.typeIndex])) {
|
||||
NestInstruction homeAway = null;
|
||||
if(anItem.getItem().isJsonObject())
|
||||
homeAway = aGsonHandler.fromJson(anItem.getItem(), NestInstruction.class);
|
||||
else
|
||||
homeAway = aGsonHandler.fromJson(anItem.getItem().getAsString(), NestInstruction.class);
|
||||
homeAway = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), NestInstruction.class);
|
||||
theNest.getHome(homeAway.getName()).setAway(homeAway.getAway());
|
||||
} else if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.NEST_THERMO_SET[DeviceMapTypes.typeIndex])) {
|
||||
NestInstruction thermoSetting = null;
|
||||
@@ -167,7 +167,7 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
log.warn("no valid Nest control info: " + thermoSetting.getControl());
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"no valid Nest control info\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
return responseString;
|
||||
|
||||
@@ -11,8 +11,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -28,6 +26,7 @@ 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;
|
||||
@@ -107,18 +106,21 @@ public class BroadlinkHome implements Home {
|
||||
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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
|
||||
} else {
|
||||
BroadlinkEntry broadlinkCommand = null;
|
||||
broadlinkCommand = new Gson().fromJson(anItem.getItem().getAsString(), BroadlinkEntry.class);
|
||||
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 = DatatypeConverter.parseHexBinary(broadlinkCommand.getType());
|
||||
byte[] intBytes = HexLibrary.decodeHexString(broadlinkCommand.getType());
|
||||
BigInteger theBig = new BigInteger(intBytes);
|
||||
int theType = theBig.intValue();
|
||||
try {
|
||||
@@ -127,32 +129,35 @@ public class BroadlinkHome implements Home {
|
||||
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\"}}]";
|
||||
+ 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\"}}]";
|
||||
+ 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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
|
||||
if(broadlinkMap == null)
|
||||
broadlinkMap = new HashMap<String, BLDevice>();
|
||||
|
||||
String newId = theDevice.getHost() + "-" + String.format("%04x", theDevice.getDeviceType());
|
||||
if(broadlinkMap.get(newId) == null)
|
||||
broadlinkMap.put(newId, theDevice);
|
||||
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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
log.debug("calling BroadlinkDevice: " + broadlinkCommand.getName());
|
||||
try {
|
||||
@@ -161,7 +166,7 @@ public class BroadlinkHome implements Home {
|
||||
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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
switch (theDevice.getDeviceType()) {
|
||||
@@ -218,13 +223,13 @@ public class BroadlinkHome implements Home {
|
||||
}
|
||||
theStringData = DeviceDataDecode.replaceDeviceData(theStringData, device);
|
||||
theStringData = TimeDecode.replaceTimeValue(theStringData);
|
||||
byte[] theData = DatatypeConverter.parseHexBinary(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 = DatatypeConverter.printHexBinary(thePacket.getData());
|
||||
returnData = HexLibrary.encodeHexString(thePacket.getData());
|
||||
else
|
||||
returnData = "No Data - null";
|
||||
log.debug("RM2 Device data return: <<<" + returnData + ">>>");
|
||||
@@ -233,7 +238,7 @@ public class BroadlinkHome implements Home {
|
||||
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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -242,7 +247,7 @@ public class BroadlinkHome implements Home {
|
||||
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\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -33,7 +33,7 @@ public class TestBLDevice extends BLDevice {
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.bwssystems.HABridge.plugins.broadlink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -23,7 +23,7 @@ public class TestMP1Device extends MP1Device {
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge.plugins.broadlink;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -21,7 +21,7 @@ public class TestRM2Device extends RM2Device {
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(((SendDataCmdPayload)aCmd).getData()));
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(((SendDataCmdPayload)aCmd).getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge.plugins.broadlink;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -24,7 +24,7 @@ public class TestSP1Device extends SP1Device {
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
|
||||
log.info("sendCmdPkt called with " + HexLibrary.encodeHexString(aCmd.getPayload().getData()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge.plugins.broadlink;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -24,7 +24,7 @@ public class TestSP2Device extends SP2Device {
|
||||
}
|
||||
|
||||
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
|
||||
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class DomoticzHome implements Home {
|
||||
|
||||
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();
|
||||
@@ -88,7 +88,7 @@ public class DomoticzHome implements Home {
|
||||
Devices theDomoticzApiResponse = null;
|
||||
String responseString = null;
|
||||
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
@@ -119,7 +119,7 @@ public class DomoticzHome implements Home {
|
||||
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
|
||||
aBody = TimeDecode.replaceTimeValue(aBody);
|
||||
}
|
||||
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, aBody, theHandler.buildHeaders());
|
||||
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"))
|
||||
@@ -128,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;
|
||||
}
|
||||
|
||||
@@ -31,13 +31,14 @@ public class CommandHome implements Home {
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
log.debug("Exec Request called with url: " + anItem.getItem().getAsString() + " and exec Garden: " + (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
|
||||
String theItem = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
log.debug("Exec Request called with url: {} and exec Garden: {}", theItem, (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
|
||||
String responseString = null;
|
||||
String intermediate;
|
||||
if (anItem.getItem().getAsString().contains("exec://"))
|
||||
intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
||||
if (theItem.contains("exec://"))
|
||||
intermediate = theItem.substring(anItem.getItem().getAsString().indexOf("://") + 3);
|
||||
else
|
||||
intermediate = anItem.getItem().getAsString();
|
||||
intermediate = theItem;
|
||||
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
intermediate = ColorDecode.replaceColorData(intermediate, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
@@ -67,13 +68,13 @@ public class CommandHome implements Home {
|
||||
log.warn("Could not execute request: " + anItem + " with message: " + e.getMessage());
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
||||
+ "state\"}}]";
|
||||
+ "/state\"}}]";
|
||||
}
|
||||
} else {
|
||||
log.warn("Could not execute request. Request is empty.");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
||||
+ "state\"}}]";
|
||||
+ "/state\"}}]";
|
||||
}
|
||||
|
||||
return responseString;
|
||||
|
||||
@@ -27,6 +27,7 @@ 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);
|
||||
@@ -47,18 +48,22 @@ public class FHEMHome implements Home {
|
||||
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();
|
||||
JsonElement jsonUrl = anItem.getItem();
|
||||
String theUrl = jsonUrl.toString();
|
||||
String responseString = null;
|
||||
|
||||
if(theUrl != null && !theUrl.isEmpty()) {
|
||||
FHEMCommand theCommand = null;
|
||||
try {
|
||||
theCommand = new Gson().fromJson(theUrl, FHEMCommand.class);
|
||||
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);
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
return responseString;
|
||||
}
|
||||
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().indexOf("://") + 3);
|
||||
|
||||
@@ -33,6 +33,7 @@ public class FHEMInstance {
|
||||
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
|
||||
@@ -41,6 +42,10 @@ public class FHEMInstance {
|
||||
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)
|
||||
@@ -54,6 +59,7 @@ public class FHEMInstance {
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
NameValue[] headers = null;
|
||||
/* Trying new code helpers
|
||||
if(theFhem.getSecure() != null && theFhem.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
@@ -61,7 +67,10 @@ public class FHEMInstance {
|
||||
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 = 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);
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -30,7 +29,7 @@ public class FibaroInfo
|
||||
{
|
||||
super();
|
||||
fibaroAddress = addressName;
|
||||
fibaroAuth = "Basic " + new String(Base64.encodeBase64((addressName.getUsername() + ":" + addressName.getPassword()).getBytes()));
|
||||
fibaroAuth = "Basic " + addressName.getUserPass64();
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
gson = new Gson();
|
||||
theFilters = null;
|
||||
|
||||
@@ -104,7 +104,7 @@ public class HalHome implements Home {
|
||||
|
||||
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
||||
if(!validHal)
|
||||
return null;
|
||||
return false;
|
||||
Iterator<HalDevice> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
HalDevice theDevice = devices.next();
|
||||
@@ -123,7 +123,7 @@ public class HalHome implements Home {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
boolean halFound = false;
|
||||
String responseString = null;
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.contains("http")) {
|
||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
@@ -165,7 +165,7 @@ public class HalHome implements Home {
|
||||
log.warn("Error on calling hal to change device state: " + anUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ public class HalHome implements Home {
|
||||
log.warn("No HAL found to call: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"No HAL found.", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
|
||||
public class HarmonyHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||
@@ -16,8 +17,9 @@ public class HarmonyHandler {
|
||||
private Boolean noopCalls;
|
||||
private Boolean devMode;
|
||||
private DevModeResponse devResponse;
|
||||
private NamedIP myNameAndIP;
|
||||
|
||||
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
|
||||
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting, NamedIP aNameAndIP) {
|
||||
super();
|
||||
noopCalls = noopCallsSetting;
|
||||
devMode = Boolean.TRUE;
|
||||
@@ -27,6 +29,7 @@ public class HarmonyHandler {
|
||||
else
|
||||
devResponse = devResponseSetting;
|
||||
harmonyClient = theClient;
|
||||
myNameAndIP = aNameAndIP;
|
||||
}
|
||||
|
||||
public List<Activity> getActivities() {
|
||||
@@ -34,7 +37,16 @@ public class HarmonyHandler {
|
||||
if(devMode)
|
||||
return devResponse.getActivities();
|
||||
|
||||
return harmonyClient.getConfig().getActivities();
|
||||
List<Activity> listOfActivities = null;
|
||||
|
||||
try {
|
||||
listOfActivities = harmonyClient.getConfig().getActivities();
|
||||
} catch (RuntimeException e) {
|
||||
handleExceptionError(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return listOfActivities;
|
||||
}
|
||||
|
||||
public List<Device> getDevices() {
|
||||
@@ -42,7 +54,15 @@ public class HarmonyHandler {
|
||||
if(devMode)
|
||||
return devResponse.getDevices();
|
||||
|
||||
return harmonyClient.getConfig().getDevices();
|
||||
List<Device> listOfDevices = null;
|
||||
|
||||
try {
|
||||
listOfDevices = harmonyClient.getConfig().getDevices();
|
||||
} catch (RuntimeException e) {
|
||||
handleExceptionError(e);
|
||||
return null;
|
||||
}
|
||||
return listOfDevices;
|
||||
}
|
||||
|
||||
public HarmonyConfig getConfig() {
|
||||
@@ -50,15 +70,29 @@ public class HarmonyHandler {
|
||||
if(devMode)
|
||||
return devResponse.getConfig();
|
||||
|
||||
return harmonyClient.getConfig();
|
||||
HarmonyConfig aConfig = null;
|
||||
try {
|
||||
aConfig = harmonyClient.getConfig();
|
||||
} catch (RuntimeException e) {
|
||||
handleExceptionError(e);
|
||||
return null;
|
||||
}
|
||||
return aConfig;
|
||||
}
|
||||
|
||||
public Activity getCurrentActivity() {
|
||||
log.debug("Harmony api current sctivity requested.");
|
||||
if(devMode)
|
||||
return devResponse.getCurrentActivity();
|
||||
|
||||
return harmonyClient.getCurrentActivity();
|
||||
|
||||
Activity anActivity = null;
|
||||
try {
|
||||
anActivity = harmonyClient.getCurrentActivity();
|
||||
} catch (RuntimeException e) {
|
||||
handleExceptionError(e);
|
||||
return null;
|
||||
}
|
||||
return anActivity;
|
||||
}
|
||||
|
||||
public Boolean startActivity(RunActivity anActivity) {
|
||||
@@ -82,12 +116,14 @@ public class HarmonyHandler {
|
||||
harmonyClient.startActivityByName(anActivity.getName());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||
return false;
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -113,11 +149,22 @@ public class HarmonyHandler {
|
||||
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
|
||||
return false;
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} catch (RuntimeException e1) {
|
||||
return handleExceptionError(e1);
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean handleExceptionError(Exception e) {
|
||||
if(e.getMessage().contains("Failed communicating with Harmony Hub") || e.getMessage().contains("Send heartbeat failed")) {
|
||||
log.warn("Issue in communcicating with Harmony Hub, retrying connect....");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,9 +175,19 @@ public class HarmonyHandler {
|
||||
log.debug("Harmony api shutdown requested.");
|
||||
if(devMode)
|
||||
return;
|
||||
|
||||
harmonyClient.disconnect();
|
||||
try {
|
||||
harmonyClient.disconnect();
|
||||
} catch(Exception e)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
harmonyClient = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the myNameAndIP
|
||||
*/
|
||||
public NamedIP getMyNameAndIP() {
|
||||
return myNameAndIP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
|
||||
public class HarmonyHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||
private Map<String, HarmonyServer> hubs;
|
||||
private Boolean isDevMode;
|
||||
private Boolean validHarmony;
|
||||
@@ -43,91 +43,136 @@ public class HarmonyHome implements Home {
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
if(!validHarmony)
|
||||
if (!validHarmony)
|
||||
return;
|
||||
log.debug("Closing Home.");
|
||||
if(closed) {
|
||||
if (closed) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
if(isDevMode || hubs == null)
|
||||
if (isDevMode || hubs == null)
|
||||
return;
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
hubs.get(key).getMyHarmony().shutdown();
|
||||
}
|
||||
|
||||
|
||||
hubs = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
public HarmonyHandler getHarmonyHandler(String aName) {
|
||||
if(!validHarmony)
|
||||
if (!validHarmony)
|
||||
return null;
|
||||
HarmonyHandler aHandler = null;
|
||||
if(aName == null || aName.equals("")) {
|
||||
if (aName == null || aName.equals("")) {
|
||||
aName = "default";
|
||||
}
|
||||
|
||||
if(hubs.get(aName) == null) {
|
||||
if (hubs.get(aName) == null) {
|
||||
Set<String> keys = hubs.keySet();
|
||||
if(!keys.isEmpty()) {
|
||||
if (!keys.isEmpty()) {
|
||||
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
||||
}
|
||||
else
|
||||
} else
|
||||
aHandler = null;
|
||||
}
|
||||
else
|
||||
} else
|
||||
aHandler = hubs.get(aName).getMyHarmony();
|
||||
return aHandler;
|
||||
}
|
||||
|
||||
|
||||
public List<HarmonyActivity> getActivities() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||
if(!validHarmony)
|
||||
if (!validHarmony)
|
||||
return null;
|
||||
while(keys.hasNext()) {
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||
while(activities.hasNext()) {
|
||||
if (activities == null) {
|
||||
resetHub(hubs.get(key).getMyHarmony());
|
||||
activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||
if (activities == null) {
|
||||
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||
activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||
if (activities == null) {
|
||||
log.error("Could not get communication restored with hub: " + key
|
||||
+ ", please restart...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activities != null) {
|
||||
while (activities.hasNext()) {
|
||||
HarmonyActivity anActivity = new HarmonyActivity();
|
||||
anActivity.setActivity(activities.next());
|
||||
anActivity.setHub(key);
|
||||
activityList.add(anActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return activityList;
|
||||
}
|
||||
|
||||
public List<HarmonyActivity> getCurrentActivities() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||
if (!validHarmony)
|
||||
return null;
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Activity theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||
if (theActivity == null) {
|
||||
resetHub(hubs.get(key).getMyHarmony());
|
||||
theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||
if (theActivity == null) {
|
||||
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||
theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||
if (theActivity == null) {
|
||||
log.error("Could not get communication restored with hub: " + key
|
||||
+ ", please restart...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theActivity != null) {
|
||||
HarmonyActivity anActivity = new HarmonyActivity();
|
||||
anActivity.setActivity(activities.next());
|
||||
anActivity.setActivity(theActivity);
|
||||
anActivity.setHub(key);
|
||||
activityList.add(anActivity);
|
||||
}
|
||||
}
|
||||
return activityList;
|
||||
}
|
||||
public List<HarmonyActivity> getCurrentActivities() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||
if(!validHarmony)
|
||||
return null;
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Activity theActivity = hubs.get(key).getMyHarmony().getCurrentActivity();
|
||||
HarmonyActivity anActivity = new HarmonyActivity();
|
||||
anActivity.setActivity(theActivity);
|
||||
anActivity.setHub(key);
|
||||
activityList.add(anActivity);
|
||||
}
|
||||
return activityList;
|
||||
}
|
||||
|
||||
public List<HarmonyDevice> getDevices() {
|
||||
Iterator<String> keys = hubs.keySet().iterator();
|
||||
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
||||
if(!validHarmony)
|
||||
if (!validHarmony)
|
||||
return null;
|
||||
while(keys.hasNext()) {
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||
while(devices.hasNext()) {
|
||||
HarmonyDevice aDevice = new HarmonyDevice();
|
||||
aDevice.setDevice(devices.next());
|
||||
aDevice.setHub(key);
|
||||
deviceList.add(aDevice);
|
||||
if (devices == null) {
|
||||
resetHub(hubs.get(key).getMyHarmony());
|
||||
devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||
if (devices == null) {
|
||||
if (resetHub(hubs.get(key).getMyHarmony())) {
|
||||
devices = hubs.get(key).getMyHarmony().getDevices().iterator();
|
||||
if (devices == null) {
|
||||
log.error("Could not get communication restored with hub: " + key
|
||||
+ ", please restart...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (devices != null) {
|
||||
while (devices.hasNext()) {
|
||||
HarmonyDevice aDevice = new HarmonyDevice();
|
||||
aDevice.setDevice(devices.next());
|
||||
aDevice.setHub(key);
|
||||
deviceList.add(aDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
@@ -135,36 +180,47 @@ public class HarmonyHome implements Home {
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String responseString = null;
|
||||
log.debug("executing HUE api request to change " + anItem.getType() + " to Harmony: " + device.getName());
|
||||
if(!validHarmony) {
|
||||
if (!validHarmony) {
|
||||
log.warn("Should not get here, no harmony configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
if(anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex]))
|
||||
{
|
||||
if (anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex])) {
|
||||
RunActivity anActivity = null;
|
||||
if(anItem.getItem().isJsonObject())
|
||||
if (anItem.getItem().isJsonObject())
|
||||
anActivity = aGsonHandler.fromJson(anItem.getItem(), RunActivity.class);
|
||||
else
|
||||
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString(), RunActivity.class);
|
||||
if(anActivity.getHub() == null || anActivity.getHub().isEmpty())
|
||||
anActivity = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), RunActivity.class);
|
||||
if (anActivity.getHub() == null || anActivity.getHub().isEmpty())
|
||||
anActivity.setHub(device.getTargetDevice());
|
||||
HarmonyHandler myHarmony = getHarmonyHandler(anActivity.getHub());
|
||||
if (myHarmony == null) {
|
||||
log.warn("Should not get here, no harmony hub available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
myHarmony.startActivity(anActivity);
|
||||
if (!myHarmony.startActivity(anActivity)) {
|
||||
if (resetHub(myHarmony)) {
|
||||
myHarmony = getHarmonyHandler(anActivity.getHub());
|
||||
if (!myHarmony.startActivity(anActivity)) {
|
||||
log.error("Could not get communication restored with hub: " + anActivity.getHub()
|
||||
+ ", please restart...");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not communicate with harmony\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex])) {
|
||||
} else if (anItem.getType().trim()
|
||||
.equalsIgnoreCase(DeviceMapTypes.HARMONY_BUTTON[DeviceMapTypes.typeIndex])) {
|
||||
String url = null;
|
||||
if(anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
|
||||
if (anItem.getItem().isJsonObject() || anItem.getItem().isJsonArray()) {
|
||||
url = aGsonHandler.toJson(anItem.getItem());
|
||||
} else
|
||||
url = anItem.getItem().getAsString();
|
||||
@@ -172,35 +228,50 @@ public class HarmonyHome implements Home {
|
||||
if (url.substring(0, 1).equalsIgnoreCase("{")) {
|
||||
url = "[" + url + "]";
|
||||
}
|
||||
|
||||
|
||||
url = BrightnessDecode.calculateReplaceIntensityValue(url, intensity, targetBri, targetBriInc, false);
|
||||
ButtonPress[] deviceButtons = aGsonHandler.fromJson(url, ButtonPress[].class);
|
||||
Integer theCount = 1;
|
||||
for(int z = 0; z < deviceButtons.length; z++) {
|
||||
if(deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
|
||||
theCount = deviceButtons[z].getCount();
|
||||
for(int y = 0; y < theCount; y++) {
|
||||
if( y > 0 || z > 0) {
|
||||
try {
|
||||
Thread.sleep(aMultiUtil.getTheDelay());
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
Integer theCount = 1;
|
||||
for (int z = 0; z < deviceButtons.length; z++) {
|
||||
if (deviceButtons[z].getCount() != null && deviceButtons[z].getCount() > 0)
|
||||
theCount = deviceButtons[z].getCount();
|
||||
for (int y = 0; y < theCount; y++) {
|
||||
if (y > 0 || z > 0) {
|
||||
try {
|
||||
Thread.sleep(aMultiUtil.getTheDelay());
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (anItem.getDelay() != null && anItem.getDelay() > 0)
|
||||
aMultiUtil.setTheDelay(anItem.getDelay());
|
||||
else
|
||||
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
|
||||
log.debug("pressing button: " + deviceButtons[z].getDevice() + " - "
|
||||
+ deviceButtons[z].getButton() + " with pressTime of: "
|
||||
+ deviceButtons[z].getPressTime() + " - iteration: " + String.valueOf(z) + " - count: "
|
||||
+ String.valueOf(y));
|
||||
if (deviceButtons[z].getHub() == null || deviceButtons[z].getHub().isEmpty())
|
||||
deviceButtons[z].setHub(device.getTargetDevice());
|
||||
HarmonyHandler myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
||||
if (myHarmony == null)
|
||||
log.warn("Button Press - Should not get here, no harmony hub available");
|
||||
else{
|
||||
if (!myHarmony.pressButton(deviceButtons[z])) {
|
||||
if (resetHub(myHarmony)) {
|
||||
myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
||||
if (!myHarmony.pressButton(deviceButtons[z])) {
|
||||
log.error("Could not get communication restored with hub: " + deviceButtons[z].getHub()
|
||||
+ ", please restart...");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Could not communicate with harmony\", \"parameter\": \"/lights/"
|
||||
+ lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (anItem.getDelay() != null && anItem.getDelay() > 0)
|
||||
aMultiUtil.setTheDelay(anItem.getDelay());
|
||||
else
|
||||
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
|
||||
log.debug("pressing button: " + deviceButtons[z].getDevice() + " - " + deviceButtons[z].getButton() + " with pressTime of: " + deviceButtons[z].getPressTime() + " - iteration: " + String.valueOf(z) + " - count: " + String.valueOf(y));
|
||||
if(deviceButtons[z].getHub() == null || deviceButtons[z].getHub().isEmpty())
|
||||
deviceButtons[z].setHub(device.getTargetDevice());
|
||||
HarmonyHandler myHarmony = getHarmonyHandler(deviceButtons[z].getHub());
|
||||
if (myHarmony == null)
|
||||
log.warn("Button Press - Should not get here, no harmony hub available");
|
||||
else
|
||||
myHarmony.pressButton(deviceButtons[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return responseString;
|
||||
@@ -208,15 +279,14 @@ public class HarmonyHome implements Home {
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
|
||||
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||
if(validHarmony || isDevMode) {
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
|
||||
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.")
|
||||
+ (isDevMode ? " DevMode is set." : ""));
|
||||
if (validHarmony || isDevMode) {
|
||||
hubs = new HashMap<String, HarmonyServer>();
|
||||
aGsonHandler =
|
||||
new GsonBuilder()
|
||||
.create();
|
||||
if(isDevMode) {
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
if (isDevMode) {
|
||||
NamedIP devModeIp = new NamedIP();
|
||||
devModeIp.setIp("10.10.10.10");
|
||||
devModeIp.setName("devMode");
|
||||
@@ -226,19 +296,21 @@ public class HarmonyHome implements Home {
|
||||
thedevList.setDevices(theList);
|
||||
bridgeSettings.getBridgeSettingsDescriptor().setHarmonyAddress(thedevList);
|
||||
}
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices().iterator();
|
||||
while(theList.hasNext() && validHarmony) {
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices()
|
||||
.iterator();
|
||||
while (theList.hasNext() && validHarmony) {
|
||||
NamedIP aHub = theList.next();
|
||||
boolean loopControl = true;
|
||||
int retryCount = 0;
|
||||
while(loopControl) {
|
||||
while (loopControl) {
|
||||
try {
|
||||
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings.getBridgeSettingsDescriptor(), isDevMode, aHub));
|
||||
loopControl = false;
|
||||
hubs.put(aHub.getName(), HarmonyServer.setup(isDevMode, aHub));
|
||||
loopControl = false;
|
||||
} catch (Exception e) {
|
||||
if(retryCount > 3) {
|
||||
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
loopControl = false;
|
||||
if (retryCount > 3) {
|
||||
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: "
|
||||
+ e.getMessage(), e);
|
||||
loopControl = false;
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
@@ -246,25 +318,44 @@ 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;
|
||||
@@ -272,7 +363,7 @@ public class HarmonyHome implements Home {
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.apache.http.client.methods.HttpGet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
@@ -50,11 +49,10 @@ public class HarmonyServer {
|
||||
}
|
||||
|
||||
public static HarmonyServer setup(
|
||||
BridgeSettingsDescriptor bridgeSettings,
|
||||
Boolean harmonyDevMode,
|
||||
NamedIP theHarmonyAddress
|
||||
) throws Exception {
|
||||
if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
|
||||
if (harmonyDevMode) {
|
||||
return new HarmonyServer(theHarmonyAddress);
|
||||
}
|
||||
Injector injector = null;
|
||||
@@ -65,11 +63,11 @@ public class HarmonyServer {
|
||||
if (!harmonyDevMode) {
|
||||
injector.injectMembers(mainObject);
|
||||
}
|
||||
mainObject.execute(bridgeSettings, harmonyDevMode);
|
||||
mainObject.execute(harmonyDevMode);
|
||||
return mainObject;
|
||||
}
|
||||
|
||||
private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
|
||||
private void execute(Boolean harmonyDevMode) throws Exception {
|
||||
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||
isDevMode = harmonyDevMode;
|
||||
String modeString = "";
|
||||
@@ -110,7 +108,7 @@ public class HarmonyServer {
|
||||
});
|
||||
harmonyClient.connect(myNameAndIP.getIp());
|
||||
}
|
||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse, myNameAndIP);
|
||||
}
|
||||
|
||||
public HarmonyHandler getMyHarmony() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class HassHome implements Home {
|
||||
|
||||
private Boolean addHassDevices(List<HassDevice> theDeviceList, List<State> theSourceList, String theKey) {
|
||||
if(!validHass)
|
||||
return null;
|
||||
return false;
|
||||
Iterator<State> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
State theDevice = devices.next();
|
||||
@@ -131,14 +131,14 @@ public class HassHome implements Home {
|
||||
log.warn("Should not get here, no HomeAssistant clients configured");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HomeAssistants configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
|
||||
} else {
|
||||
HassCommand hassCommand = null;
|
||||
if(anItem.getItem().isJsonObject())
|
||||
hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class);
|
||||
else
|
||||
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), HassCommand.class);
|
||||
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class);
|
||||
hassCommand.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(),
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
|
||||
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
|
||||
@@ -146,7 +146,7 @@ public class HassHome implements Home {
|
||||
log.warn("Should not get here, no HomeAssistants available");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HiomeAssistant clients available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
log.debug("calling HomeAssistant: " + hassCommand.getHassName() + " - "
|
||||
+ hassCommand.getEntityId() + " - " + hassCommand.getState() + " - " + hassCommand.getBri());
|
||||
|
||||
@@ -16,14 +16,19 @@ import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class HomeAssistant {
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
|
||||
private NamedIP hassAddress;
|
||||
private HTTPHandler anHttpHandler;
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
|
||||
private NamedIP hassAddress;
|
||||
private HTTPHandler anHttpHandler;
|
||||
private HassAuth theAuthType;
|
||||
private NameValue[] headers;
|
||||
|
||||
public HomeAssistant(NamedIP addressName) {
|
||||
super();
|
||||
anHttpHandler = HTTPHome.getHandler();
|
||||
hassAddress = addressName;
|
||||
hassAddress = addressName;
|
||||
theAuthType = null;
|
||||
headers = null;
|
||||
isLegacyAuth();
|
||||
}
|
||||
|
||||
public NamedIP getHassAddress() {
|
||||
@@ -35,42 +40,30 @@ public class HomeAssistant {
|
||||
}
|
||||
|
||||
public Boolean callCommand(HassCommand aCommand) {
|
||||
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - "
|
||||
+ aCommand.getEntityId() + " - " + aCommand.getState() + " - " + aCommand.getBri());
|
||||
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - " + aCommand.getEntityId() + " - "
|
||||
+ aCommand.getState() + " - " + aCommand.getBri());
|
||||
String aUrl = null;
|
||||
if(hassAddress.getSecure() != null && hassAddress.getSecure())
|
||||
aUrl = "https";
|
||||
else
|
||||
aUrl = "http";
|
||||
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
|
||||
aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
|
||||
if(domain.equals("group"))
|
||||
aUrl = hassAddress.getHttpPreamble() + "/api/services/";
|
||||
if (domain.equals("group"))
|
||||
aUrl = aUrl + "homeassistant";
|
||||
else
|
||||
aUrl = aUrl + domain;
|
||||
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
|
||||
NameValue[] headers = null;
|
||||
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
||||
NameValue password = new NameValue();
|
||||
password.setName("x-ha-access");
|
||||
password.setValue(hassAddress.getPassword());
|
||||
headers = new NameValue[1];
|
||||
headers[0] = password;
|
||||
}
|
||||
if(aCommand.getState().equalsIgnoreCase("on")) {
|
||||
headers = getAuthHeader();
|
||||
if (aCommand.getState().equalsIgnoreCase("on")) {
|
||||
aUrl = aUrl + "/turn_on";
|
||||
if(aCommand.getBri() != null)
|
||||
if (aCommand.getBri() != null)
|
||||
aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}";
|
||||
else
|
||||
aBody = aBody + "}";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
aUrl = aUrl + "/turn_off";
|
||||
aBody = aBody + "}";
|
||||
aBody = aBody + "}";
|
||||
}
|
||||
log.debug("Calling HomeAssistant with url: " + aUrl);
|
||||
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
|
||||
log.debug("call Command return is: <" + theData + ">");
|
||||
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
|
||||
log.debug("call Command return is: <" + theData + ">");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -78,39 +71,62 @@ public class HomeAssistant {
|
||||
List<State> theDeviceStates = null;
|
||||
State[] theHassStates;
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
NameValue[] headers = null;
|
||||
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
||||
NameValue password = new NameValue();
|
||||
password.setName("x-ha-access");
|
||||
password.setValue(hassAddress.getPassword());
|
||||
headers = new NameValue[1];
|
||||
headers[0] = password;
|
||||
}
|
||||
if(hassAddress.getSecure() != null && hassAddress.getSecure())
|
||||
String theData;
|
||||
headers = getAuthHeader();
|
||||
if (hassAddress.getSecure() != null && hassAddress.getSecure())
|
||||
theUrl = "https";
|
||||
else
|
||||
theUrl = "http";
|
||||
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
|
||||
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||
if(theData != null) {
|
||||
log.debug("GET Hass States - data: " + theData);
|
||||
theHassStates = new Gson().fromJson(theData, State[].class);
|
||||
if(theHassStates == null) {
|
||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " as response is not parsable.");
|
||||
}
|
||||
else {
|
||||
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
|
||||
}
|
||||
}
|
||||
else
|
||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
|
||||
theUrl = theUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states";
|
||||
theData = anHttpHandler.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||
if (theData != null) {
|
||||
log.debug("GET Hass States - data: " + theData);
|
||||
theHassStates = new Gson().fromJson(theData, State[].class);
|
||||
if (theHassStates == null) {
|
||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName()
|
||||
+ " as response is not parsable.");
|
||||
} else {
|
||||
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
|
||||
}
|
||||
} else
|
||||
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
|
||||
return theDeviceStates;
|
||||
}
|
||||
|
||||
|
||||
protected void closeClient() {
|
||||
anHttpHandler.closeHandler();
|
||||
anHttpHandler = null;
|
||||
}
|
||||
|
||||
private boolean isLegacyAuth() {
|
||||
if (theAuthType == null) {
|
||||
try {
|
||||
theAuthType = new Gson().fromJson(hassAddress.getExtensions(), HassAuth.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not read hass auth - continuing with defaults.");
|
||||
theAuthType = new HassAuth();
|
||||
theAuthType.setLegacyauth(false);
|
||||
}
|
||||
}
|
||||
return theAuthType.isLegacyauth();
|
||||
}
|
||||
|
||||
private NameValue[] getAuthHeader() {
|
||||
if (headers == null) {
|
||||
if (hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
|
||||
headers = new NameValue[1];
|
||||
headers[0] = new NameValue();
|
||||
if (isLegacyAuth()) {
|
||||
headers[0].setName("x-ha-access");
|
||||
headers[0].setValue(hassAddress.getPassword());
|
||||
} else {
|
||||
headers[0].setName("Authorization");
|
||||
headers[0].setValue("Bearer " + hassAddress.getPassword());
|
||||
}
|
||||
}
|
||||
} else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) {
|
||||
headers = null;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,20 +49,20 @@ public class HomeWizardHome implements Home {
|
||||
log.warn("Should not get here, no HomeWizard smart plug available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
|
||||
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.HOMEWIZARD_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
|
||||
log.debug("Executing HUE api request to change activity to HomeWizard smart plug: " + anItem.getItem().toString());
|
||||
String jsonToPost = anItem.getItem().toString();
|
||||
String jsonToPost = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
log.debug("Executing HUE api request to change activity to HomeWizard smart plug: {}", jsonToPost);
|
||||
|
||||
HomeWizzardSmartPlugInfo homeWizzardHandler = getHomeWizzardHandler(device.getTargetDevice());
|
||||
if(homeWizzardHandler == null) {
|
||||
log.warn("Should not get here, no HomeWizard smart plug configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no HomeWizard smart plug configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
try {
|
||||
homeWizzardHandler.execApply(jsonToPost);
|
||||
@@ -70,7 +70,7 @@ public class HomeWizardHome implements Home {
|
||||
|
||||
log.warn("Error posting request to HomeWizard smart plug");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error posting request to HomeWizard smart plug\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
+ "\",\"description\": \"Error posting request to HomeWizard smart plug\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -46,7 +44,7 @@ public class HomeWizzardSmartPlugInfo {
|
||||
|
||||
super();
|
||||
|
||||
cloudAuth = "Basic " + new String(Base64.encodeBase64((gateway.getUsername() + ":" + DigestUtils.sha1Hex(gateway.getPassword())).getBytes()));
|
||||
cloudAuth = "Basic " + gateway.getUserPass64();
|
||||
cloudPlugName = name;
|
||||
gson = new Gson();
|
||||
}
|
||||
|
||||
@@ -18,42 +18,52 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
|
||||
public class HTTPHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
|
||||
private String callType;
|
||||
|
||||
|
||||
public HTTPHandler() {
|
||||
super();
|
||||
callType = null;
|
||||
}
|
||||
|
||||
|
||||
public HTTPHandler(String type) {
|
||||
super();
|
||||
callType = type;
|
||||
}
|
||||
|
||||
|
||||
// This function executes the url from the device repository against the
|
||||
// target as http or https as defined
|
||||
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
|
||||
log.debug("doHttpRequest with url <<<" + url + ">>>, 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() + ">>>");
|
||||
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) {
|
||||
@@ -90,7 +100,11 @@ public class HTTPHandler {
|
||||
CloseableHttpResponse response = null;
|
||||
for (int retryCount = 0; retryCount < 2; retryCount++) {
|
||||
try {
|
||||
response = HttpClientPool.getClient().execute(request);
|
||||
if (usingSSL) {
|
||||
response = HttpClientPool.getSSLClient().execute(request);
|
||||
} else {
|
||||
response = HttpClientPool.getClient().execute(request);
|
||||
}
|
||||
log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: "
|
||||
+ response.getStatusLine().getStatusCode());
|
||||
if (response != null && response.getEntity() != null) {
|
||||
@@ -106,22 +120,27 @@ public class HTTPHandler {
|
||||
// ignore
|
||||
// content
|
||||
} catch (Exception e) {
|
||||
log.debug("Error ocurred in handling response entity after successful call, still responding success. "
|
||||
+ e.getMessage(), e);
|
||||
log.debug(
|
||||
"Error ocurred in handling response entity after successful call, still responding success. "
|
||||
+ e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
|
||||
if(theContent == null)
|
||||
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 (callType != null && callType == DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex] && response.getStatusLine().getStatusCode() == 302) {
|
||||
if(theContent == null)
|
||||
} 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: "
|
||||
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...");
|
||||
@@ -130,15 +149,15 @@ public class HTTPHandler {
|
||||
} 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());
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage(), e);
|
||||
retryCount = 2;
|
||||
}
|
||||
|
||||
if(retryCount < 2) {
|
||||
if (retryCount < 2) {
|
||||
theContent = null;
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
@@ -149,11 +168,40 @@ public class HTTPHandler {
|
||||
}
|
||||
return theContent;
|
||||
}
|
||||
|
||||
public NameValue[] addBasicAuthHeader(NameValue[] theHeaders, NamedIP theTarget) {
|
||||
NameValue[] headers = null;
|
||||
int index = 0;
|
||||
String encodedLogin = theTarget.getUserPass64();
|
||||
if (encodedLogin != null && !encodedLogin.trim().isEmpty()) {
|
||||
if (theHeaders != null && theHeaders.length > 0) {
|
||||
headers = new NameValue[theHeaders.length + 1];
|
||||
for(int i = 0; i < theHeaders.length; i++) {
|
||||
headers[i] = theHeaders[i];
|
||||
}
|
||||
index = theHeaders.length;
|
||||
} else {
|
||||
headers = new NameValue[1];
|
||||
}
|
||||
|
||||
log.debug("creating login for {} with username {} password len {}", theTarget.getName(),
|
||||
theTarget.getUsername(), theTarget.getPassword().length());
|
||||
headers[index] = new NameValue();
|
||||
headers[index].setName("Authorization");
|
||||
// log.debug("Encoded login info {}", encodedLogin);
|
||||
headers[index].setValue("Basic " + encodedLogin);
|
||||
} else {
|
||||
headers = theHeaders;
|
||||
}
|
||||
|
||||
return headers;
|
||||
|
||||
}
|
||||
|
||||
public void setCallType(String callType) {
|
||||
this.callType = callType;
|
||||
}
|
||||
|
||||
|
||||
public void closeHandler() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class HTTPHome implements Home {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
String responseString = null;
|
||||
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
|
||||
//Backwards Compatibility Items
|
||||
if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
|
||||
@@ -86,7 +86,7 @@ public class HTTPHome implements Home {
|
||||
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)
|
||||
@@ -95,7 +95,7 @@ public class HTTPHome implements Home {
|
||||
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;
|
||||
|
||||
@@ -4,10 +4,22 @@ import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -31,9 +43,7 @@ public final class HttpClientPool {
|
||||
// Increase default max connection per route to 20
|
||||
cm.setDefaultMaxPerRoute(20);
|
||||
// Build the client.
|
||||
threadSafeClient = HttpClients.custom()
|
||||
.setConnectionManager(cm)
|
||||
.build();
|
||||
threadSafeClient = HttpClients.custom().setConnectionManager(cm).build();
|
||||
// Start up an eviction thread.
|
||||
monitor = new IdleConnectionMonitorThread(cm);
|
||||
// Don't stop quitting.
|
||||
@@ -47,11 +57,67 @@ public final class HttpClientPool {
|
||||
|
||||
}
|
||||
|
||||
// Single-element enum to implement Singleton.
|
||||
private static enum SingletonSSL {
|
||||
// Just one of me so constructor will be called once.
|
||||
SSLClient;
|
||||
// The thread-safe client.
|
||||
private CloseableHttpClient threadSafeClient;
|
||||
// The pool monitor.
|
||||
private IdleConnectionMonitorThread monitor = null;
|
||||
private TrustStrategy acceptingTrustStrategy = null;
|
||||
private SSLContext sslContext = null;
|
||||
private SSLConnectionSocketFactory sslsf = null;
|
||||
private Registry<ConnectionSocketFactory> socketFactoryRegistry = null;
|
||||
private NoopHostnameVerifier hostnameVerifier = null;
|
||||
|
||||
// The constructor creates it - thus late
|
||||
private SingletonSSL() {
|
||||
try {
|
||||
acceptingTrustStrategy = (cert, authType) -> true;
|
||||
hostnameVerifier = new NoopHostnameVerifier();
|
||||
sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
|
||||
sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
|
||||
HttpClientPool.log.info("Instantiated SSL components.");
|
||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", new PlainConnectionSocketFactory())
|
||||
.register("https", sslsf)
|
||||
.build();
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
// Increase max total connection to 200
|
||||
cm.setMaxTotal(200);
|
||||
// Increase default max connection per route to 20
|
||||
cm.setDefaultMaxPerRoute(20);
|
||||
|
||||
// Build the client.
|
||||
threadSafeClient = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(cm).build();
|
||||
// Start up an eviction thread.
|
||||
monitor = new IdleConnectionMonitorThread(cm);
|
||||
// Don't stop quitting.
|
||||
monitor.setDaemon(true);
|
||||
monitor.start();
|
||||
} catch (Exception e) {
|
||||
HttpClientPool.log.warn("SingletonSSL failed on SSL init");
|
||||
threadSafeClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
public CloseableHttpClient get() {
|
||||
return threadSafeClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static CloseableHttpClient getClient() {
|
||||
// The thread safe client is held by the singleton.
|
||||
return Singleton.Client.get();
|
||||
}
|
||||
|
||||
public static CloseableHttpClient getSSLClient() {
|
||||
// The thread safe client is held by the singleton.
|
||||
return SingletonSSL.SSLClient.get();
|
||||
}
|
||||
|
||||
// Watches for stale connections and evicts them.
|
||||
private static class IdleConnectionMonitorThread extends Thread {
|
||||
// The manager to watch.
|
||||
@@ -123,6 +189,7 @@ public final class HttpClientPool {
|
||||
public static void shutdown() throws InterruptedException, IOException {
|
||||
// Shutdown the monitor.
|
||||
Singleton.Client.monitor.shutdown();
|
||||
SingletonSSL.SSLClient.monitor.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class HttpTestHandler extends HTTPHandler {
|
||||
}
|
||||
else {
|
||||
for(NameValue aTest:this.theData) {
|
||||
if(aTest.getName().equals(compareValue));
|
||||
if(aTest.getName().equals(compareValue))
|
||||
aTest.setValue(testData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class HueHome implements Home {
|
||||
if(anItem.getItem().isJsonObject())
|
||||
deviceId = aGsonHandler.fromJson(anItem.getItem(), HueDeviceIdentifier.class);
|
||||
else
|
||||
deviceId = aGsonHandler.fromJson(anItem.getItem().getAsString(), HueDeviceIdentifier.class);
|
||||
deviceId = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HueDeviceIdentifier.class);
|
||||
if(deviceId.getHueName() == null || deviceId.getHueName().isEmpty())
|
||||
deviceId.setHueName(device.getTargetDevice());
|
||||
|
||||
|
||||
@@ -159,10 +159,10 @@ public class HueInfo {
|
||||
log.warn("Error on calling Hue passthru to change device state: " + deviceId.getHueName());
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error on calling HUE to change device state\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else if (responseString.contains("[{\"error\":")) {
|
||||
if(responseString.contains("unauthorized user")) {
|
||||
}
|
||||
// if(responseString.contains("unauthorized user")) {
|
||||
// }
|
||||
log.warn("Error occurred when calling Hue Passthru: " + responseString);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -144,20 +144,20 @@ public class LifxHome implements Home {
|
||||
log.warn("Should not get here, no LifxDevice clients configured");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
|
||||
} else {
|
||||
LifxEntry lifxCommand = null;
|
||||
if(anItem.getItem().isJsonObject())
|
||||
lifxCommand = aGsonHandler.fromJson(anItem.getItem(), LifxEntry.class);
|
||||
else
|
||||
lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), LifxEntry.class);
|
||||
lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), LifxEntry.class);
|
||||
LifxDevice theDevice = getLifxDevice(lifxCommand.getName());
|
||||
if (theDevice == null) {
|
||||
log.warn("Should not get here, no LifxDevices available");
|
||||
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no Lifx clients available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
log.debug("calling LifxDevice: " + lifxCommand.getName());
|
||||
if(theDevice.getType().equals(LifxDevice.LIGHT_TYPE)) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
|
||||
public class Actions {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
|
||||
public class Events {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class JWT {
|
||||
|
||||
@SerializedName("jwt")
|
||||
@Expose
|
||||
private String jwt;
|
||||
|
||||
public String getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
|
||||
public void setJwt(String jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Level {
|
||||
|
||||
@SerializedName("title")
|
||||
@Expose
|
||||
private String title;
|
||||
@SerializedName("type")
|
||||
@Expose
|
||||
private String type;
|
||||
@SerializedName("@type")
|
||||
@Expose
|
||||
private String attype;
|
||||
@SerializedName("unit")
|
||||
@Expose
|
||||
private String unit;
|
||||
@SerializedName("minimum")
|
||||
@Expose
|
||||
private Integer minimum;
|
||||
@SerializedName("maximum")
|
||||
@Expose
|
||||
private Integer maximum;
|
||||
@SerializedName("links")
|
||||
@Expose
|
||||
private List<Link> links = null;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getAttype() {
|
||||
return attype;
|
||||
}
|
||||
|
||||
public void setAttype(String attype) {
|
||||
this.attype = attype;
|
||||
}
|
||||
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public void setUnit(String unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public Integer getMinimum() {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
public void setMinimum(Integer minimum) {
|
||||
this.minimum = minimum;
|
||||
}
|
||||
|
||||
public Integer getMaximum() {
|
||||
return maximum;
|
||||
}
|
||||
|
||||
public void setMaximum(Integer maximum) {
|
||||
this.maximum = maximum;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Link {
|
||||
|
||||
@SerializedName("rel")
|
||||
@Expose
|
||||
private String rel;
|
||||
@SerializedName("href")
|
||||
@Expose
|
||||
private String href;
|
||||
@SerializedName("mediaType")
|
||||
@Expose
|
||||
private String mediaType;
|
||||
|
||||
public String getRel() {
|
||||
return rel;
|
||||
}
|
||||
|
||||
public void setRel(String rel) {
|
||||
this.rel = rel;
|
||||
}
|
||||
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
public String getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public void setMediaType(String mediaType) {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class MozIotCommand {
|
||||
@SerializedName("url")
|
||||
@Expose
|
||||
private String url;
|
||||
@SerializedName("command")
|
||||
@Expose
|
||||
private MozIotCommandDetail command;
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
public MozIotCommandDetail getCommand() {
|
||||
return command;
|
||||
}
|
||||
public void setCommand(MozIotCommandDetail command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class MozIotCommandDetail {
|
||||
@SerializedName("on")
|
||||
@Expose
|
||||
private boolean on;
|
||||
@SerializedName("level")
|
||||
@Expose
|
||||
private String level;
|
||||
@SerializedName("color")
|
||||
@Expose
|
||||
private String color;
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(boolean on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
String theBody = "";
|
||||
|
||||
if(level != null && !"".equals(level)) {
|
||||
theBody = "{\"level\":" + level + "}";
|
||||
}
|
||||
else if(color != null && !"".equals(color)) {
|
||||
theBody = "{\"color\":\"" + color + "\"}";
|
||||
} else {
|
||||
theBody = "{\"on\":" + on + "}";
|
||||
}
|
||||
return theBody;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class MozIotDevice {
|
||||
@SerializedName("gatewayName")
|
||||
@Expose
|
||||
private String gatewayName;
|
||||
@SerializedName("deviceDetail")
|
||||
@Expose
|
||||
private MozillaThing deviceDetail;
|
||||
|
||||
public String getGatewayName() {
|
||||
return gatewayName;
|
||||
}
|
||||
|
||||
public void setGatewayName(String gatewayName) {
|
||||
this.gatewayName = gatewayName;
|
||||
}
|
||||
|
||||
public MozillaThing getDeviceDetail() {
|
||||
return deviceDetail;
|
||||
}
|
||||
|
||||
public void setDeviceDetail(MozillaThing deviceDetail) {
|
||||
this.deviceDetail = deviceDetail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.ColorData;
|
||||
import com.bwssystems.HABridge.hue.ColorDecode;
|
||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHome;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class MozIotHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(MozIotHome.class);
|
||||
private Map<String, MozIotInstance> moziotMap;
|
||||
private Boolean validMoziot;
|
||||
private HTTPHandler httpClient;
|
||||
private boolean closed;
|
||||
|
||||
public MozIotHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
closed = true;
|
||||
createHome(bridgeSettings);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
String responseString = null;
|
||||
|
||||
if (theUrl != null && !theUrl.isEmpty()) {
|
||||
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl, intensity, targetBri, targetBriInc,
|
||||
false);
|
||||
if (colorData != null) {
|
||||
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||
}
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
anUrl = BrightnessDecode.calculateReplaceIntensityValue(anUrl, intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
anUrl = ColorDecode.replaceColorData(anUrl, colorData,
|
||||
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
|
||||
}
|
||||
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
|
||||
anUrl = TimeDecode.replaceTimeValue(anUrl);
|
||||
|
||||
MozIotCommand theCommand = null;
|
||||
try {
|
||||
theUrl = theUrl.replaceAll("^\"|\"$", "");
|
||||
theCommand = new Gson().fromJson(anUrl, MozIotCommand.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot parse command to Mozilla IOT <<<" + theUrl + ">>>", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
return responseString;
|
||||
}
|
||||
|
||||
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().indexOf("/things/") + 8);
|
||||
String devicePortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
String theUrlCommand = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||
MozIotInstance theHandler = moziotMap.get(device.getTargetDevice());
|
||||
if (theHandler != null) {
|
||||
try {
|
||||
boolean success = theHandler.callCommand(devicePortion, theUrlCommand, theCommand.getCommand(), httpClient);
|
||||
if (!success) {
|
||||
log.warn("Comand had error to Mozilla IOT");
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null,
|
||||
null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot send comand to Mozilla IOT", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn("Mozilla IOT Call could not complete, no address found: " + theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
} else {
|
||||
log.warn(
|
||||
"Mozilla IOT Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: "
|
||||
+ theUrl);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/" + lightId + "/state", null, null)
|
||||
.getTheErrors(), HueError[].class);
|
||||
}
|
||||
return responseString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
|
||||
if (!validMoziot)
|
||||
return null;
|
||||
log.debug("consolidating devices for Mozilla IOT");
|
||||
List<MozillaThing> theResponse = null;
|
||||
Iterator<String> keys = moziotMap.keySet().iterator();
|
||||
List<MozIotDevice> deviceList = new ArrayList<MozIotDevice>();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
theResponse = moziotMap.get(key).getDevices(httpClient);
|
||||
if (theResponse != null)
|
||||
addMozIotDevices(deviceList, theResponse, key);
|
||||
else {
|
||||
log.warn("Cannot get devices for Mozilla IOT with name: " + key + ", skipping this Mozilla IOT.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private Boolean addMozIotDevices(List<MozIotDevice> theDeviceList, List<MozillaThing> theSourceList,
|
||||
String theKey) {
|
||||
Iterator<MozillaThing> things = theSourceList.iterator();
|
||||
while (things.hasNext()) {
|
||||
MozillaThing theThing = things.next();
|
||||
MozIotDevice theDevice = new MozIotDevice();
|
||||
theDevice.setDeviceDetail(theThing);
|
||||
theDevice.setGatewayName(theKey);
|
||||
theDeviceList.add(theDevice);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
moziotMap = null;
|
||||
validMoziot = bridgeSettings.getBridgeSettingsDescriptor().isValidMozIot();
|
||||
log.info("Mozilla IOT Home created." + (validMoziot ? "" : " No Mozilla IOTs configured."));
|
||||
if (validMoziot) {
|
||||
moziotMap = new HashMap<String, MozIotInstance>();
|
||||
httpClient = HTTPHome.getHandler();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getMoziotaddress().getDevices()
|
||||
.iterator();
|
||||
while (theList.hasNext() && validMoziot) {
|
||||
NamedIP aMoziot = theList.next();
|
||||
try {
|
||||
moziotMap.put(aMoziot.getName(), new MozIotInstance(aMoziot, httpClient));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get Mozilla IOT (" + aMoziot.getName() + ") setup, Exiting with message: "
|
||||
+ e.getMessage(), e);
|
||||
validMoziot = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
if (!closed && validMoziot) {
|
||||
log.debug("Home is already closed....");
|
||||
return;
|
||||
}
|
||||
|
||||
if (httpClient != null)
|
||||
httpClient.closeHandler();
|
||||
|
||||
moziotMap = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MozIotInstance {
|
||||
private static final Logger log = LoggerFactory.getLogger(MozIotInstance.class);
|
||||
private JWT moziotToken;
|
||||
private NamedIP mozIotIP;
|
||||
private NameValue[] headers;
|
||||
private HTTPHandler anHttpClient;
|
||||
|
||||
public MozIotInstance(NamedIP theNamedIp, HTTPHandler httpClient) {
|
||||
mozIotIP = theNamedIp;
|
||||
headers = null;
|
||||
moziotToken = null;
|
||||
anHttpClient = httpClient;
|
||||
gatewayLogin();
|
||||
}
|
||||
|
||||
public Boolean callCommand(String deviceId, String aCommand, MozIotCommandDetail commandData,
|
||||
HTTPHandler httpClient) {
|
||||
log.debug("calling Mozilla IOT: {}:{}{}{}", mozIotIP.getIp(), mozIotIP.getPort(), aCommand,
|
||||
commandData.getBody());
|
||||
String aUrl = null;
|
||||
|
||||
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
|
||||
aUrl = "https://";
|
||||
else
|
||||
aUrl = "http://";
|
||||
headers = getAuthHeader();
|
||||
|
||||
aUrl = aUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/things/" + deviceId + "/" + aCommand;
|
||||
String theData = httpClient.doHttpRequest(aUrl, HttpPut.METHOD_NAME, "application/json", commandData.getBody(),
|
||||
headers);
|
||||
log.debug("call Command return is: <<<{}>>>", theData);
|
||||
if (theData.contains("error") || theData.contains("ERROR") || theData.contains("Error"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<MozillaThing> getDevices(HTTPHandler httpClient) {
|
||||
log.debug("calling Mozilla IOT: " + mozIotIP.getIp() + ":" + mozIotIP.getPort());
|
||||
List<MozillaThing> deviceList = null;
|
||||
MozillaThing[] theThings;
|
||||
String theUrl = null;
|
||||
String theData;
|
||||
|
||||
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
|
||||
theUrl = "https://";
|
||||
else
|
||||
theUrl = "http://";
|
||||
headers = getAuthHeader();
|
||||
|
||||
theUrl = theUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/things";
|
||||
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
|
||||
if (theData != null) {
|
||||
log.debug("GET Mozilla IOT Devices - data: " + theData);
|
||||
try {
|
||||
theThings = new Gson().fromJson(theData, MozillaThing[].class);
|
||||
if (theThings != null && theThings.length > 0) {
|
||||
deviceList = new ArrayList<MozillaThing>();
|
||||
for (int i = 0; i < theThings.length; i++) {
|
||||
deviceList.add(theThings[i]);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot get an devices for Mozilla IOT {} Gson Parse Error.", mozIotIP.getName());
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
private NameValue[] getAuthHeader() {
|
||||
if (moziotToken == null)
|
||||
gatewayLogin();
|
||||
|
||||
if (headers == null && moziotToken != null) {
|
||||
headers = new NameValue[3];
|
||||
headers[0] = new NameValue();
|
||||
headers[0].setName("Authorization");
|
||||
headers[0].setValue("Bearer " + moziotToken.getJwt());
|
||||
headers[1] = new NameValue();
|
||||
headers[1].setName("Content-Type");
|
||||
headers[1].setValue("application/json");
|
||||
headers[2] = new NameValue();
|
||||
headers[2].setName("Accept");
|
||||
headers[2].setValue("application/json");
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
private void gatewayLogin() {
|
||||
String aUrl = null;
|
||||
|
||||
moziotToken = null;
|
||||
if (mozIotIP.getSecure() != null && mozIotIP.getSecure())
|
||||
aUrl = "https://";
|
||||
else
|
||||
aUrl = "http://";
|
||||
|
||||
headers = new NameValue[2];
|
||||
headers[0] = new NameValue();
|
||||
headers[0].setName("Content-Type");
|
||||
headers[0].setValue("application/json");
|
||||
headers[1] = new NameValue();
|
||||
headers[1].setName("Accept");
|
||||
headers[1].setValue("application/json");
|
||||
aUrl = aUrl + mozIotIP.getIp() + ":" + mozIotIP.getPort() + "/login";
|
||||
log.debug("gateway login URL: {}", aUrl);
|
||||
String commandData = "{\"email\": \"" + mozIotIP.getUsername() + "\", \"password\":\"" + mozIotIP.getPassword()
|
||||
+ "\"}";
|
||||
log.debug("The login body: {}", commandData);
|
||||
String theData = anHttpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", commandData,
|
||||
headers);
|
||||
if (theData != null) {
|
||||
log.debug("GET Mozilla login - data: {}", theData);
|
||||
try {
|
||||
moziotToken = new Gson().fromJson(theData, JWT.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Cannot get login for Mozilla IOT {} Gson Parse Error.", mozIotIP.getName());
|
||||
moziotToken = null;
|
||||
}
|
||||
} else {
|
||||
log.warn("Could not login {} error: <<<{}>>>", mozIotIP.getName(), theData);
|
||||
}
|
||||
|
||||
headers = null;
|
||||
}
|
||||
|
||||
public NamedIP getMozIotIP() {
|
||||
return mozIotIP;
|
||||
}
|
||||
|
||||
public void setMozIotIP(NamedIP mozIotIP) {
|
||||
this.mozIotIP = mozIotIP;
|
||||
}
|
||||
|
||||
protected void closeClient() {
|
||||
}
|
||||
|
||||
public JWT getMoziotToken() {
|
||||
return moziotToken;
|
||||
}
|
||||
|
||||
public void setMoziotToken(JWT moziotToken) {
|
||||
this.moziotToken = moziotToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class MozillaThing {
|
||||
|
||||
@SerializedName("title")
|
||||
@Expose
|
||||
private String title;
|
||||
@SerializedName("type")
|
||||
@Expose
|
||||
private String type;
|
||||
@SerializedName("@context")
|
||||
@Expose
|
||||
private String atcontext;
|
||||
@SerializedName("@type")
|
||||
@Expose
|
||||
private List<String> attype = null;
|
||||
@SerializedName("description")
|
||||
@Expose
|
||||
private String description;
|
||||
@SerializedName("href")
|
||||
@Expose
|
||||
private String href;
|
||||
@SerializedName("properties")
|
||||
@Expose
|
||||
private Properties properties;
|
||||
@SerializedName("actions")
|
||||
@Expose
|
||||
private Actions actions;
|
||||
@SerializedName("events")
|
||||
@Expose
|
||||
private Events events;
|
||||
@SerializedName("links")
|
||||
@Expose
|
||||
private List<Link> links = null;
|
||||
@SerializedName("layoutIndex")
|
||||
@Expose
|
||||
private Integer layoutIndex;
|
||||
@SerializedName("selectedCapability")
|
||||
@Expose
|
||||
private String selectedCapability;
|
||||
@SerializedName("iconHref")
|
||||
@Expose
|
||||
private Object iconHref;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getAtcontext() {
|
||||
return atcontext;
|
||||
}
|
||||
|
||||
public void setAtcontext(String atcontext) {
|
||||
this.atcontext = atcontext;
|
||||
}
|
||||
|
||||
public List<String> getAttype() {
|
||||
return attype;
|
||||
}
|
||||
|
||||
public void setAttype(List<String> attype) {
|
||||
this.attype = attype;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public Actions getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void setActions(Actions actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
public Events getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public void setEvents(Events events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
public Integer getLayoutIndex() {
|
||||
return layoutIndex;
|
||||
}
|
||||
|
||||
public void setLayoutIndex(Integer layoutIndex) {
|
||||
this.layoutIndex = layoutIndex;
|
||||
}
|
||||
|
||||
public String getSelectedCapability() {
|
||||
return selectedCapability;
|
||||
}
|
||||
|
||||
public void setSelectedCapability(String selectedCapability) {
|
||||
this.selectedCapability = selectedCapability;
|
||||
}
|
||||
|
||||
public Object getIconHref() {
|
||||
return iconHref;
|
||||
}
|
||||
|
||||
public void setIconHref(Object iconHref) {
|
||||
this.iconHref = iconHref;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
}
|
||||
55
src/main/java/com/bwssystems/HABridge/plugins/moziot/On.java
Normal file
55
src/main/java/com/bwssystems/HABridge/plugins/moziot/On.java
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class On {
|
||||
|
||||
@SerializedName("title")
|
||||
@Expose
|
||||
private String title;
|
||||
@SerializedName("type")
|
||||
@Expose
|
||||
private String type;
|
||||
@SerializedName("attype")
|
||||
@Expose
|
||||
private String attype;
|
||||
@SerializedName("links")
|
||||
@Expose
|
||||
private List<Link> links = null;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getAttype() {
|
||||
return attype;
|
||||
}
|
||||
|
||||
public void setAttype(String attype) {
|
||||
this.attype = attype;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
package com.bwssystems.HABridge.plugins.moziot;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Properties {
|
||||
|
||||
@SerializedName("on")
|
||||
@Expose
|
||||
private On on;
|
||||
@SerializedName("level")
|
||||
@Expose
|
||||
private Level level;
|
||||
|
||||
public On getOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(On on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(Level level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class MQTTHome implements Home {
|
||||
mqttObject = aGsonHandler.toJson(anItem.getItem());
|
||||
}
|
||||
else
|
||||
mqttObject =anItem.getItem().getAsString();
|
||||
mqttObject = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
mqttObject = BrightnessDecode.calculateReplaceIntensityValue(mqttObject,
|
||||
intensity, targetBri, targetBriInc, false);
|
||||
mqttObject = DeviceDataDecode.replaceDeviceData(mqttObject, device);
|
||||
@@ -128,7 +128,7 @@ public class MQTTHome implements Home {
|
||||
log.warn("Should not get here, no mqtt brokers configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no mqtt brokers configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
|
||||
}
|
||||
return responseString;
|
||||
|
||||
@@ -51,12 +51,15 @@ public class OpenHABHome implements Home {
|
||||
if(theUrl != null && !theUrl.isEmpty()) {
|
||||
OpenHABCommand theCommand = null;
|
||||
try {
|
||||
theCommand = new Gson().fromJson(theUrl, OpenHABCommand.class);
|
||||
if(anItem.getItem().isJsonObject())
|
||||
theCommand = new Gson().fromJson(anItem.getItem(), OpenHABCommand.class);
|
||||
else
|
||||
theCommand = new Gson().fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), OpenHABCommand.class);
|
||||
} catch(Exception e) {
|
||||
log.warn("Cannot parse command to OpenHAB <<<" + theUrl + ">>>", e);
|
||||
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
|
||||
"Error on calling url to change device state", "/lights/"
|
||||
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
|
||||
+ lightId + "/state", null, null).getTheErrors(), HueError[].class);
|
||||
return responseString;
|
||||
}
|
||||
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().indexOf("://") + 3);
|
||||
|
||||
@@ -33,16 +33,13 @@ public class OpenHABInstance {
|
||||
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
|
||||
log.debug("calling OpenHAB: " + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + aCommand);
|
||||
String aUrl = null;
|
||||
NameValue[] headers = null;
|
||||
if(theOpenHAB.getSecure() != null && theOpenHAB.getSecure())
|
||||
aUrl = "https://";
|
||||
else
|
||||
aUrl = "http://";
|
||||
if(theOpenHAB.getUsername() != null && !theOpenHAB.getUsername().isEmpty() && theOpenHAB.getPassword() != null && !theOpenHAB.getPassword().isEmpty()) {
|
||||
aUrl = aUrl + theOpenHAB.getUsername() + ":" + theOpenHAB.getPassword() + "@";
|
||||
}
|
||||
|
||||
aUrl = aUrl + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + "/" + aCommand;
|
||||
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", commandData, headers);
|
||||
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", commandData, httpClient.addBasicAuthHeader(null, theOpenHAB));
|
||||
log.debug("call Command return is: <" + theData + ">");
|
||||
if(theData.contains("error") || theData.contains("ERROR") || theData.contains("Error"))
|
||||
return false;
|
||||
|
||||
@@ -72,26 +72,26 @@ public class SomfyHome implements Home {
|
||||
log.warn("Should not get here, no somfy hub available");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no somfy hub available\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
if (anItem.getType() != null && anItem.getType().trim().equalsIgnoreCase(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
|
||||
log.debug("executing HUE api request to change activity to Somfy: " + anItem.getItem().toString());
|
||||
String jsonToPost = anItem.getItem().toString();
|
||||
String jsonToPost = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
log.debug("executing HUE api request to change activity to Somfy: {}", jsonToPost);
|
||||
|
||||
SomfyInfo somfyHandler = getSomfyHandler(device.getTargetDevice());
|
||||
if(somfyHandler == null) {
|
||||
log.warn("Should not get here, no Somfy configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Should not get here, no somfy configured\", \"parameter\": \"/lights/"
|
||||
+ lightId + "state\"}}]";
|
||||
+ lightId + "/state\"}}]";
|
||||
} else {
|
||||
try {
|
||||
somfyHandler.execApply(jsonToPost);
|
||||
} catch (Exception e) {
|
||||
log.warn("Error posting request to Somfy");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error posting request to SomfyTahoma\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
+ "\",\"description\": \"Error posting request to SomfyTahoma\", \"parameter\": \"/lights/" + lightId + "/state\"}}]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public class SomfyHome implements Home {
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validSomfy = bridgeSettings.getBridgeSettingsDescriptor().isValidSomfy();
|
||||
log.info("Somfy Home created." + (validSomfy ? "" : " No Somfys configured."));
|
||||
log.info("Somfy Home created. {}", (validSomfy ? "" : " No Somfys configured."));
|
||||
if(validSomfy) {
|
||||
somfys = new HashMap<>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getSomfyAddress().getDevices().iterator();
|
||||
|
||||
@@ -74,8 +74,8 @@ public class SomfyInfo {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
urlEncodedFormEntity.writeTo(bos);
|
||||
String body = bos.toString();
|
||||
String response = httpClient.doHttpRequest(BASE_URL + "json/login",HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
|
||||
log.debug("Somfy login response <<<" + response + ">>>");
|
||||
String response = httpClient.doHttpRequest(BASE_URL + "json/login", HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
|
||||
log.debug("Somfy login response <<<{}>>>", response);
|
||||
}
|
||||
|
||||
private NameValue[] getHttpHeaders() {
|
||||
@@ -89,16 +89,16 @@ public class SomfyInfo {
|
||||
NameValue[] httpHeader = getHttpHeaders();
|
||||
log.info("Making SOMFY http setup call");
|
||||
String response = httpClient.doHttpRequest(BASE_URL + "json/getSetup", HttpGet.METHOD_NAME, "", "", httpHeader );
|
||||
log.debug("Somfy getSetup response <<<" + response + ">>>");
|
||||
log.debug("Somfy getSetup response <<<{}>>>", response);
|
||||
GetSetup setupData = new Gson().fromJson(response, GetSetup.class);
|
||||
return setupData;
|
||||
}
|
||||
|
||||
public void execApply(String jsonToPost) throws Exception {
|
||||
login(namedIP.getUsername(), namedIP.getPassword());
|
||||
log.info("Making SOMFY http exec call");
|
||||
log.info("Making SOMFY http exec call with json: {}", jsonToPost);
|
||||
String response = httpClient.doHttpRequest(BASE_URL_ENDUSER + "exec/apply", HttpPost.METHOD_NAME, "application/json;charset=UTF-8", jsonToPost, getHttpHeaders());
|
||||
log.debug("Somfy exec reply response <<<" + response + ">>>");
|
||||
log.debug("Somfy exec reply response <<<{}>>>", response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -48,7 +48,7 @@ public class TCPHome implements Home {
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
Socket dataSendSocket = null;
|
||||
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.contains("tcp://")) {
|
||||
if(!theUrl.startsWith("{\"tcpDevice\""))
|
||||
@@ -92,7 +92,7 @@ public class TCPHome implements Home {
|
||||
if (colorData != null) {
|
||||
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||
}
|
||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||
sendData = HexLibrary.decodeHexString(theUrlBody.substring(2));
|
||||
} else {
|
||||
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
|
||||
if (colorData != null) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import com.bwssystems.HABridge.util.HexLibrary;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -40,7 +40,7 @@ public class UDPHome implements Home {
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
log.debug("executing HUE api request to UDP: " + anItem.getItem().getAsString());
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
String theUrl = anItem.getItem().getAsString().replaceAll("^\"|\"$", "");
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("udp://")) {
|
||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
@@ -68,7 +68,7 @@ public class UDPHome implements Home {
|
||||
if (colorData != null) {
|
||||
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
|
||||
}
|
||||
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||
sendData = HexLibrary.decodeHexString(theUrlBody.substring(2));
|
||||
} else {
|
||||
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
|
||||
|
||||
|
||||
@@ -4,105 +4,133 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeControlDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Configuration;
|
||||
import com.bwssystems.HABridge.api.hue.HueConstants;
|
||||
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||
import com.bwssystems.HABridge.util.AddressUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
// import java.time.Instant;
|
||||
// import java.time.temporal.ChronoUnit;
|
||||
import java.util.Enumeration;
|
||||
import org.apache.http.conn.util.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.http.conn.util.*;
|
||||
import javax.jmdns.JmDNS;
|
||||
import javax.jmdns.ServiceInfo;
|
||||
|
||||
public class UpnpListener {
|
||||
private Logger log = LoggerFactory.getLogger(UpnpListener.class);
|
||||
private UDPDatagramSender theUDPDatagramSender;
|
||||
private MulticastSocket upnpMulticastSocket;
|
||||
private int httpServerPort;
|
||||
private String responseAddress;
|
||||
private boolean strict;
|
||||
private String upnpConfigIP;
|
||||
// private boolean strict;
|
||||
private boolean upnpOriginal;
|
||||
private boolean upnpAdvanced;
|
||||
private boolean traceupnp;
|
||||
private boolean useUpnpIface;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private String bridgeId;
|
||||
private String bridgeSNUUID;
|
||||
private String httpType;
|
||||
private HuePublicConfig aHueConfig;
|
||||
private Integer theUpnpSendDelay;
|
||||
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
|
||||
"HOST: %s:%s\r\n" +
|
||||
"CACHE-CONTROL: max-age=100\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
|
||||
"hue-bridgeid: %s\r\n" +
|
||||
"ST: upnp:rootdevice\r\n" +
|
||||
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
|
||||
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" +
|
||||
"HOST: %s:%s\r\n" +
|
||||
"CACHE-CONTROL: max-age=100\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
|
||||
"hue-bridgeid: %s\r\n" +
|
||||
"ST: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" +
|
||||
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" +
|
||||
"HOST: %s:%s\r\n" +
|
||||
"CACHE-CONTROL: max-age=100\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
|
||||
"hue-bridgeid: %s\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
|
||||
private String notifyTemplate = "NOTIFY * HTTP/1.1\r\n" +
|
||||
"HOST: %s:%s\r\n" +
|
||||
"CACHE-CONTROL: max-age=100\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
|
||||
"NTS: ssdp:alive\r\n" +
|
||||
"hue-bridgeid: %s\r\n" +
|
||||
"NT: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" +
|
||||
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
/* This is the minimum response needed, all others are for the advanced setting */
|
||||
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n"
|
||||
+ "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
|
||||
/* These next 2 templates are for the advanced upnp option */
|
||||
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: uuid:" + HueConstants.UUID_PREFIX
|
||||
+ "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:"
|
||||
+ HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
|
||||
|
||||
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) throws IOException {
|
||||
|
||||
/* These notify templates are for the advanced upnp option */
|
||||
private String notifyTemplate1 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + "NT: uuid:"
|
||||
+ HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
|
||||
private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
|
||||
+ "NT: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
|
||||
|
||||
private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
|
||||
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
|
||||
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
|
||||
+ "NT: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
|
||||
|
||||
public UpnpListener(BridgeSettings theSettings, BridgeControlDescriptor theControl,
|
||||
UDPDatagramSender aUdpDatagramSender) throws IOException {
|
||||
super();
|
||||
theUDPDatagramSender = aUdpDatagramSender;
|
||||
upnpMulticastSocket = null;
|
||||
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
||||
responseAddress = theSettings.getUpnpConfigAddress();
|
||||
strict = theSettings.isUpnpStrict();
|
||||
traceupnp = theSettings.isTraceupnp();
|
||||
useUpnpIface = theSettings.isUseupnpiface();
|
||||
theUpnpSendDelay = theSettings.getUpnpsenddelay();
|
||||
httpServerPort = Integer.valueOf(theSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
upnpConfigIP = theSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress();
|
||||
// strict = theSettings.isUpnpStrict();
|
||||
upnpOriginal = theSettings.getBridgeSettingsDescriptor().isUpnporiginal();
|
||||
upnpAdvanced = theSettings.getBridgeSettingsDescriptor().isUpnpadvanced();
|
||||
traceupnp = theSettings.getBridgeSettingsDescriptor().isTraceupnp();
|
||||
useUpnpIface = theSettings.getBridgeSettingsDescriptor().isUseupnpiface();
|
||||
theUpnpSendDelay = theSettings.getBridgeSettingsDescriptor().getUpnpsenddelay();
|
||||
bridgeControl = theControl;
|
||||
aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION, theSettings.getHubmac());
|
||||
aHueConfig = HuePublicConfig.createConfig("temp", upnpConfigIP, HueConstants.HUB_VERSION,
|
||||
theSettings.getBridgeSettingsDescriptor().getHubmac());
|
||||
bridgeId = aHueConfig.getBridgeid();
|
||||
bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
|
||||
try {
|
||||
upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
|
||||
} catch(IOException e){
|
||||
log.error("Upnp Discovery Port is in use, or restricted by admin (try running with sudo or admin privs): " + Configuration.UPNP_DISCOVERY_PORT + " with message: " + e.getMessage());
|
||||
throw(e);
|
||||
if (theSettings.getBridgeSecurity().isUseHttps()) {
|
||||
httpType = "https";
|
||||
} else {
|
||||
httpType = "http";
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// This commented out code does not work... leave for review
|
||||
// if (useUpnpIface)
|
||||
// upnpMulticastSocket = new MulticastSocket(
|
||||
// new InetSocketAddress(upnpConfigIP, Configuration.UPNP_DISCOVERY_PORT));
|
||||
// else
|
||||
upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
|
||||
} catch (IOException e) {
|
||||
log.error("Upnp Discovery Port is in use, or restricted by admin (try running with sudo or admin privs): "
|
||||
+ Configuration.UPNP_DISCOVERY_PORT + " with message: " + e.getMessage());
|
||||
throw (e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean startListening(){
|
||||
public boolean startListening() {
|
||||
if (bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||
log.warn("UPNP Listener exiting as reinit or stop requested....");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("UPNP Discovery Listener starting....");
|
||||
Enumeration<NetworkInterface> ifs = null;
|
||||
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT);
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT);
|
||||
try {
|
||||
ifs = NetworkInterface.getNetworkInterfaces();
|
||||
} catch (SocketException e) {
|
||||
ifs = NetworkInterface.getNetworkInterfaces();
|
||||
} catch (SocketException e) {
|
||||
log.error("Could not get network interfaces for this machine: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
InetAddress theUpnpAddress = null;
|
||||
while (ifs.hasMoreElements()) {
|
||||
NetworkInterface xface = ifs.nextElement();
|
||||
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
||||
@@ -113,16 +141,20 @@ public class UpnpListener {
|
||||
InetAddress addr = addrs.nextElement();
|
||||
log.debug(name + " ... has addr " + addr);
|
||||
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
||||
if(!useUpnpIface) {
|
||||
if(traceupnp)
|
||||
if (!useUpnpIface) {
|
||||
if (traceupnp)
|
||||
log.info("Traceupnp: Interface: " + name + " valid usable IP address: " + addr);
|
||||
IPsPerNic++;
|
||||
}
|
||||
else if(addr.getHostAddress().equals(responseAddress)) {
|
||||
if(traceupnp)
|
||||
log.info("Traceupnp: Interface: " + name + " matches upnp config address of IP address: " + addr);
|
||||
} else if (useUpnpIface && (addr.getHostAddress().equals(upnpConfigIP) || name.equals("lo"))) {
|
||||
if (traceupnp)
|
||||
log.info("Traceupnp: Interface: " + name + " matches upnp config address of IP address: "
|
||||
+ addr);
|
||||
IPsPerNic++;
|
||||
}
|
||||
|
||||
if (addr.getHostAddress().equals(upnpConfigIP)) {
|
||||
theUpnpAddress = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("Checking " + name + " to our interface set");
|
||||
@@ -140,16 +172,44 @@ public class UpnpListener {
|
||||
}
|
||||
}
|
||||
|
||||
JmDNS jmdns = null;
|
||||
if (theUpnpAddress != null) {
|
||||
log.info("Create and run mDNS service.");
|
||||
try {
|
||||
// Create a JmDNS instance
|
||||
jmdns = JmDNS.create(theUpnpAddress, "Philips-hue");
|
||||
|
||||
// Register a service - Defined TXT keys: bridgeid, modelid
|
||||
final HashMap<String, String> values = new HashMap<String, String>();
|
||||
values.put("modelid", HueConstants.MODEL_ID);
|
||||
values.put("bridgeid", bridgeId);
|
||||
ServiceInfo serviceInfo = ServiceInfo.create("_hue._tcp.local.",
|
||||
"Philips Hue - " + bridgeId.substring(bridgeId.length() - 6), httpServerPort, 0, 0, values);
|
||||
jmdns.registerService(serviceInfo);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not start mDNS service for hue api. {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||
log.warn("UPNP Listener exiting as reinit or stop requested....");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("UPNP Discovery Listener running and ready....");
|
||||
boolean loopControl = true;
|
||||
boolean error = false;
|
||||
try {
|
||||
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
|
||||
} catch (SocketException e1) {
|
||||
log.warn("Could not sent soTimeout on multi-cast socket");
|
||||
|
||||
if(upnpAdvanced) {
|
||||
try {
|
||||
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
|
||||
} catch (SocketException e1) {
|
||||
log.warn("Could not sent soTimeout on multi-cast socket");
|
||||
}
|
||||
}
|
||||
Instant current, previous;
|
||||
previous = Instant.now();
|
||||
// Instant current, previous;
|
||||
// previous = Instant.now();
|
||||
while (loopControl) { // trigger shutdown here
|
||||
byte[] buf = new byte[1024];
|
||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||
@@ -157,21 +217,32 @@ public class UpnpListener {
|
||||
upnpMulticastSocket.receive(packet);
|
||||
if (isSSDPDiscovery(packet)) {
|
||||
try {
|
||||
sendUpnpResponse(packet.getAddress(), packet.getPort());
|
||||
} catch (IOException e) {
|
||||
log.warn("UpnpListener encountered an error sending upnp response packet. IP: " + packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
|
||||
sendUpnpResponse(packet);
|
||||
} catch (Exception e) {
|
||||
log.warn("UpnpListener encountered an error sending upnp response packet. IP: "
|
||||
+ packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
|
||||
log.debug("UpnpListener send upnp exception: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
current = Instant.now();
|
||||
if(ChronoUnit.MILLIS.between(previous, current) > Configuration.UPNP_NOTIFY_TIMEOUT) {
|
||||
sendUpnpNotify(socketAddress.getAddress());
|
||||
previous = Instant.now();
|
||||
}
|
||||
|
||||
/*
|
||||
* current = Instant.now(); if (ChronoUnit.MILLIS.between(previous, current) >
|
||||
* Configuration.UPNP_NOTIFY_TIMEOUT) { try {
|
||||
* sendUpnpNotify(socketAddress.getAddress()); } catch (IOException e) { log.
|
||||
* warn("UpnpListener encountered an error sending upnp notify packets. IP: " +
|
||||
* packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
|
||||
* log.debug("UpnpListener send upnp notify exception: ", e); } previous =
|
||||
* Instant.now();
|
||||
*
|
||||
* }
|
||||
*/
|
||||
} catch (SocketTimeoutException e) {
|
||||
sendUpnpNotify(socketAddress.getAddress());
|
||||
try {
|
||||
sendUpnpNotify(socketAddress.getAddress());
|
||||
} catch (IOException en) {
|
||||
log.warn("UpnpListener encountered an error sending upnp notify packets. IP: "
|
||||
+ packet.getAddress().getHostAddress() + " with message: " + en.getMessage());
|
||||
log.debug("UpnpListener send upnp notify exception: ", en);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("UpnpListener encountered an error reading socket. Shutting down", e);
|
||||
error = true;
|
||||
@@ -186,6 +257,10 @@ public class UpnpListener {
|
||||
}
|
||||
}
|
||||
upnpMulticastSocket.close();
|
||||
if (jmdns != null) {
|
||||
// Unregister all services
|
||||
jmdns.unregisterAllServices();
|
||||
}
|
||||
if (bridgeControl.isReinit())
|
||||
log.info("UPNP Discovery Listener - ended, restart found");
|
||||
if (bridgeControl.isStop())
|
||||
@@ -200,97 +275,158 @@ public class UpnpListener {
|
||||
/**
|
||||
* ssdp discovery packet detection
|
||||
*/
|
||||
protected boolean isSSDPDiscovery(DatagramPacket packet){
|
||||
//Only respond to discover request for strict upnp form
|
||||
protected boolean isSSDPDiscovery(DatagramPacket packet) {
|
||||
// Only respond to discover request for strict upnp form
|
||||
String packetString = new String(packet.getData(), 0, packet.getLength());
|
||||
if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")){
|
||||
if(strict && (packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") || packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all")))
|
||||
{
|
||||
if(traceupnp) {
|
||||
log.info("Traceupnp: SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
||||
}
|
||||
else
|
||||
log.debug("SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: <<<" + packetString + ">>>");
|
||||
// log.info("Packet string <<<" + packetString + ">>>");
|
||||
if (packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1")
|
||||
&& packetString.contains("\"ssdp:discover\"")) {
|
||||
if ((packetString.contains("ST: urn:schemas-upnp-org:device:basic:1")
|
||||
|| packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all"))) {
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":"
|
||||
+ packet.getPort());
|
||||
} else
|
||||
log.debug("SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":"
|
||||
+ packet.getPort() + ", body: <<<" + packetString + ">>>");
|
||||
return true;
|
||||
}
|
||||
else if (!strict)
|
||||
{
|
||||
if(traceupnp) {
|
||||
log.info("Traceupnp: SSDP M-SEARCH packet (!strict) from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
||||
}
|
||||
else
|
||||
log.debug("SSDP M-SEARCH packet (!strict) from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: <<<" + packetString + ">>>");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// log.debug("isSSDPDiscovery found message to not be valid - strict: " + strict);
|
||||
// log.debug("SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||
} /*
|
||||
* else if (!strict) { if(traceupnp) {
|
||||
* log.info("Traceupnp: SSDP M-SEARCH packet (!strict) from " +
|
||||
* packet.getAddress().getHostAddress() + ":" + packet.getPort()); } else
|
||||
* log.debug("SSDP M-SEARCH packet (!strict) from " +
|
||||
* packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: <<<"
|
||||
* + packetString + ">>>"); return true; }
|
||||
*/
|
||||
} else {
|
||||
// log.debug("isSSDPDiscovery found message to not be valid - strict: " +
|
||||
// strict);
|
||||
log.debug("SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: "
|
||||
+ packetString);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
|
||||
protected void sendUpnpResponse(DatagramPacket aPacket) throws IOException {
|
||||
// SocketAddress requesterAddress = aPacket.getSocketAddress();
|
||||
InetAddress requester = aPacket.getAddress();
|
||||
int sourcePort = aPacket.getPort();
|
||||
String discoveryResponse = null;
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
String httpLocationAddress = null;
|
||||
if (useUpnpIface) {
|
||||
httpLocationAddress = upnpConfigIP;
|
||||
} else {
|
||||
// refactored suggestion by https://github.com/pvint
|
||||
httpLocationAddress = AddressUtil.getOutboundAddress(requester.getHostAddress(), sourcePort).getHostAddress();
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if(traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 1 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
|
||||
}
|
||||
else
|
||||
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
|
||||
if(traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 2 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
|
||||
|
||||
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 1 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
|
||||
}
|
||||
else
|
||||
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
|
||||
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
|
||||
+ " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
if(upnpAdvanced) {
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
|
||||
bridgeSNUUID, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
|
||||
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
|
||||
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if(traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 3 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
|
||||
}
|
||||
else
|
||||
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
}
|
||||
|
||||
private void sendUDPResponse(byte[] udpMessage, InetAddress requester, int sourcePort) throws IOException {
|
||||
log.debug("Sending response string: <<<" + new String(udpMessage) + ">>>");
|
||||
if(upnpMulticastSocket == null)
|
||||
throw new IOException("Socket not initialized");
|
||||
DatagramPacket response = new DatagramPacket(udpMessage, udpMessage.length, requester, sourcePort);
|
||||
upnpMulticastSocket.send(response);
|
||||
if (upnpOriginal) {
|
||||
theUDPDatagramSender.sendUDPResponse(udpMessage, requester, sourcePort);
|
||||
} else {
|
||||
if (upnpMulticastSocket == null)
|
||||
throw new IOException("Socket not initialized");
|
||||
DatagramPacket response = new DatagramPacket(udpMessage, udpMessage.length, requester, sourcePort);
|
||||
upnpMulticastSocket.send(response);
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendUpnpNotify(InetAddress aSocketAddress) {
|
||||
|
||||
protected void sendUpnpNotify(InetAddress aSocketAddress) throws IOException {
|
||||
String notifyData = null;
|
||||
notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
|
||||
log.debug("sendUpnpNotify notifyTemplate is <<<" + notifyData + ">>>");
|
||||
DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
try {
|
||||
upnpMulticastSocket.send(notifyPacket);
|
||||
} catch (IOException e1) {
|
||||
log.warn("UpnpListener encountered an error sending upnp notify packet. IP: " + notifyPacket.getAddress().getHostAddress() + " with message: " + e1.getMessage());
|
||||
log.debug("UpnpListener send upnp notify exception: ", e1);
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate1");
|
||||
}
|
||||
log.debug("sendUpnpNotify notifyTemplate1 is <<<{}>>>", notifyData);
|
||||
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate2");
|
||||
}
|
||||
log.debug("sendUpnpNotify notifyTemplate2 is <<<{}>>>", notifyData);
|
||||
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate3");
|
||||
}
|
||||
log.debug("sendUpnpNotify notifyTemplate3 is <<<{}>>>", notifyData);
|
||||
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.api.hue.HueConstants;
|
||||
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||
import com.bwssystems.HABridge.util.AddressUtil;
|
||||
|
||||
import static spark.Spark.get;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class UpnpSettingsResource {
|
||||
private BridgeSettingsDescriptor theSettings;
|
||||
private BridgeSettings bridgeSettings;
|
||||
|
||||
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||
private String hueTemplate_pre = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||
+ "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
|
||||
+ "<specVersion>\n"
|
||||
+ "<major>1</major>\n"
|
||||
@@ -36,8 +37,9 @@ public class UpnpSettingsResource {
|
||||
+ "<modelNumber>" + HueConstants.MODEL_ID + "</modelNumber>\n"
|
||||
+ "<modelURL>http://www.meethue.com</modelURL>\n"
|
||||
+ "<serialNumber>%s</serialNumber>\n"
|
||||
+ "<UDN>uuid:" + HueConstants.UUID_PREFIX + "%s</UDN>\n"
|
||||
+ "<presentationURL>index.html</presentationURL>\n"
|
||||
+ "<UDN>uuid:" + HueConstants.UUID_PREFIX + "%s</UDN>\n";
|
||||
|
||||
private String hueTemplate_post = "<presentationURL>index.html</presentationURL>\n"
|
||||
+ "<iconList>\n"
|
||||
+ "<icon>\n"
|
||||
+ "<mimetype>image/png</mimetype>\n"
|
||||
@@ -53,9 +55,22 @@ public class UpnpSettingsResource {
|
||||
+ "<depth>24</depth>\n"
|
||||
+ "<url>hue_logo_3.png</url>\n"
|
||||
+ "</icon>\n"
|
||||
+ "</iconList>\n"
|
||||
+ "</device>\n"
|
||||
+ "</root>\n";
|
||||
+ "</iconList>\n";
|
||||
|
||||
private String hueTemplate_end = "</device>\n"
|
||||
+ "</root>\n";
|
||||
|
||||
/* not utilizing this section any more
|
||||
private String hueTemplate_mid_orig = "<serviceList>\n"
|
||||
+ "<service>\n"
|
||||
+ "<serviceType>(null)</serviceType>\n"
|
||||
+ "<serviceId>(null)</serviceId>\n"
|
||||
+ "<controlURL>(null)</controlURL>\n"
|
||||
+ "<eventSubURL>(null)</eventSubURL>\n"
|
||||
+ "<SCPDURL>(null)</SCPDURL>\n"
|
||||
+ "</service>\n"
|
||||
+ "</serviceList>\n";
|
||||
*/
|
||||
|
||||
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
|
||||
super();
|
||||
@@ -75,12 +90,36 @@ public class UpnpSettingsResource {
|
||||
|
||||
String portNumber = Integer.toString(request.port());
|
||||
String filledTemplate = null;
|
||||
String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress(), HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac();
|
||||
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac);
|
||||
String httpLocationAddr = null;
|
||||
String hueTemplate = null;
|
||||
if(theSettings.isUpnporiginal()) {
|
||||
httpLocationAddr = theSettings.getUpnpConfigAddress();
|
||||
hueTemplate = hueTemplate_pre + hueTemplate_end;
|
||||
} else if(!theSettings.isUpnpadvanced()) {
|
||||
if(theSettings.isUseupnpiface()) {
|
||||
httpLocationAddr = theSettings.getUpnpConfigAddress();
|
||||
} else {
|
||||
log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port());
|
||||
httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress();
|
||||
}
|
||||
hueTemplate = hueTemplate_pre + hueTemplate_end;
|
||||
} else {
|
||||
|
||||
if(theSettings.isUseupnpiface()) {
|
||||
httpLocationAddr = theSettings.getUpnpConfigAddress();
|
||||
} else {
|
||||
log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port());
|
||||
httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress();
|
||||
}
|
||||
hueTemplate = hueTemplate_pre + hueTemplate_post + hueTemplate_end;
|
||||
}
|
||||
|
||||
String bridgeIdMac = HuePublicConfig.createConfig("temp", httpLocationAddr, HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac();
|
||||
filledTemplate = String.format(hueTemplate, httpLocationAddr, portNumber, httpLocationAddr, bridgeIdMac, bridgeIdMac);
|
||||
if(theSettings.isTraceupnp())
|
||||
log.info("Traceupnp: request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + theSettings.getUpnpConfigAddress() + ":" + portNumber);
|
||||
log.info("Traceupnp: request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + httpLocationAddr + ":" + portNumber);
|
||||
else
|
||||
log.debug("request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + theSettings.getUpnpConfigAddress() + ":" + portNumber);
|
||||
log.debug("request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + httpLocationAddr + ":" + portNumber);
|
||||
// response.header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
|
||||
// response.header("Pragma", "no-cache");
|
||||
// response.header("Expires", "Mon, 1 Aug 2011 09:00:00 GMT");
|
||||
|
||||
62
src/main/java/com/bwssystems/HABridge/util/AddressUtil.java
Normal file
62
src/main/java/com/bwssystems/HABridge/util/AddressUtil.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
import java.net.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AddressUtil {
|
||||
final static Logger log = LoggerFactory.getLogger(AddressUtil.class);
|
||||
|
||||
// added by https://github.com/pvint
|
||||
// Ruthlessly stolen from
|
||||
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
|
||||
// Try to get a source IP that makes sense for the requester to contact for use
|
||||
// in the LOCATION header in replies
|
||||
public static InetAddress getOutboundAddress(String remoteAddress, int remotePort) {
|
||||
InetAddress localAddress = null;
|
||||
log.debug("Entering getOutboundAddress with args.");
|
||||
try {
|
||||
localAddress = getOutboundAddress(new InetSocketAddress(remoteAddress, remotePort));
|
||||
} catch (Exception e) {
|
||||
log.debug("getOutboundAddress(SocketAddress) Threw an Exception: " + e.getMessage());
|
||||
ParseRoute theRoute = ParseRoute.getInstance();
|
||||
try {
|
||||
localAddress = InetAddress.getByName(theRoute.getLocalIPAddress());
|
||||
log.warn("Error <" + e.getMessage() + "> on determining interface to reply for <" + remoteAddress
|
||||
+ ">. Using default route IP Address of " + localAddress.getHostAddress());
|
||||
} catch (Exception e1) {
|
||||
log.error("Cannot find address for parsed local ip address: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if(localAddress != null)
|
||||
log.debug("localAddress is IP Address of " + localAddress.getHostAddress());
|
||||
else
|
||||
log.debug("localAddress returning NULL");
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
// added by https://github.com/pvint
|
||||
// Ruthlessly stolen from
|
||||
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
|
||||
// Try to get a source IP that makes sense for the requestor to contact for use
|
||||
// in the LOCATION header in replies
|
||||
public static InetAddress getOutboundAddress(SocketAddress remoteAddress) throws SocketException {
|
||||
DatagramSocket sock = new DatagramSocket();
|
||||
// connect is needed to bind the socket and retrieve the local address
|
||||
// later (it would return 0.0.0.0 otherwise)
|
||||
log.debug("Entering getOutboundAddress with socket arg.");
|
||||
sock.connect(remoteAddress);
|
||||
log.debug("getOutboundAddress(SocketAddress) getLocalAddress.");
|
||||
final InetAddress localAddress = sock.getLocalAddress();
|
||||
sock.disconnect();
|
||||
sock.close();
|
||||
sock = null;
|
||||
if(localAddress != null)
|
||||
log.debug("getOutbountAddress(SocketAddress) returning IP Address of " + localAddress.getHostAddress());
|
||||
else
|
||||
log.debug("getOutboundAddress(SocketAddress) returning NULL");
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -92,4 +93,67 @@ public abstract class BackupHandler {
|
||||
return theFilenames;
|
||||
}
|
||||
|
||||
public String downloadBackup(String aFilename) {
|
||||
Path filePath = FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename);
|
||||
|
||||
String content = null;
|
||||
if (Files.notExists(filePath) || !Files.isReadable(filePath)) {
|
||||
log.warn("Error reading the file: {} - Does not exist or is not readable. continuing...", aFilename);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
content = new String(Files.readAllBytes(filePath));
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading the file: {} message: {}", aFilename, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
public String uploadBackup(String aFilename, String theContent) {
|
||||
String successMessage = null;
|
||||
if(aFilename == null || aFilename.isEmpty()) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
aFilename = defaultName + "upload-" + dateFormat.format(Calendar.getInstance().getTime()) + fileExtension;
|
||||
} else {
|
||||
if(!aFilename.endsWith(fileExtension)) {
|
||||
aFilename = aFilename +fileExtension;
|
||||
}
|
||||
}
|
||||
Path filePath = FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename);
|
||||
|
||||
successMessage = uploadWriter(theContent, filePath);
|
||||
|
||||
return successMessage;
|
||||
}
|
||||
|
||||
private String uploadWriter(String content, Path filePath) {
|
||||
String aMessage = null;
|
||||
if (Files.exists(filePath)) {
|
||||
aMessage = "Error: File exists, cannot write: " + filePath;
|
||||
log.error(aMessage);
|
||||
return aMessage;
|
||||
}
|
||||
|
||||
if (Files.notExists(filePath.getParent())) {
|
||||
try {
|
||||
Files.createDirectories(filePath.getParent());
|
||||
} catch (IOException e) {
|
||||
aMessage = "Error: creating the directory: " + filePath + " message: " + e.getMessage();
|
||||
log.error(aMessage, e);
|
||||
return aMessage;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||
aMessage = "Success: creating file: " + filePath;
|
||||
} catch (IOException e) {
|
||||
aMessage = "Error: writing the file: " + filePath + " message: " + e.getMessage();
|
||||
log.error(aMessage, e);
|
||||
}
|
||||
|
||||
return aMessage;
|
||||
}
|
||||
}
|
||||
|
||||
72
src/main/java/com/bwssystems/HABridge/util/HexLibrary.java
Normal file
72
src/main/java/com/bwssystems/HABridge/util/HexLibrary.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class HexLibrary {
|
||||
|
||||
public static String byteToHex(byte num) {
|
||||
char[] hexDigits = new char[2];
|
||||
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
|
||||
hexDigits[1] = Character.forDigit((num & 0xF), 16);
|
||||
return new String(hexDigits);
|
||||
}
|
||||
|
||||
public static byte hexToByte(String hexString) {
|
||||
int firstDigit = toDigit(hexString.charAt(0));
|
||||
int secondDigit = toDigit(hexString.charAt(1));
|
||||
return (byte) ((firstDigit << 4) + secondDigit);
|
||||
}
|
||||
|
||||
private static int toDigit(char hexChar) {
|
||||
int digit = Character.digit(hexChar, 16);
|
||||
if (digit == -1) {
|
||||
throw new IllegalArgumentException("Invalid Hexadecimal Character: " + hexChar);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
|
||||
public static String encodeHexString(byte[] byteArray) {
|
||||
StringBuffer hexStringBuffer = new StringBuffer();
|
||||
for (int i = 0; i < byteArray.length; i++) {
|
||||
hexStringBuffer.append(byteToHex(byteArray[i]));
|
||||
}
|
||||
return hexStringBuffer.toString();
|
||||
}
|
||||
|
||||
public static byte[] decodeHexString(String hexString) {
|
||||
if (hexString.length() % 2 == 1) {
|
||||
throw new IllegalArgumentException("Invalid hexadecimal String supplied.");
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[hexString.length() / 2];
|
||||
for (int i = 0; i < hexString.length(); i += 2) {
|
||||
bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String encodeUsingBigIntegerStringFormat(byte[] bytes) {
|
||||
BigInteger bigInteger = new BigInteger(1, bytes);
|
||||
return String.format("%0" + (bytes.length << 1) + "x", bigInteger);
|
||||
}
|
||||
|
||||
public static String encodeUsingBigIntegerToString(String intValue) {
|
||||
BigInteger bigInteger = BigInteger.valueOf(Integer.decode(intValue));
|
||||
return bigInteger.toString(16);
|
||||
}
|
||||
|
||||
public static String encodeUsingBigIntegerToString(byte[] bytes) {
|
||||
BigInteger bigInteger = new BigInteger(1, bytes);
|
||||
return bigInteger.toString(16);
|
||||
}
|
||||
|
||||
public static byte[] decodeUsingBigInteger(String hexString) {
|
||||
byte[] byteArray = new BigInteger(hexString, 16).toByteArray();
|
||||
if (byteArray[0] == 0) {
|
||||
byte[] output = new byte[byteArray.length - 1];
|
||||
System.arraycopy(byteArray, 1, output, 0, output.length);
|
||||
return output;
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
165
src/main/java/com/bwssystems/HABridge/util/ParseRoute.java
Normal file
165
src/main/java/com/bwssystems/HABridge/util/ParseRoute.java
Normal file
@@ -0,0 +1,165 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Find out the local IP address and default gateway
|
||||
* @author Henry Zheng
|
||||
* @url http://www.ireasoning.com
|
||||
*/
|
||||
public class ParseRoute
|
||||
{
|
||||
private String _gateway;
|
||||
private String _ip;
|
||||
private static ParseRoute _instance;
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
ParseRoute pr = ParseRoute.getInstance();
|
||||
System.out.println( "Gateway: " + pr.getGateway() );
|
||||
System.out.println( "IP: " + pr.getLocalIPAddress() );
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
System.out.println( e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ParseRoute ()
|
||||
{
|
||||
parse();
|
||||
}
|
||||
|
||||
private static boolean isWindows ()
|
||||
{
|
||||
String os = System.getProperty ( "os.name" ).toUpperCase ();
|
||||
return os.contains( "WINDOWS" ) ;
|
||||
}
|
||||
|
||||
private static boolean isLinux ()
|
||||
{
|
||||
String os = System.getProperty ( "os.name" ).toUpperCase ();
|
||||
return os.contains( "LINUX" ) ;
|
||||
}
|
||||
|
||||
public String getLocalIPAddress()
|
||||
{
|
||||
return _ip;
|
||||
}
|
||||
|
||||
public String getGateway()
|
||||
{
|
||||
return _gateway;
|
||||
}
|
||||
|
||||
public static ParseRoute getInstance()
|
||||
{
|
||||
if(_instance == null)
|
||||
{
|
||||
_instance = new ParseRoute();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private void parse()
|
||||
{
|
||||
if(isWindows())
|
||||
{
|
||||
parseWindows();
|
||||
}
|
||||
else if(isLinux())
|
||||
{
|
||||
parseLinux();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseWindows()
|
||||
{
|
||||
try
|
||||
{
|
||||
Process pro = Runtime.getRuntime().exec("cmd.exe /c route print");
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pro.getInputStream()));
|
||||
|
||||
String line;
|
||||
while((line = bufferedReader.readLine())!=null)
|
||||
{
|
||||
line = line.trim();
|
||||
String [] tokens = Tokenizer.parse(line, ' ', true , true);// line.split(" ");
|
||||
if(tokens.length == 5 && tokens[0].equals("0.0.0.0"))
|
||||
{
|
||||
_gateway = tokens[2];
|
||||
_ip = tokens[3];
|
||||
return;
|
||||
}
|
||||
}
|
||||
//pro.waitFor();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
System.err.println(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLinux()
|
||||
{
|
||||
BufferedReader reader = null;
|
||||
try
|
||||
{
|
||||
reader = new BufferedReader(new FileReader("/proc/net/route"));
|
||||
String line;
|
||||
while((line = reader.readLine())!=null)
|
||||
{
|
||||
line = line.trim();
|
||||
String [] tokens = Tokenizer.parse(line, '\t', true , true);// line.split(" ");
|
||||
if(tokens.length > 1 && tokens[1].equals("00000000"))
|
||||
{
|
||||
String gateway = tokens[2]; //0102A8C0
|
||||
if(gateway.length() == 8)
|
||||
{
|
||||
String[] s4 = new String[4];
|
||||
s4[3] = String.valueOf(Integer.parseInt(gateway.substring(0, 2), 16));
|
||||
s4[2] = String.valueOf(Integer.parseInt(gateway.substring(2, 4), 16));
|
||||
s4[1] = String.valueOf(Integer.parseInt(gateway.substring(4, 6), 16));
|
||||
s4[0] = String.valueOf(Integer.parseInt(gateway.substring(6, 8), 16));
|
||||
_gateway = s4[0] + "." + s4[1] + "." + s4[2] + "." + s4[3];
|
||||
}
|
||||
String iface = tokens[0];
|
||||
NetworkInterface nif = NetworkInterface.getByName(iface);
|
||||
Enumeration<java.net.InetAddress> addrs = nif.getInetAddresses();
|
||||
while(addrs.hasMoreElements())
|
||||
{
|
||||
Object obj = addrs.nextElement();
|
||||
if(obj instanceof Inet4Address)
|
||||
{
|
||||
_ip = obj.toString();
|
||||
if(_ip.startsWith("/")) _ip = _ip.substring(1);
|
||||
reader.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
System.err.println(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if(reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch(Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
195
src/main/java/com/bwssystems/HABridge/util/StringArray.java
Normal file
195
src/main/java/com/bwssystems/HABridge/util/StringArray.java
Normal file
@@ -0,0 +1,195 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* This class is an auto-resizable String array. It has similar methods to ArrayList
|
||||
*
|
||||
* @author Henry Zheng
|
||||
* @url http://www.ireasoning.com
|
||||
*/
|
||||
|
||||
public class StringArray implements Serializable
|
||||
{
|
||||
public static final long serialVersionUID = 42L;
|
||||
public static final int DEFAULT_CAPACITY = 10;
|
||||
|
||||
protected String[] _strings = null;
|
||||
protected int _upperBound = 0;
|
||||
protected int _capacity = DEFAULT_CAPACITY;
|
||||
protected int _initialSize = _capacity;
|
||||
protected float _loadFactory = 1.5F;
|
||||
|
||||
public StringArray ()
|
||||
{
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
public StringArray( int size)
|
||||
{
|
||||
_capacity = size;
|
||||
_initialSize = size;
|
||||
_strings = new String[size];
|
||||
}
|
||||
|
||||
public synchronized void ensureCapacity(int capacity)
|
||||
{
|
||||
if(_capacity < capacity)
|
||||
{
|
||||
_capacity = (_capacity * 3)/2 + 1;
|
||||
if(_capacity < capacity)
|
||||
{
|
||||
_capacity = capacity;
|
||||
}
|
||||
String [] oldData = _strings;
|
||||
_strings = new String[_capacity];
|
||||
System.arraycopy(oldData, 0, _strings, 0, _upperBound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void add(String s)
|
||||
{
|
||||
if(_upperBound == _capacity )
|
||||
{
|
||||
resize((int) (_capacity * _loadFactory));
|
||||
}
|
||||
_strings[_upperBound++] = s;
|
||||
}
|
||||
|
||||
public synchronized void add(StringArray sa)
|
||||
{
|
||||
for (int i = 0; i < sa.size() ; i++)
|
||||
{
|
||||
add(sa.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized String get(int index)
|
||||
{
|
||||
return _strings[index];
|
||||
}
|
||||
|
||||
public synchronized void set(int index, String newVal)
|
||||
{
|
||||
_strings[index] = newVal;
|
||||
}
|
||||
|
||||
/** Adds all elements in passed string array */
|
||||
public synchronized void add(String [] strs)
|
||||
{
|
||||
for (int i = 0; i < strs.length ; i++)
|
||||
{
|
||||
add(strs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets this object. */
|
||||
public synchronized void clear()
|
||||
{
|
||||
_capacity = _initialSize;
|
||||
_strings = new String[_capacity];
|
||||
_upperBound = 0;
|
||||
|
||||
}
|
||||
|
||||
public synchronized String remove(int index)
|
||||
{
|
||||
if(index >= _upperBound )
|
||||
{
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
String s = _strings[index];
|
||||
for (int i = index; i < _upperBound - 1 ; i++)
|
||||
{
|
||||
_strings[i] = _strings[i + 1];
|
||||
}
|
||||
_upperBound --;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first occurance of passed str
|
||||
* @return the string removed, or null if not found
|
||||
*/
|
||||
public synchronized String remove(String str)
|
||||
{
|
||||
for (int i = 0; i < _upperBound ; i++)
|
||||
{
|
||||
if(_strings[i].equals(str))
|
||||
{
|
||||
return remove(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized int size()
|
||||
{
|
||||
return _upperBound;
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty()
|
||||
{
|
||||
return _upperBound == 0;
|
||||
}
|
||||
|
||||
public synchronized String[] toArray()
|
||||
{
|
||||
String [] ret = new String[_upperBound];
|
||||
for (int i = 0; i < _upperBound ; i++)
|
||||
{
|
||||
ret[i] = _strings[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected synchronized void resize(int newCapacity)
|
||||
{
|
||||
String [] as = new String[newCapacity];
|
||||
for (int i = 0; i < _strings.length ; i++)
|
||||
{
|
||||
as[i] = _strings[i];
|
||||
}
|
||||
_strings = as;
|
||||
_capacity = newCapacity;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < _upperBound ; i++)
|
||||
{
|
||||
buf.append(_strings[i] + "\n");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
StringArray as = new StringArray();
|
||||
String [] ss = null;
|
||||
ss = as.toArray();
|
||||
// System.out.println( "ss len="+ss.length);
|
||||
// System.out.println( "ss = " + ss);
|
||||
for (int i = 0; i < 10 ; i++)
|
||||
{
|
||||
as.add("" + i);
|
||||
}
|
||||
// System.out.println( "size = " + as.size());
|
||||
ss = as.toArray();
|
||||
for (int i = 0; i < ss.length ; i++)
|
||||
{
|
||||
// System.out.println( ss[i]);
|
||||
}
|
||||
// System.out.println( "remove 5th element.");
|
||||
as.remove(5);
|
||||
|
||||
// System.out.println( "size = " + as.size());
|
||||
ss = as.toArray();
|
||||
for (int i = 0; i < ss.length ; i++)
|
||||
{
|
||||
// System.out.println( ss[i]);
|
||||
}
|
||||
}
|
||||
}//end of class StringArray
|
||||
175
src/main/java/com/bwssystems/HABridge/util/Tokenizer.java
Normal file
175
src/main/java/com/bwssystems/HABridge/util/Tokenizer.java
Normal file
@@ -0,0 +1,175 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
|
||||
/**
|
||||
* This class perform similar functionality to StringTokenizer class but faster.
|
||||
* The difference is StringTokenizer doesn't count empty token, but this class does.
|
||||
*
|
||||
* @author Henry Zheng
|
||||
* @url http://www.ireasoning.com
|
||||
*/
|
||||
public class Tokenizer
|
||||
{
|
||||
private Tokenizer()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* It's different from the other parse method in that it checks left and right string first, which take higer
|
||||
* priority than the delimiter. For example, if left and right is ", for string a:b:1"c:d"2:3 ,
|
||||
* it returns { a, b, 1"c:d"2, 3 }
|
||||
* @param left the openning tag of higher priority token
|
||||
* @param right the closing tag of higher priority token
|
||||
* @trimEachToken if true, each token will be trim by calling String.trim()
|
||||
*/
|
||||
public static String[] parse(String text, char delimiter, boolean trimEachToken, String left, String right)
|
||||
{
|
||||
if(text == null) return null;
|
||||
StringArray tokens = new StringArray();
|
||||
int pos1 = -1;
|
||||
int pos2 = -1;
|
||||
int firstPos = -1;
|
||||
while(true)
|
||||
{
|
||||
pos2 = text.indexOf(delimiter, firstPos + 1);
|
||||
if(pos2 < 0 )
|
||||
{
|
||||
String str = text.substring(pos1 + 1);
|
||||
if(trimEachToken )
|
||||
{
|
||||
str = str.trim();
|
||||
}
|
||||
tokens.add(str);
|
||||
break;
|
||||
}
|
||||
if(pos2 == pos1 + 1)
|
||||
{
|
||||
tokens.add("");
|
||||
}
|
||||
else
|
||||
{
|
||||
int tagPos1 = text.indexOf(left, firstPos + 1);
|
||||
if(tagPos1 > 0 && tagPos1 < pos2 )
|
||||
{
|
||||
int tagPos2 = text.indexOf(right, tagPos1 + 1);
|
||||
if(tagPos2 > 0)
|
||||
{
|
||||
firstPos = tagPos2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
String str = text.substring(pos1 + 1, pos2);
|
||||
if(trimEachToken )
|
||||
{
|
||||
str = str.trim();
|
||||
}
|
||||
tokens.add(str);
|
||||
}
|
||||
pos1 = pos2;
|
||||
firstPos = pos1;
|
||||
}
|
||||
String[] ret = tokens.toArray();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @trimEachToken if true, each token will be trim by calling String.trim()
|
||||
*/
|
||||
public static String[] parse(String text, char delimiter, boolean trimEachToken)
|
||||
{
|
||||
return parse(text, delimiter, trimEachToken, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @trimEachToken if true, each token will be trim by calling String.trim()
|
||||
*/
|
||||
public static String[] parse(String text, char delimiter, boolean trimEachToken, boolean ignoreEmptyToken)
|
||||
{
|
||||
if(text == null) return null;
|
||||
StringArray tokens = new StringArray();
|
||||
int pos1 = -1;
|
||||
int pos2 = -1;
|
||||
while(true)
|
||||
{
|
||||
pos2 = text.indexOf(delimiter, pos1 + 1);
|
||||
if(pos2 < 0 )
|
||||
{
|
||||
String str = text.substring(pos1 + 1);
|
||||
if(trimEachToken )
|
||||
{
|
||||
str = str.trim();
|
||||
}
|
||||
if(ignoreEmptyToken)
|
||||
{
|
||||
if(str.length() != 0) tokens.add(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
tokens.add(str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(pos2 == pos1 + 1)
|
||||
{
|
||||
if(!ignoreEmptyToken) { tokens.add(""); }
|
||||
}
|
||||
else
|
||||
{
|
||||
String str = text.substring(pos1 + 1, pos2);
|
||||
if(trimEachToken )
|
||||
{
|
||||
str = str.trim();
|
||||
}
|
||||
if(ignoreEmptyToken)
|
||||
{
|
||||
if(str.length() != 0) tokens.add(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
tokens.add(str);
|
||||
}
|
||||
}
|
||||
pos1 = pos2;
|
||||
}
|
||||
String[] ret = tokens.toArray();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not trim each token.
|
||||
* @see #parse(String, char, boolean)
|
||||
*/
|
||||
public static String[] parse(String text, char delimiter)
|
||||
{
|
||||
return parse(text, delimiter, false);
|
||||
}
|
||||
|
||||
// public static void main(String[] args)
|
||||
// {
|
||||
// String str = "1,\"2,\"ab\",ttt1,\"3,,a\"222\",4";
|
||||
// if(args.length > 0)
|
||||
// {
|
||||
// str = args[0];
|
||||
// }
|
||||
// String [] tokens = Tokenizer.parse(str, ',');
|
||||
//
|
||||
//// System.out.println( "Text = (" + str + ")");
|
||||
// // System.out.println( "------------------------------------------");
|
||||
// for (int i = 0; i < tokens.length ; i++)
|
||||
// {
|
||||
// // System.out.println( "(" + tokens[i] + ")");
|
||||
// }
|
||||
// // System.out.println( "------------------------------------------");
|
||||
|
||||
// String [] tokens = Tokenizer.parse(str, ',', new String[]{"("}, new String[]{")"});
|
||||
//
|
||||
// // System.out.println( "Text = [" + str + "]");
|
||||
// // System.out.println( "------------------------------------------");
|
||||
// for (int i = 0; i < tokens.length ; i++)
|
||||
// {
|
||||
// // System.out.println( "[" + tokens[i] + "]");
|
||||
// }
|
||||
// // System.out.println( "------------------------------------------");
|
||||
|
||||
// }
|
||||
}//end of class Tokenizer
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bwssystems.logservices;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.bwssystems.logservices.LoggingUtil.LogLevels;
|
||||
|
||||
/**
|
||||
@@ -7,7 +9,10 @@ import com.bwssystems.logservices.LoggingUtil.LogLevels;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class LoggerInfo {
|
||||
public class LoggerInfo implements Serializable {
|
||||
|
||||
/** serialVersionUID. */
|
||||
private static final long serialVersionUID = 1085935297588739585L;
|
||||
|
||||
private String loggerName;
|
||||
private LogLevels logLevel;
|
||||
|
||||
@@ -60,4 +60,16 @@ legend.form-label {
|
||||
.msg-error {
|
||||
color:#F00;
|
||||
font-size:14px;
|
||||
}
|
||||
}
|
||||
|
||||
.progress {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
border: 3px groove #CCC;
|
||||
}
|
||||
|
||||
.progress div {
|
||||
font-size: smaller;
|
||||
background: greenyellow;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
.scrollArea {
|
||||
height: 100%;
|
||||
/* THis makes the table scroll - disabled as a feature for now
|
||||
max-height: 800px;
|
||||
*/
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #d5d5d5;
|
||||
|
||||
BIN
src/main/resources/public/hue_logo_0.png
Normal file
BIN
src/main/resources/public/hue_logo_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user