mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 08:28:46 +00:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a59747bc9 | ||
|
|
53ec096c95 | ||
|
|
8ccb768391 | ||
|
|
9d84e2a180 | ||
|
|
6a5fae583f | ||
|
|
8d15d0a0fb | ||
|
|
d4b8b70a83 | ||
|
|
a276f97776 | ||
|
|
9438b25538 | ||
|
|
6c15ca2c3b | ||
|
|
39782fa339 | ||
|
|
d7e29e2ee5 | ||
|
|
6b4693eaaf | ||
|
|
7f816b03d5 | ||
|
|
ed3db4427b | ||
|
|
80ca8c3ca3 | ||
|
|
e43473734e | ||
|
|
8a468b8352 | ||
|
|
51ce10cfc7 | ||
|
|
b5f7144c9c | ||
|
|
86a931d383 | ||
|
|
3e890721c5 | ||
|
|
62d1c64a3d | ||
|
|
c025b186cd | ||
|
|
e999c3a969 | ||
|
|
351403e611 | ||
|
|
c773477a43 | ||
|
|
5d1f0ce3b6 | ||
|
|
7e0fd6c21b | ||
|
|
3bf52f5da0 | ||
|
|
bd856d8f9e | ||
|
|
73b2be752e | ||
|
|
dda7a7a34a | ||
|
|
f238e05533 | ||
|
|
aaaebd0c05 | ||
|
|
9a1924422e | ||
|
|
e446c618ce | ||
|
|
60d35acff9 | ||
|
|
c9adab53a9 | ||
|
|
72b6b2027b | ||
|
|
60239bad82 | ||
|
|
aecd589308 | ||
|
|
ee45cee8e3 | ||
|
|
21e5dfb338 | ||
|
|
b73a4cd666 | ||
|
|
05418fdda1 | ||
|
|
a717fd7c68 | ||
|
|
8408d7350e | ||
|
|
3ba8f56db2 | ||
|
|
7a0946e3b7 | ||
|
|
50c9369d71 | ||
|
|
6c2a34f507 | ||
|
|
ee2c105040 | ||
|
|
3ac83912f3 | ||
|
|
e62fcf7765 | ||
|
|
9c3d95f177 | ||
|
|
926a7f50dc | ||
|
|
ad820a68c9 | ||
|
|
73f0f766f7 | ||
|
|
113ce0ca59 | ||
|
|
a5860417c1 | ||
|
|
48af3d84a2 | ||
|
|
8ce0483e54 | ||
|
|
1a2024d92b | ||
|
|
8198919a27 | ||
|
|
614734a2aa | ||
|
|
58fccb1fa7 | ||
|
|
77d3084b01 | ||
|
|
922bb54143 | ||
|
|
8586bbd965 | ||
|
|
d64a028f30 | ||
|
|
fff30d17d6 | ||
|
|
13fa5dea73 | ||
|
|
1d6a4c1432 | ||
|
|
9cb275230e | ||
|
|
c97ab2cd38 | ||
|
|
7b45ca9438 | ||
|
|
e6da9950d6 | ||
|
|
20328b15d8 | ||
|
|
2ff73e5672 | ||
|
|
cca9a6be78 | ||
|
|
5d5b68209a | ||
|
|
d2e906caa3 | ||
|
|
a1708f2a88 | ||
|
|
49c3b85894 | ||
|
|
f9f5a3a878 | ||
|
|
2565183ee9 | ||
|
|
a6bb1ae3aa | ||
|
|
4bc91be88b | ||
|
|
315fd31270 | ||
|
|
09787fe08d | ||
|
|
37d346f558 | ||
|
|
ac59398aa0 | ||
|
|
87073435fc | ||
|
|
8687f3482a | ||
|
|
32a5f26ddd | ||
|
|
c28f07d628 | ||
|
|
d3cc961dfb | ||
|
|
1b3d826f28 | ||
|
|
c8f4d89a45 | ||
|
|
2b335d6b9b | ||
|
|
b27bb5eef8 | ||
|
|
3c54ccd56d | ||
|
|
cf772334c4 | ||
|
|
5a843f7569 | ||
|
|
2a52783bb1 | ||
|
|
195f1854ec | ||
|
|
2e5596a6e4 | ||
|
|
9fc13c6c45 | ||
|
|
4b4d4e36c7 | ||
|
|
1e7bdc560b | ||
|
|
aff0f8d64c | ||
|
|
7a812d6e6b | ||
|
|
26f2105801 | ||
|
|
feef345a3b | ||
|
|
314ae58ebd | ||
|
|
d8b6232ac1 | ||
|
|
41e22ee64d | ||
|
|
be2fbcd4cb | ||
|
|
14e7f37522 | ||
|
|
e3f5946c9d | ||
|
|
12eab16f21 | ||
|
|
3df68047a9 | ||
|
|
0dd652f82a | ||
|
|
53af1a4dfd | ||
|
|
816a0025b1 | ||
|
|
405562809a | ||
|
|
4c87c6fce8 | ||
|
|
2fd0f7748b | ||
|
|
ed5f3b4b3c | ||
|
|
aad09b7527 | ||
|
|
0ae66da085 | ||
|
|
d344b764da | ||
|
|
c85b67fb9f | ||
|
|
a23d662444 | ||
|
|
4b98f799c2 | ||
|
|
acba2b5cae | ||
|
|
4dc818296a | ||
|
|
40123ed858 | ||
|
|
718ba5a5c2 | ||
|
|
2e6944d840 | ||
|
|
e29f12905d | ||
|
|
408b79d5d8 | ||
|
|
bf5ad2e23c | ||
|
|
59f1db285d | ||
|
|
203ed0b5d3 | ||
|
|
b443d16a11 | ||
|
|
295b1e1a30 | ||
|
|
c872f3543d | ||
|
|
23f2d2716d | ||
|
|
7c1d6e40b8 | ||
|
|
c5fbd5d1f0 | ||
|
|
aebde7ee48 | ||
|
|
c8fb93eeb6 | ||
|
|
1602ed004a | ||
|
|
7514e36edb | ||
|
|
2789d8c180 | ||
|
|
af1777aeb3 | ||
|
|
fc2d587e1a | ||
|
|
416b4d3fda | ||
|
|
9666273840 | ||
|
|
774bc8a36b | ||
|
|
74d4548beb | ||
|
|
eecf0f9875 | ||
|
|
ed96b5ad81 | ||
|
|
9f7d3ea331 | ||
|
|
68de92bb74 | ||
|
|
392a46c3d8 | ||
|
|
568569248a | ||
|
|
d61d10b5b6 | ||
|
|
7294dbf175 | ||
|
|
6c99358f95 | ||
|
|
eee0394f20 | ||
|
|
d87f3bc541 | ||
|
|
e38374f749 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@ data
|
|||||||
.idea
|
.idea
|
||||||
/target/
|
/target/
|
||||||
/.settings/
|
/.settings/
|
||||||
|
/start.bat
|
||||||
|
/.classpath
|
||||||
|
|||||||
23
.project
Normal file
23
.project
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?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>
|
||||||
151
pom.xml
151
pom.xml
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>0.3.2</version>
|
<version>3.0.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera, using lightweight frameworks</description>
|
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub or Nest, using lightweight frameworks</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
@@ -17,45 +17,114 @@
|
|||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.bwssytems</groupId>
|
||||||
|
<artifactId>harmony-java-client</artifactId>
|
||||||
|
<version>1.0.8</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.8</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sparkjava</groupId>
|
<groupId>com.sparkjava</groupId>
|
||||||
<artifactId>spark-core</artifactId>
|
<artifactId>spark-core</artifactId>
|
||||||
<version>2.2</version>
|
<version>2.3</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
<version>4.3.6</version>
|
<version>4.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>httpcore</artifactId>
|
||||||
<version>1.7.5</version>
|
<version>4.4.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>log4j-over-slf4j</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>1.7.5</version>
|
<version>1.7.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.1.5</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.2.4</version>
|
<version>2.6.2</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
<version>2.6.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.cedarsoftware</groupId>
|
<groupId>net.java.dev.eval</groupId>
|
||||||
<artifactId>json-io</artifactId>
|
<artifactId>eval</artifactId>
|
||||||
<version>4.1.6</version>
|
<version>0.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject</groupId>
|
||||||
|
<artifactId>guice</artifactId>
|
||||||
|
<version>4.0-beta4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.igniterealtime.smack</groupId>
|
||||||
|
<artifactId>smack-core</artifactId>
|
||||||
|
<version>4.0.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<includes>
|
||||||
|
<include>version.properties</include>
|
||||||
|
</includes>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>version.properties</exclude>
|
||||||
|
</excludes>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@@ -78,24 +147,42 @@
|
|||||||
<exclude>META-INF/*.RSA</exclude>
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
<exclude>META-INF/*.txt</exclude>
|
<exclude>META-INF/*.txt</exclude>
|
||||||
<exclude>META-INF/maven/**</exclude>
|
<exclude>META-INF/maven/**</exclude>
|
||||||
<exclude>META-INF/services/**</exclude>
|
|
||||||
<exclude>META-INF/DEPENDENCIES</exclude>
|
|
||||||
<exclude>about_files/**</exclude>
|
<exclude>about_files/**</exclude>
|
||||||
<exclude>*.properties</exclude>
|
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>org.slf4j:*</artifact>
|
<artifact>*:*</artifact>
|
||||||
<includes>
|
</filter>
|
||||||
<include>**</include>
|
<filter>
|
||||||
</includes>
|
<artifact>org.slf4j:slf4j-api</artifact>
|
||||||
</filter>
|
<includes>
|
||||||
<filter>
|
<include>**</include>
|
||||||
<artifact>commons-logging:commons-logging</artifact>
|
</includes>
|
||||||
<includes>
|
</filter>
|
||||||
<include>**</include>
|
<filter>
|
||||||
</includes>
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
</filter>
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>xpp3:xpp3</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>org.igniterealtime.smack:*</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>com.github.bwssytems:harmony-java-client</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer
|
<transformer
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class BridgeControlDescriptor {
|
||||||
|
private boolean reinit;
|
||||||
|
private boolean stop;
|
||||||
|
|
||||||
|
public BridgeControlDescriptor() {
|
||||||
|
super();
|
||||||
|
this.reinit = false;
|
||||||
|
this.stop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReinit() {
|
||||||
|
return reinit;
|
||||||
|
}
|
||||||
|
public void setReinit(boolean reinit) {
|
||||||
|
this.reinit = reinit;
|
||||||
|
}
|
||||||
|
public boolean isStop() {
|
||||||
|
return stop;
|
||||||
|
}
|
||||||
|
public void setStop(boolean stop) {
|
||||||
|
this.stop = stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +1,245 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
public class BridgeSettings {
|
import java.io.IOException;
|
||||||
private String upnpconfigaddress;
|
import java.net.InetAddress;
|
||||||
private String serverport;
|
import java.net.NetworkInterface;
|
||||||
private String upnpresponseport;
|
import java.net.SocketException;
|
||||||
private String upnpdevicedb;
|
import java.nio.file.FileSystems;
|
||||||
private String veraaddress;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import org.apache.http.conn.util.InetAddressUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.util.BackupHandler;
|
||||||
|
import com.bwssystems.util.JsonTransformer;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class BridgeSettings extends BackupHandler {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||||
|
private BridgeSettingsDescriptor theBridgeSettings;
|
||||||
|
private BridgeControlDescriptor bridgeControl;
|
||||||
|
|
||||||
public String getUpnpConfigAddress() {
|
public BridgeSettings() {
|
||||||
return upnpconfigaddress;
|
super();
|
||||||
|
bridgeControl = new BridgeControlDescriptor();
|
||||||
|
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||||
}
|
}
|
||||||
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
public BridgeControlDescriptor getBridgeControl() {
|
||||||
this.upnpconfigaddress = upnpConfigAddress;
|
return bridgeControl;
|
||||||
}
|
}
|
||||||
public String getServerPort() {
|
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
||||||
return serverport;
|
return theBridgeSettings;
|
||||||
}
|
}
|
||||||
public void setServerPort(String serverPort) {
|
public void buildSettings() {
|
||||||
this.serverport = serverPort;
|
InetAddress address = null;
|
||||||
|
String addressString = null;
|
||||||
|
String theVeraAddress = null;
|
||||||
|
String theHarmonyAddress = null;
|
||||||
|
|
||||||
|
String configFileProperty = System.getProperty("config.file");
|
||||||
|
if(configFileProperty == null) {
|
||||||
|
Path filePath = Paths.get(Configuration.CONFIG_FILE);
|
||||||
|
if(Files.exists(filePath) && Files.isReadable(filePath))
|
||||||
|
configFileProperty = Configuration.CONFIG_FILE;
|
||||||
|
}
|
||||||
|
String serverPortOverride = System.getProperty("server.port");
|
||||||
|
if(configFileProperty != null)
|
||||||
|
{
|
||||||
|
log.info("reading from config file: " + configFileProperty);
|
||||||
|
theBridgeSettings.setConfigfile(configFileProperty);
|
||||||
|
_loadConfig();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.info("reading from system properties");
|
||||||
|
theBridgeSettings.setNumberoflogmessages(Configuration.NUMBER_OF_LOG_MESSAGES);
|
||||||
|
theBridgeSettings.setFarenheit(true);
|
||||||
|
theBridgeSettings.setConfigfile(Configuration.CONFIG_FILE);
|
||||||
|
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
|
||||||
|
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
|
||||||
|
theBridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db"));
|
||||||
|
theBridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
|
||||||
|
|
||||||
|
theVeraAddress = System.getProperty("vera.address");
|
||||||
|
IpList theVeraList = null;
|
||||||
|
if(theVeraAddress != null) {
|
||||||
|
try {
|
||||||
|
theVeraList = new Gson().fromJson(theVeraAddress, IpList.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
theVeraList = new Gson().fromJson("{devices:[{name:default,ip:" + theVeraAddress + "}]}", IpList.class);
|
||||||
|
} catch (Exception et) {
|
||||||
|
log.error("Cannot parse vera.address, not set with message: " + e.getMessage(), e);
|
||||||
|
theVeraList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theBridgeSettings.setVeraAddress(theVeraList);
|
||||||
|
|
||||||
|
theHarmonyAddress = System.getProperty("harmony.address");
|
||||||
|
IpList theHarmonyList = null;
|
||||||
|
if(theHarmonyAddress != null) {
|
||||||
|
try {
|
||||||
|
theHarmonyList = new Gson().fromJson(theHarmonyAddress, IpList.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
theHarmonyList = new Gson().fromJson("{devices:[{name:default,ip:" + theHarmonyAddress + "}]}", IpList.class);
|
||||||
|
} catch (Exception et) {
|
||||||
|
log.error("Cannot parse harmony.address, not set with message: " + e.getMessage(), e);
|
||||||
|
theHarmonyList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theBridgeSettings.setHarmonyAddress(theHarmonyList);
|
||||||
|
theBridgeSettings.setHarmonyUser(System.getProperty("harmony.user"));
|
||||||
|
theBridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd"));
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().equals("")) {
|
||||||
|
try {
|
||||||
|
log.info("Getting an IP address for this host....");
|
||||||
|
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
|
||||||
|
|
||||||
|
while (ifs.hasMoreElements() && addressString == null) {
|
||||||
|
NetworkInterface xface = ifs.nextElement();
|
||||||
|
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
||||||
|
String name = xface.getName();
|
||||||
|
int IPsPerNic = 0;
|
||||||
|
|
||||||
|
while (addrs.hasMoreElements() && IPsPerNic == 0) {
|
||||||
|
address = addrs.nextElement();
|
||||||
|
if (InetAddressUtils.isIPv4Address(address.getHostAddress())) {
|
||||||
|
log.debug(name + " ... has IPV4 addr " + address);
|
||||||
|
if(!name.equalsIgnoreCase(Configuration.LOOP_BACK_INTERFACE)|| !address.getHostAddress().equalsIgnoreCase(Configuration.LOOP_BACK_ADDRESS)) {
|
||||||
|
IPsPerNic++;
|
||||||
|
addressString = address.getHostAddress();
|
||||||
|
log.info("Adding " + addressString + " from interface " + name + " as our default upnp config address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
theBridgeSettings.setUpnpConfigAddress(addressString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(theBridgeSettings.getUpnpResponsePort() == null)
|
||||||
|
theBridgeSettings.setUpnpResponsePort(Configuration.UPNP_RESPONSE_PORT);
|
||||||
|
|
||||||
|
if(theBridgeSettings.getServerPort() == null)
|
||||||
|
theBridgeSettings.setServerPort(Configuration.DEFAULT_WEB_PORT);
|
||||||
|
|
||||||
|
if(theBridgeSettings.getUpnpDeviceDb() == null)
|
||||||
|
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
||||||
|
|
||||||
|
if(theBridgeSettings.getNumberoflogmessages() == null)
|
||||||
|
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||||
|
|
||||||
|
if(theBridgeSettings.getNumberoflogmessages() <= 0)
|
||||||
|
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
|
||||||
|
|
||||||
|
if(theBridgeSettings.getButtonsleep() == null)
|
||||||
|
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||||
|
|
||||||
|
if(theBridgeSettings.getButtonsleep() < 0)
|
||||||
|
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||||
|
|
||||||
|
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
||||||
|
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
||||||
|
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||||
|
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
||||||
|
theBridgeSettings.setHalconfigured(theBridgeSettings.isValidHal());
|
||||||
|
if(serverPortOverride != null)
|
||||||
|
theBridgeSettings.setServerPort(serverPortOverride);
|
||||||
|
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||||
}
|
}
|
||||||
public String getUpnpResponsePort() {
|
|
||||||
return upnpresponseport;
|
public void loadConfig() {
|
||||||
|
if(theBridgeSettings.getConfigfile() != null)
|
||||||
|
_loadConfig();
|
||||||
}
|
}
|
||||||
public void setUpnpResponsePort(String upnpResponsePort) {
|
private void _loadConfig() {
|
||||||
this.upnpresponseport = upnpResponsePort;
|
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||||
}
|
_loadConfig(configPath);
|
||||||
public String getUpnpDeviceDb() {
|
}
|
||||||
return upnpdevicedb;
|
|
||||||
}
|
private void _loadConfig(Path aPath) {
|
||||||
public void setUpnpDeviceDb(String upnpDeviceDb) {
|
String jsonContent = configReader(aPath);
|
||||||
this.upnpdevicedb = upnpDeviceDb;
|
try {
|
||||||
}
|
theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
|
||||||
public String getVeraAddress() {
|
} catch (Exception e) {
|
||||||
return veraaddress;
|
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
|
||||||
}
|
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||||
public void setVeraAddress(String veraAddress) {
|
theBridgeSettings.setConfigfile(aPath.toString());
|
||||||
this.veraaddress = veraAddress;
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(BridgeSettingsDescriptor newBridgeSettings) {
|
||||||
|
log.debug("Save HA Bridge settings.");
|
||||||
|
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||||
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
|
String jsonValue = aRenderer.render(newBridgeSettings);
|
||||||
|
configWriter(jsonValue, configPath);
|
||||||
|
_loadConfig(configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void configWriter(String content, Path filePath) {
|
||||||
|
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||||
|
log.error("Error file is not writable: " + filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Files.notExists(filePath.getParent())) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(filePath.getParent());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error creating the directory: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path target = null;
|
||||||
|
if(Files.exists(filePath)) {
|
||||||
|
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old");
|
||||||
|
Files.move(filePath, target);
|
||||||
|
}
|
||||||
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
|
if(target != null)
|
||||||
|
Files.delete(target);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String configReader(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...");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
content = new String(Files.readAllBytes(filePath));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,256 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||||
|
|
||||||
|
public class BridgeSettingsDescriptor {
|
||||||
|
private String upnpconfigaddress;
|
||||||
|
private Integer serverport;
|
||||||
|
private Integer upnpresponseport;
|
||||||
|
private String upnpdevicedb;
|
||||||
|
private IpList veraaddress;
|
||||||
|
private IpList harmonyaddress;
|
||||||
|
private String harmonyuser;
|
||||||
|
private String harmonypwd;
|
||||||
|
private Integer buttonsleep;
|
||||||
|
private boolean upnpstrict;
|
||||||
|
private boolean traceupnp;
|
||||||
|
private String nestuser;
|
||||||
|
private String nestpwd;
|
||||||
|
private boolean veraconfigured;
|
||||||
|
private boolean harmonyconfigured;
|
||||||
|
private boolean nestconfigured;
|
||||||
|
private boolean farenheit;
|
||||||
|
private String configfile;
|
||||||
|
private Integer numberoflogmessages;
|
||||||
|
private IpList hueaddress;
|
||||||
|
private boolean hueconfigured;
|
||||||
|
private IpList haladdress;
|
||||||
|
private String haltoken;
|
||||||
|
private boolean halconfigured;
|
||||||
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
|
private boolean settingsChanged;
|
||||||
|
|
||||||
|
public BridgeSettingsDescriptor() {
|
||||||
|
super();
|
||||||
|
this.upnpstrict = true;
|
||||||
|
this.traceupnp = false;
|
||||||
|
this.nestconfigured = false;
|
||||||
|
this.veraconfigured = false;
|
||||||
|
this.harmonyconfigured = false;
|
||||||
|
this.hueconfigured = false;
|
||||||
|
this.halconfigured = false;
|
||||||
|
this.farenheit = true;
|
||||||
|
this.whitelist = null;
|
||||||
|
this.settingsChanged = false;
|
||||||
|
}
|
||||||
|
public String getUpnpConfigAddress() {
|
||||||
|
return upnpconfigaddress;
|
||||||
|
}
|
||||||
|
public void setUpnpConfigAddress(String upnpConfigAddress) {
|
||||||
|
this.upnpconfigaddress = upnpConfigAddress;
|
||||||
|
}
|
||||||
|
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 IpList getVeraAddress() {
|
||||||
|
return veraaddress;
|
||||||
|
}
|
||||||
|
public void setVeraAddress(IpList veraAddress) {
|
||||||
|
this.veraaddress = veraAddress;
|
||||||
|
}
|
||||||
|
public IpList getHarmonyAddress() {
|
||||||
|
return harmonyaddress;
|
||||||
|
}
|
||||||
|
public void setHarmonyAddress(IpList harmonyaddress) {
|
||||||
|
this.harmonyaddress = harmonyaddress;
|
||||||
|
}
|
||||||
|
public String getHarmonyUser() {
|
||||||
|
return harmonyuser;
|
||||||
|
}
|
||||||
|
public void setHarmonyUser(String harmonyuser) {
|
||||||
|
this.harmonyuser = harmonyuser;
|
||||||
|
}
|
||||||
|
public String getHarmonyPwd() {
|
||||||
|
return harmonypwd;
|
||||||
|
}
|
||||||
|
public void setHarmonyPwd(String harmonypwd) {
|
||||||
|
this.harmonypwd = harmonypwd;
|
||||||
|
}
|
||||||
|
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 void setVeraconfigured(boolean veraconfigured) {
|
||||||
|
this.veraconfigured = veraconfigured;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
public boolean isSettingsChanged() {
|
||||||
|
return settingsChanged;
|
||||||
|
}
|
||||||
|
public void setSettingsChanged(boolean settingsChanged) {
|
||||||
|
this.settingsChanged = settingsChanged;
|
||||||
|
}
|
||||||
|
public Boolean isValidVera() {
|
||||||
|
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))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidHarmony() {
|
||||||
|
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))
|
||||||
|
return false;
|
||||||
|
if(this.getHarmonyPwd() == null || this.getHarmonyPwd().equals(""))
|
||||||
|
return false;
|
||||||
|
if(this.getHarmonyUser() == null || this.getHarmonyUser().equals(""))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidNest() {
|
||||||
|
if(this.getNestpwd() == null || this.getNestpwd().equals(""))
|
||||||
|
return false;
|
||||||
|
if(this.getNestuser() == null || this.getNestuser().equals(""))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Boolean isValidHue() {
|
||||||
|
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))
|
||||||
|
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))
|
||||||
|
return false;
|
||||||
|
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
15
src/main/java/com/bwssystems/HABridge/Configuration.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class Configuration {
|
||||||
|
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
|
||||||
|
public final static String UPNP_RESPONSE_PORT = "50000";
|
||||||
|
public final static String DEFAULT_ADDRESS = "1.1.1.1";
|
||||||
|
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
|
||||||
|
public final static String LOOP_BACK_INTERFACE = "lo";
|
||||||
|
public final static String DEFAULT_WEB_PORT = "8080";
|
||||||
|
public final static String DEFAULT_BUTTON_SLEEP = "100";
|
||||||
|
public static final int UPNP_DISCOVERY_PORT = 1900;
|
||||||
|
public static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
|
||||||
|
public static final String CONFIG_FILE = "data/habridge.config";
|
||||||
|
public static final int NUMBER_OF_LOG_MESSAGES = 512;
|
||||||
|
}
|
||||||
@@ -2,9 +2,6 @@ package com.bwssystems.HABridge;
|
|||||||
|
|
||||||
import static spark.Spark.*;
|
import static spark.Spark.*;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -12,7 +9,10 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
|
|||||||
import com.bwssystems.HABridge.hue.HueMulator;
|
import com.bwssystems.HABridge.hue.HueMulator;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||||
import com.bwssystems.vera.VeraInfo;
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.hal.HalHome;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.bwssystems.hue.HueHome;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -34,47 +34,69 @@ public class HABridge {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||||
DeviceResource theResources;
|
DeviceResource theResources;
|
||||||
|
HarmonyHome harmonyHome;
|
||||||
|
NestHome nestHome;
|
||||||
|
HueHome hueHome;
|
||||||
|
HalHome halHome;
|
||||||
HueMulator theHueMulator;
|
HueMulator theHueMulator;
|
||||||
UpnpSettingsResource theSettingResponder;
|
UpnpSettingsResource theSettingResponder;
|
||||||
UpnpListener theUpnpListener;
|
UpnpListener theUpnpListener;
|
||||||
InetAddress address;
|
SystemControl theSystem;
|
||||||
String addressString;
|
|
||||||
BridgeSettings bridgeSettings;
|
BridgeSettings bridgeSettings;
|
||||||
|
Version theVersion;
|
||||||
|
|
||||||
|
theVersion = new Version();
|
||||||
|
|
||||||
//get ip address for upnp requests
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
|
||||||
try {
|
|
||||||
address = InetAddress.getLocalHost();
|
|
||||||
addressString = address.getHostAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
log.error("Cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bridgeSettings = new BridgeSettings();
|
bridgeSettings = new BridgeSettings();
|
||||||
bridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address", addressString));
|
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||||
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", "data/device.db"));
|
bridgeSettings.buildSettings();
|
||||||
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", "50000"));
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") initializing....");
|
||||||
bridgeSettings.setVeraAddress(System.getProperty("vera.address", "192.168.1.100"));
|
// sparkjava config directive to set ip address for the web server to listen on
|
||||||
|
// ipAddress("0.0.0.0"); // not used
|
||||||
// sparkjava config directive to set ip address for the web server to listen on
|
// sparkjava config directive to set port for the web server to listen on
|
||||||
// ipAddress("0.0.0.0"); // not used
|
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||||
// sparkjava config directive to set port for the web server to listen on
|
// sparkjava config directive to set html static file location for Jetty
|
||||||
bridgeSettings.setServerPort(System.getProperty("server.port", "8080"));
|
staticFileLocation("/public");
|
||||||
port(Integer.valueOf(bridgeSettings.getServerPort()));
|
// setup system control api first
|
||||||
// sparkjava config directive to set html static file location for Jetty
|
theSystem = new SystemControl(bridgeSettings, theVersion);
|
||||||
staticFileLocation("/public");
|
theSystem.setupServer();
|
||||||
log.info("Starting setup....");
|
//setup the harmony connection if available
|
||||||
// setup the class to handle the resource setup rest api
|
harmonyHome = new HarmonyHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
theResources = new DeviceResource(bridgeSettings);
|
//setup the nest connection if available
|
||||||
// setup the class to handle the hue emulator rest api
|
nestHome = new NestHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
theHueMulator = new HueMulator(theResources.getDeviceRepository());
|
//setup the hue passtrhu configuration if available
|
||||||
// setup the class to handle the upnp response rest api
|
hueHome = new HueHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
//setup the hal configuration if available
|
||||||
// wait for the sparkjava initialization of the rest api classes to be complete
|
halHome = new HalHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
awaitInitialization();
|
// setup the class to handle the resource setup rest api
|
||||||
|
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome);
|
||||||
// start the upnp ssdp discovery listener
|
// setup the class to handle the hue emulator rest api
|
||||||
theUpnpListener = new UpnpListener(bridgeSettings);
|
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome);
|
||||||
theUpnpListener.startListening();
|
theHueMulator.setupServer();
|
||||||
|
// setup the class to handle the upnp response rest api
|
||||||
|
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
theSettingResponder.setupServer();
|
||||||
|
// wait for the sparkjava initialization of the rest api classes to be complete
|
||||||
|
awaitInitialization();
|
||||||
|
|
||||||
|
// start the upnp ssdp discovery listener
|
||||||
|
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl());
|
||||||
|
if(theUpnpListener.startListening())
|
||||||
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
||||||
|
else
|
||||||
|
bridgeSettings.getBridgeControl().setStop(true);
|
||||||
|
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
|
||||||
|
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
bridgeSettings.getBridgeControl().setReinit(false);
|
||||||
|
stop();
|
||||||
|
nestHome.closeTheNest();
|
||||||
|
nestHome = null;
|
||||||
|
harmonyHome.shutdownHarmonyHubs();
|
||||||
|
harmonyHome = null;
|
||||||
|
}
|
||||||
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
16
src/main/java/com/bwssystems/HABridge/IpList.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IpList {
|
||||||
|
private List<NamedIP> devices;
|
||||||
|
|
||||||
|
public List<NamedIP> getDevices() {
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevices(List<NamedIP> devices) {
|
||||||
|
this.devices = devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
25
src/main/java/com/bwssystems/HABridge/NamedIP.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
public class NamedIP {
|
||||||
|
private String name;
|
||||||
|
private String ip;
|
||||||
|
private String port;
|
||||||
|
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 getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
public void setPort(String port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
283
src/main/java/com/bwssystems/HABridge/SystemControl.java
Normal file
283
src/main/java/com/bwssystems/HABridge/SystemControl.java
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import static spark.Spark.get;
|
||||||
|
import static spark.Spark.options;
|
||||||
|
import static spark.Spark.post;
|
||||||
|
import static spark.Spark.put;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.MulticastSocket;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||||
|
import com.bwssystems.logservices.LoggerInfo;
|
||||||
|
import com.bwssystems.logservices.LoggingForm;
|
||||||
|
import com.bwssystems.logservices.LoggingManager;
|
||||||
|
import com.bwssystems.util.TextStringFormatter;
|
||||||
|
import com.bwssystems.util.JsonTransformer;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
|
import ch.qos.logback.core.read.CyclicBufferAppender;
|
||||||
|
|
||||||
|
public class SystemControl {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SystemControl.class);
|
||||||
|
public static final String CYCLIC_BUFFER_APPENDER_NAME = "CYCLIC";
|
||||||
|
private LoggerContext lc;
|
||||||
|
private static final String SYSTEM_CONTEXT = "/system";
|
||||||
|
private BridgeSettings bridgeSettings;
|
||||||
|
private Version version;
|
||||||
|
private CyclicBufferAppender<ILoggingEvent> cyclicBufferAppender;
|
||||||
|
private DateFormat dateFormat;
|
||||||
|
private LoggingManager theLogServiceMgr;
|
||||||
|
|
||||||
|
|
||||||
|
public SystemControl(BridgeSettings theBridgeSettings, Version theVersion) {
|
||||||
|
this.bridgeSettings = theBridgeSettings;
|
||||||
|
this.version = theVersion;
|
||||||
|
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
|
||||||
|
reacquireCBA();
|
||||||
|
theLogServiceMgr = new LoggingManager();
|
||||||
|
theLogServiceMgr.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function sets up the sparkjava rest calls for the hue api
|
||||||
|
public void setupServer() {
|
||||||
|
log.info("System control service started....");
|
||||||
|
// http://ip_address:port/system/habridge/version gets the version of this bridge instance
|
||||||
|
get (SYSTEM_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get HA Bridge version: v" + version.getVersion());
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return "{\"version\":\"" + version.getVersion() + "\"}";
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/logmsgs gets the log messages for the bridge
|
||||||
|
get (SYSTEM_CONTEXT + "/logmsgs", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get logmsgs.");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
String logMsgs;
|
||||||
|
int count = -1;
|
||||||
|
if(cyclicBufferAppender == null)
|
||||||
|
reacquireCBA();
|
||||||
|
if (cyclicBufferAppender != null) {
|
||||||
|
count = cyclicBufferAppender.getLength();
|
||||||
|
}
|
||||||
|
logMsgs = "[";
|
||||||
|
if (count == -1) {
|
||||||
|
logMsgs = logMsgs + "{\"message\":\"Failed to locate CyclicBuffer\"}";
|
||||||
|
} else if (count == 0) {
|
||||||
|
logMsgs = logMsgs + "{\"message\":\"No logging events to display\"}";
|
||||||
|
} else {
|
||||||
|
LoggingEvent le;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
le = (LoggingEvent) cyclicBufferAppender.get(i);
|
||||||
|
logMsgs = logMsgs + ( i > 0?",{":"{") + "\"time\":\"" + dateFormat.format(le.getTimeStamp()) + "\",\"level\":\"" + le.getLevel().levelStr + "\",\"component\":\"" + le.getLoggerName() + "\",\"message\":\"" + TextStringFormatter.forJSON(le.getFormattedMessage()) + "\"}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logMsgs = logMsgs + "]";
|
||||||
|
response.status(200);
|
||||||
|
return logMsgs;
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/logmgmt/loggers gets the logger info for the bridge
|
||||||
|
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get loggers info with showAll argument: " + request.params(":all"));
|
||||||
|
Boolean showAll = false;
|
||||||
|
if(request.params(":all").equals("true"))
|
||||||
|
showAll = true;
|
||||||
|
theLogServiceMgr.setShowAll(showAll);
|
||||||
|
theLogServiceMgr.init();
|
||||||
|
response.status(200);
|
||||||
|
return theLogServiceMgr.getConfiguredLoggers();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/logmgmt/update CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (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/logmgmt/update which changes logging parameters for the process
|
||||||
|
put(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
||||||
|
log.debug("update loggers: " + request.body());
|
||||||
|
response.status(200);
|
||||||
|
LoggerInfo updateLoggers[];
|
||||||
|
updateLoggers = new Gson().fromJson(request.body(), LoggerInfo[].class);
|
||||||
|
LoggingForm theModel = theLogServiceMgr.getModel();
|
||||||
|
theModel.setUpdatedLoggers(Arrays.asList(updateLoggers));
|
||||||
|
theLogServiceMgr.updateLogLevels();
|
||||||
|
return theLogServiceMgr.getConfiguredLoggers();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
||||||
|
get(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||||
|
log.debug("bridge settings requested from " + request.ip());
|
||||||
|
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/settings CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/settings", "application/json", (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/settings which returns the bridge configuration settings
|
||||||
|
put(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||||
|
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
|
||||||
|
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
|
||||||
|
bridgeSettings.save(newBridgeSettings);
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/control/reinit CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/control/reinit", "application/json", (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/control/reinit sets the parameter reinit the server
|
||||||
|
put(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
|
||||||
|
return reinit();
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/control/stop CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/control/stop", "application/json", (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/control/stop sets the parameter stop the server
|
||||||
|
put(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
|
||||||
|
return stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/available returns a list of config backup filenames
|
||||||
|
get (SYSTEM_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get backup filenames");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return bridgeSettings.getBackups();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/create CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "PUT");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
put (SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||||
|
log.debug("Create backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
BackupFilename returnFilename = new BackupFilename();
|
||||||
|
returnFilename.setFilename(bridgeSettings.backup(aFilename.getFilename()));
|
||||||
|
return returnFilename;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/delete CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
log.debug("Delete backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null)
|
||||||
|
bridgeSettings.deleteBackup(aFilename.getFilename());
|
||||||
|
else
|
||||||
|
log.warn("No filename given for delete backup.");
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/system/backup/restore CORS request
|
||||||
|
options(SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
log.debug("Restore backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null) {
|
||||||
|
bridgeSettings.restoreBackup(aFilename.getFilename());
|
||||||
|
bridgeSettings.loadConfig();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("No filename given for restore backup.");
|
||||||
|
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void reacquireCBA() {
|
||||||
|
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
|
||||||
|
Logger.ROOT_LOGGER_NAME).getAppender(CYCLIC_BUFFER_APPENDER_NAME);
|
||||||
|
cyclicBufferAppender.setMaxSize(bridgeSettings.getBridgeSettingsDescriptor().getNumberoflogmessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void pingListener() {
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
String testData = "M-SEARCH * HTTP/1.1\nHOST: " + Configuration.UPNP_MULTICAST_ADDRESS + ":" + Configuration.UPNP_DISCOVERY_PORT + "ST: urn:schemas-upnp-org:device:CloudProxy:1\nMAN: \"ssdp:discover\"\nMX: 3";
|
||||||
|
buf = testData.getBytes();
|
||||||
|
MulticastSocket socket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
|
||||||
|
|
||||||
|
InetAddress group = InetAddress.getByName(Configuration.UPNP_MULTICAST_ADDRESS);
|
||||||
|
DatagramPacket packet;
|
||||||
|
packet = new DatagramPacket(buf, buf.length, group, Configuration.UPNP_DISCOVERY_PORT);
|
||||||
|
socket.send(packet);
|
||||||
|
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
log.warn("Error pinging listener. " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String reinit() {
|
||||||
|
bridgeSettings.getBridgeControl().setReinit(true);
|
||||||
|
pingListener();
|
||||||
|
return "{\"control\":\"reiniting\"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String stop() {
|
||||||
|
bridgeSettings.getBridgeControl().setStop(true);
|
||||||
|
pingListener();
|
||||||
|
return "{\"control\":\"stopping\"}";
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
50
src/main/java/com/bwssystems/HABridge/Version.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
public final class Version {
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
private String groupId;
|
||||||
|
private String artifactId;
|
||||||
|
private Properties prop;
|
||||||
|
|
||||||
|
public Version()
|
||||||
|
{
|
||||||
|
InputStream resourceAsStream =
|
||||||
|
(InputStream) this.getClass().getResourceAsStream(
|
||||||
|
"/version.properties"
|
||||||
|
);
|
||||||
|
this.prop = new Properties();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.prop.load( resourceAsStream );
|
||||||
|
this.version = this.prop.getProperty("version");
|
||||||
|
this.groupId = this.prop.getProperty("groupId");
|
||||||
|
this.artifactId = this.prop.getProperty("artifactId");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
this.version = "0.0.0";
|
||||||
|
this.groupId = "no group";
|
||||||
|
this.artifactId = "no artifact";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArtifactId() {
|
||||||
|
return artifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/main/java/com/bwssystems/HABridge/api/CallItem.java
Normal file
13
src/main/java/com/bwssystems/HABridge/api/CallItem.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class CallItem {
|
||||||
|
private String item;
|
||||||
|
|
||||||
|
public String getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItem(String anitem) {
|
||||||
|
item = anitem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package com.bwssystems.HABridge.api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by arm on 4/13/15.
|
|
||||||
*/
|
|
||||||
public class Device {
|
|
||||||
private String name;
|
|
||||||
private String deviceType;
|
|
||||||
private String offUrl;
|
|
||||||
private String onUrl;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceType() {
|
|
||||||
return deviceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceType(String deviceType) {
|
|
||||||
this.deviceType = deviceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffUrl() {
|
|
||||||
return offUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffUrl(String offUrl) {
|
|
||||||
this.offUrl = offUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOnUrl() {
|
|
||||||
return onUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnUrl(String onUrl) {
|
|
||||||
this.onUrl = onUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class NameValue {
|
||||||
|
private String name;
|
||||||
|
private String value;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class SuccessUserResponse {
|
||||||
|
private UserCreateResponse success;
|
||||||
|
|
||||||
|
public UserCreateResponse getSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(UserCreateResponse success) {
|
||||||
|
this.success = success;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class UserCreateResponse {
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
@@ -14,9 +11,9 @@ public class DeviceResponse {
|
|||||||
private String name;
|
private String name;
|
||||||
private String modelid;
|
private String modelid;
|
||||||
private String manufacturername;
|
private String manufacturername;
|
||||||
|
private String luminaireuniqueid;
|
||||||
private String uniqueid;
|
private String uniqueid;
|
||||||
private String swversion;
|
private String swversion;
|
||||||
private Map<String, String> pointsymbol;
|
|
||||||
|
|
||||||
public DeviceState getState() {
|
public DeviceState getState() {
|
||||||
return state;
|
return state;
|
||||||
@@ -74,48 +71,25 @@ public class DeviceResponse {
|
|||||||
this.swversion = swversion;
|
this.swversion = swversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getPointsymbol() {
|
public String getLuminaireuniqueid() {
|
||||||
Map<String, String> dummyValue = new HashMap<>();
|
return luminaireuniqueid;
|
||||||
dummyValue.put("1", "none");
|
}
|
||||||
dummyValue.put("2", "none");
|
|
||||||
dummyValue.put("3", "none");
|
|
||||||
dummyValue.put("4", "none");
|
|
||||||
dummyValue.put("5", "none");
|
|
||||||
dummyValue.put("6", "none");
|
|
||||||
dummyValue.put("7", "none");
|
|
||||||
dummyValue.put("8", "none");
|
|
||||||
|
|
||||||
return dummyValue;
|
public void setLuminaireuniqueid(String luminaireuniqueid) {
|
||||||
}
|
this.luminaireuniqueid = luminaireuniqueid;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPointsymbol(Map<String, String> pointsymbol) {
|
public static DeviceResponse createResponse(DeviceDescriptor device){
|
||||||
this.pointsymbol = pointsymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceResponse createResponse(String name, String id){
|
|
||||||
DeviceState deviceState = new DeviceState();
|
|
||||||
DeviceResponse response = new DeviceResponse();
|
DeviceResponse response = new DeviceResponse();
|
||||||
response.setState(deviceState);
|
response.setState(device.getDeviceState());
|
||||||
deviceState.setOn(false);
|
|
||||||
deviceState.setReachable(true);
|
|
||||||
deviceState.setEffect("none");
|
|
||||||
deviceState.setAlert("none");
|
|
||||||
deviceState.setBri(254);
|
|
||||||
deviceState.setHue(15823);
|
|
||||||
deviceState.setSat(88);
|
|
||||||
deviceState.setCt(313);
|
|
||||||
|
|
||||||
List<Double> xv = new LinkedList<>();
|
response.setName(device.getName());
|
||||||
xv.add(Double.valueOf("0.4255"));
|
response.setUniqueid(device.getId());
|
||||||
xv.add(Double.valueOf("0.3998"));
|
|
||||||
deviceState.setXy(xv);
|
|
||||||
deviceState.setColormode("ct");
|
|
||||||
response.setName(name);
|
|
||||||
response.setUniqueid(id);
|
|
||||||
response.setManufacturername("Philips");
|
response.setManufacturername("Philips");
|
||||||
response.setType("Extended color light");
|
response.setType("Dimmable light");
|
||||||
response.setModelid("LCT001");
|
response.setModelid("LWB004");
|
||||||
response.setSwversion("65003148");
|
response.setSwversion("66012040");
|
||||||
|
response.setLuminaireuniqueid(null);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
// import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,7 +8,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class DeviceState {
|
public class DeviceState {
|
||||||
private boolean on;
|
private boolean on;
|
||||||
private int bri = 255;
|
private int bri;
|
||||||
private int hue;
|
private int hue;
|
||||||
private int sat;
|
private int sat;
|
||||||
private String effect;
|
private String effect;
|
||||||
@@ -96,7 +97,24 @@ public class DeviceState {
|
|||||||
public void setXy(List<Double> xy) {
|
public void setXy(List<Double> xy) {
|
||||||
this.xy = xy;
|
this.xy = xy;
|
||||||
}
|
}
|
||||||
|
public static DeviceState createDeviceState() {
|
||||||
|
DeviceState newDeviceState = new DeviceState();
|
||||||
|
newDeviceState.fillIn();
|
||||||
|
// newDeviceState.setColormode("none");
|
||||||
|
// ArrayList<Double> doubleArray = new ArrayList<Double>();
|
||||||
|
// doubleArray.add(new Double(0));
|
||||||
|
// doubleArray.add(new Double(0));
|
||||||
|
// newDeviceState.setXy(doubleArray);
|
||||||
|
|
||||||
|
return newDeviceState;
|
||||||
|
}
|
||||||
|
public void fillIn() {
|
||||||
|
if(this.getAlert() == null)
|
||||||
|
this.setAlert("none");
|
||||||
|
if(this.getEffect() == null)
|
||||||
|
this.setEffect("none");
|
||||||
|
this.setReachable(true);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DeviceState{" +
|
return "DeviceState{" +
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
public class DeviceTypes {
|
||||||
|
private Boolean bridge;
|
||||||
|
private String[] lights;
|
||||||
|
public Boolean getBridge() {
|
||||||
|
return bridge;
|
||||||
|
}
|
||||||
|
public void setBridge(Boolean bridge) {
|
||||||
|
this.bridge = bridge;
|
||||||
|
}
|
||||||
|
public String[] getLights() {
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
|
public void setLights(String[] lights) {
|
||||||
|
this.lights = lights;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
public class GroupResponse {
|
||||||
|
private DeviceState action;
|
||||||
|
private String[] lights;
|
||||||
|
private String name;
|
||||||
|
public DeviceState getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
public void setAction(DeviceState action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
public String[] getLights() {
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
|
public void setLights(String[] lights) {
|
||||||
|
this.lights = lights;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupResponse createGroupResponse(String[] theLights) {
|
||||||
|
GroupResponse theResponse = new GroupResponse();
|
||||||
|
theResponse.setAction(DeviceState.createDeviceState());
|
||||||
|
theResponse.setName("Lightset 0");
|
||||||
|
theResponse.setLights(theLights);
|
||||||
|
return theResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,86 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
*/
|
*/
|
||||||
public class HueApiResponse {
|
public class HueApiResponse {
|
||||||
private Map<String, DeviceResponse> lights;
|
private Map<String, DeviceResponse> lights;
|
||||||
|
private Map<String, JsonObject> scenes;
|
||||||
|
private Map<String, JsonObject> groups;
|
||||||
|
private Map<String, JsonObject> schedules;
|
||||||
|
private Map<String, JsonObject> sensors;
|
||||||
|
private Map<String, JsonObject> rules;
|
||||||
|
private HueConfig config;
|
||||||
|
|
||||||
public Map<String, DeviceResponse> getLights() {
|
public HueApiResponse(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
|
||||||
|
super();
|
||||||
|
this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist));
|
||||||
|
this.setRules(new HashMap<>());
|
||||||
|
this.setSensors(new HashMap<>());
|
||||||
|
this.setSchedules(new HashMap<>());
|
||||||
|
this.setGroups(new HashMap<>());
|
||||||
|
this.setScenes(new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, DeviceResponse> getLights() {
|
||||||
return lights;
|
return lights;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLights(Map<String, DeviceResponse> lights) {
|
public void setLights(Map<String, DeviceResponse> lights) {
|
||||||
this.lights = lights;
|
this.lights = lights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, JsonObject> getScenes() {
|
||||||
|
return scenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScenes(Map<String, JsonObject> scenes) {
|
||||||
|
this.scenes = scenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, JsonObject> getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroups(Map<String, JsonObject> groups) {
|
||||||
|
this.groups = groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, JsonObject> getSchedules() {
|
||||||
|
return schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchedules(Map<String, JsonObject> schedules) {
|
||||||
|
this.schedules = schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, JsonObject> getSensors() {
|
||||||
|
return sensors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSensors(Map<String, JsonObject> sensors) {
|
||||||
|
this.sensors = sensors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, JsonObject> getRules() {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRules(Map<String, JsonObject> rules) {
|
||||||
|
this.rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueConfig getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(HueConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
275
src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java
Normal file
275
src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class HueConfig
|
||||||
|
{
|
||||||
|
private Boolean portalservices;
|
||||||
|
private String gateway;
|
||||||
|
private String mac;
|
||||||
|
private String swversion;
|
||||||
|
private String apiversion;
|
||||||
|
private Boolean linkbutton;
|
||||||
|
private String ipaddress;
|
||||||
|
private Integer proxyport;
|
||||||
|
private Swupdate swupdate;
|
||||||
|
private String netmask;
|
||||||
|
private String name;
|
||||||
|
private Boolean dhcp;
|
||||||
|
private String UTC;
|
||||||
|
private String proxyaddress;
|
||||||
|
private String localtime;
|
||||||
|
private String timezone;
|
||||||
|
private String zigbeechannel;
|
||||||
|
private String modelid;
|
||||||
|
private String bridgeid;
|
||||||
|
private Boolean factorynew;
|
||||||
|
private String replacesbridgeid;
|
||||||
|
private Map<String, WhitelistEntry> whitelist;
|
||||||
|
|
||||||
|
public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
|
||||||
|
HueConfig aConfig = new HueConfig();
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
aConfig.setMac(HueConfig.getMacAddress(ipaddress));
|
||||||
|
aConfig.setApiversion("1.10.0");
|
||||||
|
aConfig.setPortalservices(false);
|
||||||
|
aConfig.setGateway(ipaddress);
|
||||||
|
aConfig.setSwversion("01028090");
|
||||||
|
aConfig.setLinkbutton(false);
|
||||||
|
aConfig.setIpaddress(ipaddress);
|
||||||
|
aConfig.setProxyport(0);
|
||||||
|
aConfig.setSwupdate(Swupdate.createSwupdate());
|
||||||
|
aConfig.setNetmask("255.255.255.0");
|
||||||
|
aConfig.setName(name);
|
||||||
|
aConfig.setDhcp(true);
|
||||||
|
aConfig.setUtc(dateFormatGmt.format(new Date()));
|
||||||
|
aConfig.setProxyaddress("none");
|
||||||
|
aConfig.setLocaltime(dateFormat.format(new Date()));
|
||||||
|
aConfig.setTimezone(TimeZone.getDefault().getID());
|
||||||
|
aConfig.setZigbeechannel("6");
|
||||||
|
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
|
||||||
|
aConfig.setModelid("BSB002");
|
||||||
|
aConfig.setFactorynew(false);
|
||||||
|
aConfig.setReplacesbridgeid(null);
|
||||||
|
aConfig.setWhitelist(awhitelist);
|
||||||
|
|
||||||
|
return aConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMacAddress(String addr)
|
||||||
|
{
|
||||||
|
InetAddress ip;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ip = InetAddress.getByName(addr);
|
||||||
|
|
||||||
|
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||||
|
|
||||||
|
byte[] mac = network.getHardwareAddress();
|
||||||
|
|
||||||
|
for (int i = 0; i < mac.length; i++) {
|
||||||
|
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (SocketException e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
public Boolean getPortalservices() {
|
||||||
|
return portalservices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPortalservices(Boolean portalservices) {
|
||||||
|
this.portalservices = portalservices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGateway() {
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGateway(String gateway) {
|
||||||
|
this.gateway = gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMac() {
|
||||||
|
return mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMac(String mac) {
|
||||||
|
this.mac = mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSwversion() {
|
||||||
|
return swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwversion(String swversion) {
|
||||||
|
this.swversion = swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getLinkbutton() {
|
||||||
|
return linkbutton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkbutton(Boolean linkbutton) {
|
||||||
|
this.linkbutton = linkbutton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIpaddress() {
|
||||||
|
return ipaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIpaddress(String ipaddress) {
|
||||||
|
this.ipaddress = ipaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getProxyport() {
|
||||||
|
return proxyport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyport(Integer proxyport) {
|
||||||
|
this.proxyport = proxyport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Swupdate getSwupdate() {
|
||||||
|
return swupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwupdate(Swupdate swupdate) {
|
||||||
|
this.swupdate = swupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNetmask() {
|
||||||
|
return netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetmask(String netmask) {
|
||||||
|
this.netmask = netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDhcp() {
|
||||||
|
return dhcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDhcp(Boolean dhcp) {
|
||||||
|
this.dhcp = dhcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUtc() {
|
||||||
|
return UTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUtc(String utc) {
|
||||||
|
this.UTC = utc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxyaddress() {
|
||||||
|
return proxyaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyaddress(String proxyaddress) {
|
||||||
|
this.proxyaddress = proxyaddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, WhitelistEntry> getWhitelist() {
|
||||||
|
return whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiversion() {
|
||||||
|
return apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiversion(String apiversion) {
|
||||||
|
this.apiversion = apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocaltime() {
|
||||||
|
return localtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocaltime(String localtime) {
|
||||||
|
this.localtime = localtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimezone() {
|
||||||
|
return timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimezone(String timezone) {
|
||||||
|
this.timezone = timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZigbeechannel() {
|
||||||
|
return zigbeechannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZigbeechannel(String zigbeechannel) {
|
||||||
|
this.zigbeechannel = zigbeechannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModelid() {
|
||||||
|
return modelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModelid(String modelid) {
|
||||||
|
this.modelid = modelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBridgeid() {
|
||||||
|
return bridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBridgeid(String bridgeid) {
|
||||||
|
this.bridgeid = bridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFactorynew() {
|
||||||
|
return factorynew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFactorynew(Boolean factorynew) {
|
||||||
|
this.factorynew = factorynew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReplacesbridgeid() {
|
||||||
|
return replacesbridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReplacesbridgeid(String replacesbridgeid) {
|
||||||
|
this.replacesbridgeid = replacesbridgeid;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
19
src/main/java/com/bwssystems/HABridge/api/hue/HueError.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
public class HueError {
|
||||||
|
|
||||||
|
private HueErrorDetails error;
|
||||||
|
|
||||||
|
public HueError(HueErrorDetails error) {
|
||||||
|
super();
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueErrorDetails getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setError(HueErrorDetails error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
public class HueErrorDetails {
|
||||||
|
private String type;
|
||||||
|
private String address;
|
||||||
|
private String description;
|
||||||
|
private String method_name;
|
||||||
|
private String resource_name;
|
||||||
|
private String value;
|
||||||
|
public HueErrorDetails(String type, String address, String description, String method_name, String resource_name,
|
||||||
|
String value) {
|
||||||
|
super();
|
||||||
|
this.type = type;
|
||||||
|
this.address = address;
|
||||||
|
this.description = description;
|
||||||
|
this.method_name = method_name;
|
||||||
|
this.resource_name = resource_name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
public String getMethod_name() {
|
||||||
|
return method_name;
|
||||||
|
}
|
||||||
|
public void setMethod_name(String method_name) {
|
||||||
|
this.method_name = method_name;
|
||||||
|
}
|
||||||
|
public String getResource_name() {
|
||||||
|
return resource_name;
|
||||||
|
}
|
||||||
|
public void setResource_name(String resource_name) {
|
||||||
|
this.resource_name = resource_name;
|
||||||
|
}
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class HueErrorResponse {
|
||||||
|
private ArrayList<HueError> theErrors;
|
||||||
|
|
||||||
|
public HueErrorResponse() {
|
||||||
|
super();
|
||||||
|
theErrors = new ArrayList<HueError>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addError(HueError anError) {
|
||||||
|
theErrors.add(anError);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueError[] getTheErrors() {
|
||||||
|
HueError theList[] = new HueError[theErrors.size()];
|
||||||
|
theList = theErrors.toArray(theList);
|
||||||
|
return theList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTheErrors(ArrayList<HueError> theErrors) {
|
||||||
|
this.theErrors = theErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
|
public class HuePublicConfig
|
||||||
|
{
|
||||||
|
private String name;
|
||||||
|
private String apiversion;
|
||||||
|
private String swversion;
|
||||||
|
private String mac;
|
||||||
|
private String bridgeid;
|
||||||
|
private String replacesbridgeid;
|
||||||
|
private Boolean factorynew;
|
||||||
|
private String modelid;
|
||||||
|
|
||||||
|
public static HuePublicConfig createConfig(String name, String ipaddress) {
|
||||||
|
HuePublicConfig aConfig = new HuePublicConfig();
|
||||||
|
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
|
||||||
|
aConfig.setApiversion("1.10.0");
|
||||||
|
aConfig.setSwversion("01028090");
|
||||||
|
aConfig.setName(name);
|
||||||
|
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
|
||||||
|
aConfig.setModelid("BSB002");
|
||||||
|
aConfig.setFactorynew(false);
|
||||||
|
aConfig.setReplacesbridgeid(null);
|
||||||
|
|
||||||
|
return aConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMacAddress(String addr)
|
||||||
|
{
|
||||||
|
InetAddress ip;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ip = InetAddress.getByName(addr);
|
||||||
|
|
||||||
|
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||||
|
|
||||||
|
byte[] mac = network.getHardwareAddress();
|
||||||
|
|
||||||
|
for (int i = 0; i < mac.length; i++) {
|
||||||
|
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (SocketException e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
|
||||||
|
sb.append("00:00:88:00:bb:ee");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getBridgeIdFromMac(String macAddr, String ipAddr)
|
||||||
|
{
|
||||||
|
StringTokenizer st = new StringTokenizer(macAddr, ":");
|
||||||
|
String bridgeId = "";
|
||||||
|
String port = null;
|
||||||
|
while(st.hasMoreTokens()) {
|
||||||
|
bridgeId = bridgeId + st.nextToken();
|
||||||
|
}
|
||||||
|
if(ipAddr.contains(":")) {
|
||||||
|
port = ipAddr.substring(ipAddr.indexOf(":"));
|
||||||
|
BigInteger bigInt = BigInteger.valueOf(Integer.getInteger(port).intValue());
|
||||||
|
byte[] theBytes = bigInt.toByteArray();
|
||||||
|
bridgeId = bridgeId + DatatypeConverter.printHexBinary(theBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bridgeId = bridgeId + "0800";
|
||||||
|
return bridgeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMac() {
|
||||||
|
return mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMac(String mac) {
|
||||||
|
this.mac = mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSwversion() {
|
||||||
|
return swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwversion(String swversion) {
|
||||||
|
this.swversion = swversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getApiversion() {
|
||||||
|
return apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiversion(String apiversion) {
|
||||||
|
this.apiversion = apiversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getModelid() {
|
||||||
|
return modelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModelid(String modelid) {
|
||||||
|
this.modelid = modelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBridgeid() {
|
||||||
|
return bridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBridgeid(String bridgeid) {
|
||||||
|
this.bridgeid = bridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFactorynew() {
|
||||||
|
return factorynew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFactorynew(Boolean factorynew) {
|
||||||
|
this.factorynew = factorynew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReplacesbridgeid() {
|
||||||
|
return replacesbridgeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReplacesbridgeid(String replacesbridgeid) {
|
||||||
|
this.replacesbridgeid = replacesbridgeid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
// import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by arm on 4/14/15.
|
||||||
|
*/
|
||||||
|
public class StateChangeBody {
|
||||||
|
private boolean on;
|
||||||
|
private int bri;
|
||||||
|
private int hue;
|
||||||
|
private int sat;
|
||||||
|
private String effect;
|
||||||
|
private int ct;
|
||||||
|
private String alert;
|
||||||
|
private List<Double> xy;
|
||||||
|
private int transitiontime;
|
||||||
|
private int bri_inc;
|
||||||
|
private int hue_inc;
|
||||||
|
private int sat_inc;
|
||||||
|
private List<Double> xy_inc;
|
||||||
|
private int ct_inc;
|
||||||
|
|
||||||
|
public boolean isOn() {
|
||||||
|
return on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOn(boolean on) {
|
||||||
|
this.on = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBri() {
|
||||||
|
return bri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBri(int bri) {
|
||||||
|
this.bri = 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 String getEffect() {
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEffect(String effect) {
|
||||||
|
this.effect = effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCt() {
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCt(int ct) {
|
||||||
|
this.ct = ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlert() {
|
||||||
|
return alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlert(String alert) {
|
||||||
|
this.alert = alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Double> getXy() {
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXy(List<Double> xy) {
|
||||||
|
this.xy = xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTransitiontime() {
|
||||||
|
return transitiontime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransitiontime(int transitiontime) {
|
||||||
|
this.transitiontime = transitiontime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBri_inc() {
|
||||||
|
return bri_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBri_inc(int bri_inc) {
|
||||||
|
this.bri_inc = bri_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHue_inc() {
|
||||||
|
return hue_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHue_inc(int hue_inc) {
|
||||||
|
this.hue_inc = hue_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSat_inc() {
|
||||||
|
return sat_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSat_inc(int sat_inc) {
|
||||||
|
this.sat_inc = sat_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Double> getXy_inc() {
|
||||||
|
return xy_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXy_inc(List<Double> xy_inc) {
|
||||||
|
this.xy_inc = xy_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCt_inc() {
|
||||||
|
return ct_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCt_inc(int ct_inc) {
|
||||||
|
this.ct_inc = ct_inc;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/main/java/com/bwssystems/HABridge/api/hue/Swupdate.java
Normal file
68
src/main/java/com/bwssystems/HABridge/api/hue/Swupdate.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
|
||||||
|
public class Swupdate
|
||||||
|
{
|
||||||
|
private Integer updatestate;
|
||||||
|
private Boolean checkforupdate;
|
||||||
|
private DeviceTypes devicetypes;
|
||||||
|
private String text;
|
||||||
|
private Boolean notify;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public static Swupdate createSwupdate() {
|
||||||
|
Swupdate aSwupdate = new Swupdate();
|
||||||
|
aSwupdate.setUpdatestate(0);
|
||||||
|
aSwupdate.setCheckforupdate(false);
|
||||||
|
aSwupdate.setDevicetypes(new DeviceTypes());
|
||||||
|
aSwupdate.setNotify(false);
|
||||||
|
aSwupdate.setText("");
|
||||||
|
aSwupdate.setUrl("");
|
||||||
|
return aSwupdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getCheckforupdate() {
|
||||||
|
return checkforupdate;
|
||||||
|
}
|
||||||
|
public void setCheckforupdate(Boolean checkforupdate) {
|
||||||
|
this.checkforupdate = checkforupdate;
|
||||||
|
}
|
||||||
|
public DeviceTypes getDevicetypes() {
|
||||||
|
return devicetypes;
|
||||||
|
}
|
||||||
|
public void setDevicetypes(DeviceTypes devicetypes) {
|
||||||
|
this.devicetypes = devicetypes;
|
||||||
|
}
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getNotify() {
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotify(Boolean notify) {
|
||||||
|
this.notify = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUpdatestate() {
|
||||||
|
return updatestate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatestate(Integer updatestate) {
|
||||||
|
this.updatestate = updatestate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
public static WhitelistEntry createEntry(String devicetype) {
|
||||||
|
WhitelistEntry anEntry = new WhitelistEntry();
|
||||||
|
anEntry.setName(devicetype);
|
||||||
|
anEntry.setCreateDate(getCurrentDate());
|
||||||
|
anEntry.setLastUseDate(getCurrentDate());
|
||||||
|
return anEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCurrentDate() {
|
||||||
|
return dateFormat.format(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastUseDate() {
|
||||||
|
return lastUseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUseDate(String lastUseDate) {
|
||||||
|
this.lastUseDate = lastUseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateDate() {
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateDate(String createDate) {
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
public class BackupFilename {
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,58 @@
|
|||||||
package com.bwssystems.HABridge.dao;
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Object to handle the device configuration
|
* Object to handle the device configuration
|
||||||
*/
|
*/
|
||||||
public class DeviceDescriptor{
|
public class DeviceDescriptor{
|
||||||
private String id;
|
@SerializedName("id")
|
||||||
|
@Expose
|
||||||
|
private String id;
|
||||||
|
@SerializedName("name")
|
||||||
|
@Expose
|
||||||
private String name;
|
private String name;
|
||||||
|
@SerializedName("mapId")
|
||||||
|
@Expose
|
||||||
|
private String mapId;
|
||||||
|
@SerializedName("mapType")
|
||||||
|
@Expose
|
||||||
|
private String mapType;
|
||||||
|
@SerializedName("deviceType")
|
||||||
|
@Expose
|
||||||
private String deviceType;
|
private String deviceType;
|
||||||
|
@SerializedName("targetDevice")
|
||||||
|
@Expose
|
||||||
|
private String targetDevice;
|
||||||
|
@SerializedName("offUrl")
|
||||||
|
@Expose
|
||||||
private String offUrl;
|
private String offUrl;
|
||||||
|
@SerializedName("dimUrl")
|
||||||
|
@Expose
|
||||||
|
private String dimUrl;
|
||||||
|
@SerializedName("onUrl")
|
||||||
|
@Expose
|
||||||
private String onUrl;
|
private String onUrl;
|
||||||
|
@SerializedName("headers")
|
||||||
|
@Expose
|
||||||
|
private String headers;
|
||||||
|
@SerializedName("httpVerb")
|
||||||
|
@Expose
|
||||||
|
private String httpVerb;
|
||||||
|
@SerializedName("contentType")
|
||||||
|
@Expose
|
||||||
|
private String contentType;
|
||||||
|
@SerializedName("contentBody")
|
||||||
|
@Expose
|
||||||
|
private String contentBody;
|
||||||
|
@SerializedName("contentBodyOff")
|
||||||
|
@Expose
|
||||||
|
private String contentBodyOff;
|
||||||
|
|
||||||
|
private DeviceState deviceState;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -17,7 +61,23 @@ public class DeviceDescriptor{
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDeviceType() {
|
public String getMapId() {
|
||||||
|
return mapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapId(String mapId) {
|
||||||
|
this.mapId = mapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMapType() {
|
||||||
|
return mapType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapType(String mapType) {
|
||||||
|
this.mapType = mapType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceType() {
|
||||||
return deviceType;
|
return deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +85,15 @@ public class DeviceDescriptor{
|
|||||||
this.deviceType = deviceType;
|
this.deviceType = deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOffUrl() {
|
public String getTargetDevice() {
|
||||||
|
return targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetDevice(String targetDevice) {
|
||||||
|
this.targetDevice = targetDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOffUrl() {
|
||||||
return offUrl;
|
return offUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +101,15 @@ public class DeviceDescriptor{
|
|||||||
this.offUrl = offUrl;
|
this.offUrl = offUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOnUrl() {
|
public String getDimUrl() {
|
||||||
|
return dimUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDimUrl(String dimUrl) {
|
||||||
|
this.dimUrl = dimUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOnUrl() {
|
||||||
return onUrl;
|
return onUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,4 +124,55 @@ public class DeviceDescriptor{
|
|||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeaders(String headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHttpVerb() {
|
||||||
|
return httpVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHttpVerb(String httpVerb) {
|
||||||
|
this.httpVerb = httpVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentBody() {
|
||||||
|
return contentBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentBody(String contentBody) {
|
||||||
|
this.contentBody = contentBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentBodyOff() {
|
||||||
|
return contentBodyOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentBodyOff(String contentBodyOff) {
|
||||||
|
this.contentBodyOff = contentBodyOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceState getDeviceState() {
|
||||||
|
if(deviceState == null)
|
||||||
|
deviceState = DeviceState.createDeviceState();
|
||||||
|
return deviceState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceState(DeviceState deviceState) {
|
||||||
|
this.deviceState = deviceState;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.bwssystems.HABridge.dao;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -14,39 +14,52 @@ import java.util.Random;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.bwssystems.util.BackupHandler;
|
||||||
|
import com.bwssystems.util.JsonTransformer;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
/*
|
/*
|
||||||
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
||||||
* loading.
|
* loading.
|
||||||
*/
|
*/
|
||||||
public class DeviceRepository {
|
public class DeviceRepository extends BackupHandler {
|
||||||
Map<String, DeviceDescriptor> devices;
|
private Map<String, DeviceDescriptor> devices;
|
||||||
Path repositoryPath;
|
private Path repositoryPath;
|
||||||
final Random random = new Random();
|
private Gson gson;
|
||||||
final Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
final private Random random = new Random();
|
||||||
|
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||||
|
|
||||||
public DeviceRepository(String deviceDb) {
|
public DeviceRepository(String deviceDb) {
|
||||||
super();
|
super();
|
||||||
|
gson =
|
||||||
|
new GsonBuilder()
|
||||||
|
.excludeFieldsWithoutExposeAnnotation()
|
||||||
|
.create();
|
||||||
|
repositoryPath = null;
|
||||||
repositoryPath = Paths.get(deviceDb);
|
repositoryPath = Paths.get(deviceDb);
|
||||||
String jsonContent = repositoryReader(repositoryPath);
|
setupParams(repositoryPath, ".bk", "device.db-");
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadRepository() {
|
||||||
|
if(repositoryPath != null)
|
||||||
|
_loadRepository(repositoryPath);
|
||||||
|
}
|
||||||
|
private void _loadRepository(Path aPath){
|
||||||
|
String jsonContent = repositoryReader(aPath);
|
||||||
devices = new HashMap<String, DeviceDescriptor>();
|
devices = new HashMap<String, DeviceDescriptor>();
|
||||||
|
|
||||||
if(jsonContent != null)
|
if(jsonContent != null)
|
||||||
{
|
{
|
||||||
List<DeviceDescriptor> list = readJsonStream(jsonContent);
|
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
||||||
ListIterator<DeviceDescriptor> theIterator = list.listIterator();
|
for(int i = 0; i < list.length; i++) {
|
||||||
DeviceDescriptor theDevice = null;
|
put(list[i].getId(), list[i]);
|
||||||
while (theIterator.hasNext()) {
|
|
||||||
theDevice = theIterator.next();
|
|
||||||
put(theDevice.getId(), theDevice);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DeviceDescriptor> findAll() {
|
public List<DeviceDescriptor> findAll() {
|
||||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||||
@@ -66,16 +79,19 @@ public class DeviceRepository {
|
|||||||
devices.put(id, aDescriptor);
|
devices.put(id, aDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(DeviceDescriptor aDescriptor) {
|
public void save(DeviceDescriptor[] descriptors) {
|
||||||
if(aDescriptor.getId() != null)
|
String theNames = "";
|
||||||
devices.remove(aDescriptor.getId());
|
for(int i = 0; i < descriptors.length; i++) {
|
||||||
else
|
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||||
aDescriptor.setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
|
devices.remove(descriptors[i].getId());
|
||||||
put(aDescriptor.getId(), aDescriptor);
|
else
|
||||||
JsonTransformer aRenderer = new JsonTransformer();
|
descriptors[i].setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
|
||||||
String jsonValue = aRenderer.render(findAll());
|
put(descriptors[i].getId(), descriptors[i]);
|
||||||
|
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||||
|
}
|
||||||
|
String jsonValue = gson.toJson(findAll());
|
||||||
repositoryWriter(jsonValue, repositoryPath);
|
repositoryWriter(jsonValue, repositoryPath);
|
||||||
log.debug("Save device: " + aDescriptor.getName());
|
log.debug("Save device(s): " + theNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String delete(DeviceDescriptor aDescriptor) {
|
public String delete(DeviceDescriptor aDescriptor) {
|
||||||
@@ -106,7 +122,14 @@ public class DeviceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Path target = null;
|
||||||
|
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);
|
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||||
|
if(target != null)
|
||||||
|
Files.delete(target);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -116,7 +139,7 @@ public class DeviceRepository {
|
|||||||
|
|
||||||
String content = null;
|
String content = null;
|
||||||
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
||||||
log.error("Error reading the file: " + filePath + " - Does not exist or is not readable. ");
|
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,61 +152,4 @@ public class DeviceRepository {
|
|||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private List<DeviceDescriptor> readJsonStream(String context) {
|
|
||||||
JsonReader reader = new JsonReader(new StringReader(context));
|
|
||||||
List<DeviceDescriptor> theDescriptors = null;
|
|
||||||
try {
|
|
||||||
theDescriptors = readDescriptorArray(reader);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading json array: " + context + " message: " + e.getMessage(), e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error closing json reader: " + context + " message: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return theDescriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<DeviceDescriptor> readDescriptorArray(JsonReader reader) throws IOException {
|
|
||||||
List<DeviceDescriptor> descriptors = new ArrayList<DeviceDescriptor>();
|
|
||||||
|
|
||||||
reader.beginArray();
|
|
||||||
while (reader.hasNext()) {
|
|
||||||
descriptors.add(readDescriptor(reader));
|
|
||||||
}
|
|
||||||
reader.endArray();
|
|
||||||
return descriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeviceDescriptor readDescriptor(JsonReader reader) throws IOException {
|
|
||||||
DeviceDescriptor deviceEntry = new DeviceDescriptor();
|
|
||||||
|
|
||||||
reader.beginObject();
|
|
||||||
while (reader.hasNext()) {
|
|
||||||
String name = reader.nextName();
|
|
||||||
if (name.equals("id")) {
|
|
||||||
deviceEntry.setId(reader.nextString());
|
|
||||||
log.debug("Read a Device - device json id: " + deviceEntry.getId());
|
|
||||||
} else if (name.equals("name")) {
|
|
||||||
deviceEntry.setName(reader.nextString());
|
|
||||||
log.debug("Read a Device - device json name: " + deviceEntry.getName());
|
|
||||||
} else if (name.equals("deviceType")) {
|
|
||||||
deviceEntry.setDeviceType(reader.nextString());
|
|
||||||
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
|
|
||||||
} else if (name.equals("offUrl")) {
|
|
||||||
deviceEntry.setOffUrl(reader.nextString());
|
|
||||||
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());
|
|
||||||
} else if (name.equals("onUrl")) {
|
|
||||||
deviceEntry.setOnUrl(reader.nextString());
|
|
||||||
log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl());
|
|
||||||
} else {
|
|
||||||
reader.skipValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader.endObject();
|
|
||||||
return deviceEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
src/main/java/com/bwssystems/HABridge/dao/ErrorMessage.java
Normal file
18
src/main/java/com/bwssystems/HABridge/dao/ErrorMessage.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
public class ErrorMessage {
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ErrorMessage(String message) {
|
||||||
|
super();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,33 @@
|
|||||||
package com.bwssystems.HABridge.devicemanagmeent;
|
package com.bwssystems.HABridge.devicemanagmeent;
|
||||||
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
|
import static spark.Spark.options;
|
||||||
import static spark.Spark.post;
|
import static spark.Spark.post;
|
||||||
import static spark.Spark.put;
|
import static spark.Spark.put;
|
||||||
import static spark.Spark.delete;
|
import static spark.Spark.delete;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettings;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||||
import com.bwssystems.luupRequests.Sdata;
|
import com.bwssystems.HABridge.dao.ErrorMessage;
|
||||||
import com.bwssystems.vera.VeraInfo;
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
|
import com.bwssystems.hal.HalHome;
|
||||||
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.bwssystems.hue.HueHome;
|
||||||
|
import com.bwssystems.luupRequests.Device;
|
||||||
|
import com.bwssystems.luupRequests.Scene;
|
||||||
|
import com.bwssystems.util.JsonTransformer;
|
||||||
|
import com.bwssystems.vera.VeraHome;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,16 +36,43 @@ import com.google.gson.Gson;
|
|||||||
public class DeviceResource {
|
public class DeviceResource {
|
||||||
private static final String API_CONTEXT = "/api/devices";
|
private static final String API_CONTEXT = "/api/devices";
|
||||||
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
||||||
|
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
private VeraInfo veraInfo;
|
private VeraHome veraHome;
|
||||||
|
private HarmonyHome myHarmonyHome;
|
||||||
|
private NestHome nestHome;
|
||||||
|
private HueHome hueHome;
|
||||||
|
private HalHome halHome;
|
||||||
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||||
|
|
||||||
|
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, HalHome aHalHome) {
|
||||||
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
|
|
||||||
public DeviceResource(BridgeSettings theSettings) {
|
if(theSettings.isValidVera())
|
||||||
super();
|
this.veraHome = new VeraHome(theSettings);
|
||||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
else
|
||||||
veraInfo = new VeraInfo(theSettings.getVeraAddress());
|
this.veraHome = null;
|
||||||
setupEndpoints();
|
|
||||||
|
if(theSettings.isValidHarmony())
|
||||||
|
this.myHarmonyHome = theHarmonyHome;
|
||||||
|
else
|
||||||
|
this.myHarmonyHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidNest())
|
||||||
|
this.nestHome = aNestHome;
|
||||||
|
else
|
||||||
|
this.nestHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidHue())
|
||||||
|
this.hueHome = aHueHome;
|
||||||
|
else
|
||||||
|
this.hueHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidHal())
|
||||||
|
this.halHome = aHalHome;
|
||||||
|
else
|
||||||
|
this.halHome = null;
|
||||||
|
|
||||||
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceRepository getDeviceRepository() {
|
public DeviceRepository getDeviceRepository() {
|
||||||
@@ -42,43 +81,73 @@ public class DeviceResource {
|
|||||||
|
|
||||||
private void setupEndpoints() {
|
private void setupEndpoints() {
|
||||||
log.info("HABridge device management service started.... ");
|
log.info("HABridge device management service started.... ");
|
||||||
|
// http://ip_address:port/api/devices CORS request
|
||||||
|
options(API_CONTEXT, "application/json", (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, DELETE");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
post(API_CONTEXT, "application/json", (request, response) -> {
|
post(API_CONTEXT, "application/json", (request, response) -> {
|
||||||
log.debug("Create a Device - request body: " + request.body());
|
log.debug("Create a Device(s) - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor devices[];
|
||||||
DeviceDescriptor deviceEntry = new DeviceDescriptor();
|
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
|
||||||
deviceEntry.setName(device.getName());
|
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
|
||||||
log.debug("Create a Device - device json name: " + deviceEntry.getName());
|
}
|
||||||
deviceEntry.setDeviceType(device.getDeviceType());
|
else {
|
||||||
log.debug("Create a Device - device json type:" + deviceEntry.getDeviceType());
|
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
||||||
deviceEntry.setOnUrl(device.getOnUrl());
|
}
|
||||||
log.debug("Create a Device - device json on URL:" + deviceEntry.getOnUrl());
|
for(int i = 0; i < devices.length; i++) {
|
||||||
deviceEntry.setOffUrl(device.getOffUrl());
|
if(devices[i].getContentBody() != null ) {
|
||||||
log.debug("Create a Device - device json off URL:" + deviceEntry.getOffUrl());
|
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
|
||||||
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
deviceRepository.save(deviceEntry);
|
log.debug("Bad http verb in create a Device(s): " + request.body());
|
||||||
log.debug("Created a Device: " + request.body());
|
return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
|
||||||
|
}
|
||||||
response.status(201);
|
}
|
||||||
return deviceEntry;
|
}
|
||||||
|
|
||||||
|
deviceRepository.save(devices);
|
||||||
|
log.debug("Created a Device(s): " + request.body());
|
||||||
|
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.status(HttpStatus.SC_CREATED);
|
||||||
|
|
||||||
|
return devices;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/:id CORS request
|
||||||
|
options(API_CONTEXT + "/:id", "application/json", (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, DELETE");
|
||||||
|
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 + "/:id", "application/json", (request, response) -> {
|
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
|
log.debug("Edit a Device - request body: " + request.body());
|
||||||
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
||||||
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
|
if(deviceRepository.findOne(request.params(":id")) == null){
|
||||||
if(deviceEntry == null){
|
log.debug("Could not save an edited device, Device Id not found: " + request.params(":id"));
|
||||||
log.debug("Could not save an edited Device Id: " + request.params(":id"));
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||||
return null;
|
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
|
||||||
}
|
}
|
||||||
log.debug("Saving an edited Device: " + deviceEntry.getName());
|
else
|
||||||
|
{
|
||||||
deviceEntry.setName(device.getName());
|
log.debug("Saving an edited Device: " + device.getName());
|
||||||
if(device.getDeviceType() != null)
|
|
||||||
deviceEntry.setDeviceType(device.getDeviceType());
|
if (device.getDeviceType() != null)
|
||||||
deviceEntry.setOnUrl(device.getOnUrl());
|
device.setDeviceType(device.getDeviceType());
|
||||||
deviceEntry.setOffUrl(device.getOffUrl());
|
|
||||||
|
DeviceDescriptor[] theDevices = new DeviceDescriptor[1];
|
||||||
deviceRepository.save(deviceEntry);
|
theDevices[0] = device;
|
||||||
return deviceEntry;
|
deviceRepository.save(theDevices);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
return device;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT, "application/json", (request, response) -> {
|
get (API_CONTEXT, "application/json", (request, response) -> {
|
||||||
@@ -87,45 +156,191 @@ public class DeviceResource {
|
|||||||
JsonTransformer aRenderer = new JsonTransformer();
|
JsonTransformer aRenderer = new JsonTransformer();
|
||||||
String theStream = aRenderer.render(deviceList);
|
String theStream = aRenderer.render(deviceList);
|
||||||
log.debug("The Device List: " + theStream);
|
log.debug("The Device List: " + theStream);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return deviceList;
|
return deviceList;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Get a device");
|
log.debug("Get a device");
|
||||||
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
|
||||||
if(descriptor == null){
|
if(descriptor == null) {
|
||||||
return null;
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("Could not find, id: " + request.params(":id") + " ");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
||||||
log.debug("Delete a device");
|
String anId = request.params(":id");
|
||||||
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
|
log.debug("Delete a device: " + anId);
|
||||||
if(deleted == null){
|
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
||||||
return null;
|
if(deleted == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("Could not delete, id: " + anId + " not found. ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deviceRepository.delete(deleted);
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
}
|
}
|
||||||
deviceRepository.delete(deleted);
|
|
||||||
return null;
|
return null;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
||||||
log.debug("Get vera devices");
|
log.debug("Get vera devices");
|
||||||
Sdata sData = veraInfo.getSdata();
|
if(veraHome == null){
|
||||||
if(sData == null){
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return new ErrorMessage("A Vera is not available.");
|
||||||
}
|
}
|
||||||
return sData.getDevices();
|
List<Device> theDevices = veraHome.getDevices();
|
||||||
|
if(theDevices == null) {
|
||||||
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||||
|
return new ErrorMessage("A Vera request failed to get devices. Check your Vera IP addresses.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return theDevices;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/vera/scenes", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/vera/scenes", "application/json", (request, response) -> {
|
||||||
log.debug("Get vera scenes");
|
log.debug("Get vera scenes");
|
||||||
Sdata sData = veraInfo.getSdata();
|
if(veraHome == null){
|
||||||
if(sData == null){
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
return null;
|
return new ErrorMessage("A Vera is not available.");
|
||||||
}
|
}
|
||||||
return sData.getScenes();
|
List<Scene> theScenes = veraHome.getScenes();
|
||||||
|
if(theScenes == null) {
|
||||||
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||||
|
return new ErrorMessage("A Vera is not available and failed to get scenes. Check your Vera IP addresses.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return theScenes;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony activities");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Harmony is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getActivities();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony current activity");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Harmony is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getCurrentActivities();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get harmony devices");
|
||||||
|
if(myHarmonyHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Harmony is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return myHarmonyHome.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/nest/items", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get nest items");
|
||||||
|
if(nestHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Nest is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return nestHome.getItems();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/hue/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get hue items");
|
||||||
|
if(hueHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Hue is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return hueHome.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/hal/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get hal items");
|
||||||
|
if(halHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Hal is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return halHome.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get backup filenames");
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return deviceRepository.getBackups();
|
||||||
|
}, 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);
|
||||||
|
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/create", "application/json", (request, response) -> {
|
||||||
|
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()));
|
||||||
|
return returnFilename;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/delete CORS request
|
||||||
|
options(API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||||
|
log.debug("Delete backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null)
|
||||||
|
deviceRepository.deleteBackup(aFilename.getFilename());
|
||||||
|
else
|
||||||
|
log.warn("No filename given for delete backup.");
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
// http://ip_address:port/api/devices/backup/restore CORS request
|
||||||
|
options(API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
|
response.header("Access-Control-Allow-Methods", "POST");
|
||||||
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||||
|
response.header("Content-Type", "text/html; charset=utf-8");
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||||
|
log.debug("Restore backup: " + request.body());
|
||||||
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||||
|
if(aFilename != null) {
|
||||||
|
deviceRepository.restoreBackup(aFilename.getFilename());
|
||||||
|
deviceRepository.loadRepository();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("No filename given for restore backup.");
|
||||||
|
return null;
|
||||||
|
}, new JsonTransformer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,9 @@ package com.bwssystems.HABridge.upnp;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettings;
|
import com.bwssystems.HABridge.BridgeControlDescriptor;
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.Configuration;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
@@ -14,104 +16,206 @@ import org.apache.http.conn.util.*;
|
|||||||
|
|
||||||
public class UpnpListener {
|
public class UpnpListener {
|
||||||
private Logger log = LoggerFactory.getLogger(UpnpListener.class);
|
private Logger log = LoggerFactory.getLogger(UpnpListener.class);
|
||||||
private static final int UPNP_DISCOVERY_PORT = 1900;
|
|
||||||
private static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
|
|
||||||
|
|
||||||
private int upnpResponsePort;
|
private int upnpResponsePort;
|
||||||
|
|
||||||
private int httpServerPort;
|
private int httpServerPort;
|
||||||
|
|
||||||
private String responseAddress;
|
private String responseAddress;
|
||||||
|
private boolean strict;
|
||||||
public UpnpListener(BridgeSettings theSettings) {
|
private boolean traceupnp;
|
||||||
super();
|
private BridgeControlDescriptor bridgeControl;
|
||||||
upnpResponsePort = Integer.valueOf(theSettings.getUpnpResponsePort());
|
private boolean discoveryTemplateLatest;
|
||||||
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||||
responseAddress = theSettings.getUpnpConfigAddress();
|
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||||
}
|
"EXT:\r\n" +
|
||||||
|
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||||
public void startListening(){
|
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.10.0\r\n" +
|
||||||
log.info("UPNP Discovery Listener started....");
|
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||||
|
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||||
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
|
private String discoveryTemplateOld = "HTTP/1.1 200 OK\r\n" +
|
||||||
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
|
|
||||||
InetSocketAddress socketAddress = new InetSocketAddress(UPNP_MULTICAST_ADDRESS, UPNP_DISCOVERY_PORT);
|
|
||||||
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
|
|
||||||
|
|
||||||
while (ifs.hasMoreElements()) {
|
|
||||||
NetworkInterface xface = ifs.nextElement();
|
|
||||||
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
|
||||||
String name = xface.getName();
|
|
||||||
int IPsPerNic = 0;
|
|
||||||
|
|
||||||
while (addrs.hasMoreElements()) {
|
|
||||||
InetAddress addr = addrs.nextElement();
|
|
||||||
log.debug(name + " ... has addr " + addr);
|
|
||||||
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
|
||||||
IPsPerNic++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("Checking " + name + " to our interface set");
|
|
||||||
if (IPsPerNic > 0) {
|
|
||||||
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
|
||||||
log.debug("Adding " + name + " to our interface set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(true){ //trigger shutdown here
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
|
||||||
upnpMulticastSocket.receive(packet);
|
|
||||||
String packetString = new String(packet.getData());
|
|
||||||
if(isSSDPDiscovery(packetString)){
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
log.error("could not sleep");
|
|
||||||
}
|
|
||||||
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
|
||||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("UpnpListener encountered an error. Shutting down", e);
|
|
||||||
|
|
||||||
}
|
|
||||||
log.info("UPNP Discovery Listener Stopped");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* very naive ssdp discovery packet detection
|
|
||||||
* @param body
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected boolean isSSDPDiscovery(String body){
|
|
||||||
// log.debug("Check if this is a MAN ssdp-discover packet for a upnp basic device: " + body);
|
|
||||||
//Only respond to discover request for upnp basic device from echo, the others are for the wemo
|
|
||||||
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")&& body.contains("ST: urn:schemas-upnp-org:device:basic:1")){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
|
||||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||||
"EXT:\r\n" +
|
"EXT:\r\n" +
|
||||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
|
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
|
||||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||||
|
|
||||||
|
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
|
||||||
|
super();
|
||||||
|
upnpResponsePort = theSettings.getUpnpResponsePort();
|
||||||
|
httpServerPort = Integer.valueOf(theSettings.getServerPort());
|
||||||
|
responseAddress = theSettings.getUpnpConfigAddress();
|
||||||
|
strict = theSettings.isUpnpStrict();
|
||||||
|
traceupnp = theSettings.isTraceupnp();
|
||||||
|
bridgeControl = theControl;
|
||||||
|
discoveryTemplateLatest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
public boolean startListening(){
|
||||||
|
log.info("UPNP Discovery Listener starting....");
|
||||||
|
DatagramSocket responseSocket = null;
|
||||||
|
MulticastSocket upnpMulticastSocket = null;
|
||||||
|
Enumeration<NetworkInterface> ifs = null;
|
||||||
|
|
||||||
|
boolean portLoopControl = true;
|
||||||
|
int retryCount = 0;
|
||||||
|
while(portLoopControl) {
|
||||||
|
try {
|
||||||
|
responseSocket = new DatagramSocket(upnpResponsePort);
|
||||||
|
if(retryCount > 0)
|
||||||
|
log.info("Upnp Response Port issue, found open port: " + upnpResponsePort);
|
||||||
|
portLoopControl = false;
|
||||||
|
} catch(SocketException e) {
|
||||||
|
if(retryCount == 0)
|
||||||
|
log.warn("Upnp Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + upnpResponsePort);
|
||||||
|
if(retryCount >= 20) {
|
||||||
|
portLoopControl = false;
|
||||||
|
log.error("Upnp Response Port issue, could not find open port - last port tried: " + upnpResponsePort + " with message: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(portLoopControl) {
|
||||||
|
retryCount++;
|
||||||
|
upnpResponsePort++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT);
|
||||||
|
try {
|
||||||
|
ifs = NetworkInterface.getNetworkInterfaces();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Could not get network interfaces for this machine: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ifs.hasMoreElements()) {
|
||||||
|
NetworkInterface xface = ifs.nextElement();
|
||||||
|
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
||||||
|
String name = xface.getName();
|
||||||
|
int IPsPerNic = 0;
|
||||||
|
|
||||||
|
while (addrs.hasMoreElements()) {
|
||||||
|
InetAddress addr = addrs.nextElement();
|
||||||
|
if (traceupnp)
|
||||||
|
log.info("Traceupnp: " + name + " ... has addr " + addr);
|
||||||
|
else
|
||||||
|
log.debug(name + " ... has addr " + addr);
|
||||||
|
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
||||||
|
IPsPerNic++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("Checking " + name + " to our interface set");
|
||||||
|
if (IPsPerNic > 0) {
|
||||||
|
try {
|
||||||
|
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
||||||
|
if (traceupnp)
|
||||||
|
log.info("Traceupnp: Adding " + name + " to our interface set");
|
||||||
|
else
|
||||||
|
log.debug("Adding " + name + " to our interface set");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Multicast join failed for: " + socketAddress.getHostName() + " to interface: "
|
||||||
|
+ xface.getName() + " with message: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("UPNP Discovery Listener running and ready....");
|
||||||
|
boolean loopControl = true;
|
||||||
|
boolean error = false;
|
||||||
|
while (loopControl) { // trigger shutdown here
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
|
try {
|
||||||
|
upnpMulticastSocket.receive(packet);
|
||||||
|
if (isSSDPDiscovery(packet)) {
|
||||||
|
try {
|
||||||
|
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("UpnpListener encountered an error sending upnp response packet. Shutting down", e);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("UpnpListener encountered an error reading socket. Shutting down", e);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
if (error || bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
upnpMulticastSocket.close();
|
||||||
|
responseSocket.close();
|
||||||
|
if (bridgeControl.isReinit())
|
||||||
|
log.info("UPNP Discovery Listener - ended, restart found");
|
||||||
|
if (bridgeControl.isStop())
|
||||||
|
log.info("UPNP Discovery Listener - ended, stop found");
|
||||||
|
if (!bridgeControl.isStop() && !bridgeControl.isReinit()) {
|
||||||
|
log.info("UPNP Discovery Listener - ended, error found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return bridgeControl.isReinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssdp discovery packet detection
|
||||||
|
*/
|
||||||
|
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\"")){
|
||||||
|
log.debug("isSSDPDiscovery Found message to be an M-SEARCH message.");
|
||||||
|
log.debug("isSSDPDiscovery Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
|
||||||
|
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: isSSDPDiscovery found message to be an M-SEARCH message.");
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
|
||||||
|
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
}
|
||||||
|
log.debug("isSSDPDiscovery found message to be valid under strict rules - strict: " + strict);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!strict)
|
||||||
|
{
|
||||||
|
if(traceupnp) {
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message.");
|
||||||
|
log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
|
||||||
|
log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString);
|
||||||
|
}
|
||||||
|
log.debug("isSSDPDiscovery found message to be valid under loose rules - strict: " + strict);
|
||||||
|
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(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||||
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
|
String discoveryResponse = null;
|
||||||
log.debug("sndUpnpResponse: " + discoveryResponse);
|
if(discoveryTemplateLatest)
|
||||||
|
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||||
|
else
|
||||||
|
discoveryResponse = String.format(discoveryTemplateOld, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort);
|
||||||
|
if(traceupnp)
|
||||||
|
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
|
||||||
|
else
|
||||||
|
log.debug("sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
|
||||||
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
|
||||||
socket.send(response);
|
socket.send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getRandomUUIDString(){
|
|
||||||
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ package com.bwssystems.HABridge.upnp;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettings;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
import com.bwssystems.HABridge.JsonTransformer;
|
|
||||||
|
|
||||||
import static spark.Spark.get;
|
import static spark.Spark.get;
|
||||||
|
|
||||||
@@ -12,57 +11,103 @@ import static spark.Spark.get;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class UpnpSettingsResource {
|
public class UpnpSettingsResource {
|
||||||
private static final String UPNP_CONTEXT = "/upnp";
|
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
|
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
|
||||||
|
|
||||||
|
private BridgeSettingsDescriptor theSettings;
|
||||||
|
|
||||||
private String hueTemplate = "<?xml version=\"1.0\"?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
|
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||||
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
|
+ "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
|
||||||
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
|
+ "<specVersion>\n"
|
||||||
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
+ "<major>1</major>\n"
|
||||||
+ "<friendlyName>HA-Bridge (%s)</friendlyName>\n"
|
+ "<minor>0</minor>\n"
|
||||||
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n"
|
+ "</specVersion>\n"
|
||||||
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n"
|
+ "<URLBase>http://%s:%s/</URLBase>\n"
|
||||||
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n"
|
+ "<device>\n"
|
||||||
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
|
+ "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
|
||||||
+ "<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n"
|
+ "<friendlyName>Philips hue (%s)</friendlyName>\n"
|
||||||
+ "<serialNumber>01189998819991197253</serialNumber>\n"
|
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n"
|
||||||
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
|
+ "<manufacturerURL>http://www.philips.com</manufacturerURL>\n"
|
||||||
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
|
+ "<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>\n"
|
||||||
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
|
+ "<modelName>Philips hue bridge 2015</modelName>\n"
|
||||||
+ "<SCPDURL>(null)</SCPDURL>\n" + "</service>\n" + "</serviceList>\n"
|
+ "<modelNumber>BSB002</modelNumber>\n"
|
||||||
+ "<presentationURL>index.html</presentationURL>\n" + "<iconList>\n" + "<icon>\n"
|
+ "<modelURL>http://www.meethue.com</modelURL>\n"
|
||||||
+ "<mimetype>image/png</mimetype>\n" + "<height>48</height>\n" + "<width>48</width>\n"
|
+ "<serialNumber>0017880ae670</serialNumber>\n"
|
||||||
+ "<depth>24</depth>\n" + "<url>hue_logo_0.png</url>\n" + "</icon>\n" + "<icon>\n"
|
+ "<UDN>uuid:2f402f80-da50-11e1-9b23-001788102201</UDN>\n"
|
||||||
+ "<mimetype>image/png</mimetype>\n" + "<height>120</height>\n" + "<width>120</width>\n"
|
+ "<serviceList>\n"
|
||||||
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\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"
|
||||||
|
+ "<presentationURL>index.html</presentationURL>\n"
|
||||||
|
+ "<iconList>\n"
|
||||||
|
+ "<icon>\n"
|
||||||
|
+ "<mimetype>image/png</mimetype>\n"
|
||||||
|
+ "<height>48</height>\n"
|
||||||
|
+ "<width>48</width>\n"
|
||||||
|
+ "<depth>24</depth>\n"
|
||||||
|
+ "<url>hue_logo_0.png</url>\n"
|
||||||
|
+ "</icon>\n"
|
||||||
|
+ "<icon>\n"
|
||||||
|
+ "<mimetype>image/png</mimetype>\n"
|
||||||
|
+ "<height>120</height>\n"
|
||||||
|
+ "<width>120</width>\n"
|
||||||
|
+ "<depth>24</depth>\n"
|
||||||
|
+ "<url>hue_logo_3.png</url>\n"
|
||||||
|
+ "</icon>\n"
|
||||||
|
+ "</iconList>\n"
|
||||||
|
+ "</device>\n"
|
||||||
+ "</root>\n";
|
+ "</root>\n";
|
||||||
|
|
||||||
public UpnpSettingsResource(BridgeSettings theSettings) {
|
public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) {
|
||||||
super();
|
super();
|
||||||
setupListener(theSettings);
|
this.theSettings = theBridgeSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupListener (BridgeSettings theSettings) {
|
public void setupServer() {
|
||||||
log.info("Hue description service started....");
|
log.info("Hue description service started....");
|
||||||
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
|
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
|
||||||
get("/description.xml", "application/xml", (request, response) -> {
|
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip());
|
if(theSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
|
||||||
|
else
|
||||||
|
log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
|
||||||
String portNumber = Integer.toString(request.port());
|
String portNumber = Integer.toString(request.port());
|
||||||
String filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
String filledTemplate = null;
|
||||||
log.debug("upnp device settings response: " + filledTemplate);
|
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
|
||||||
response.status(201);
|
if(theSettings.isTraceupnp())
|
||||||
|
log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber);
|
||||||
|
else
|
||||||
|
log.debug("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + 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");
|
||||||
|
// response.header("Connection", "close"); // Not sure if the server will actually close the connections by just setting the header
|
||||||
|
// response.header("Access-Control-Max-Age", "0");
|
||||||
|
// response.header("Access-Control-Allow-Origin", "*");
|
||||||
|
// response.header("Access-Control-Allow-Credentials", "true");
|
||||||
|
// response.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
|
||||||
|
// response.header("Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
// response.header("Content-Type", "application/xml; charset=utf-8");
|
||||||
|
response.type("application/xml; charset=utf-8");
|
||||||
|
response.status(200);
|
||||||
|
|
||||||
return filledTemplate;
|
return filledTemplate;
|
||||||
} );
|
} );
|
||||||
|
// http://ip_adress:port/favicon.ico
|
||||||
// http://ip_address:port/upnp/settings which returns the bridge configuration settings
|
get("/favicon.ico", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
get(UPNP_CONTEXT + "/settings", "application/json", (request, response) -> {
|
return "";
|
||||||
log.debug("bridge settings requested from " + request.ip());
|
} );
|
||||||
|
// http://ip_adress:port/hue_logo_0.png
|
||||||
response.status(201);
|
get("/hue_logo_0.png", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
|
return "";
|
||||||
return theSettings;
|
} );
|
||||||
}, new JsonTransformer());
|
// http://ip_adress:port/hue_logo_3.png
|
||||||
|
get("/hue_logo_3.png", "application/xml; charset=utf-8", (request, response) -> {
|
||||||
|
return "";
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/main/java/com/bwssystems/NestBridge/NestHome.java
Normal file
110
src/main/java/com/bwssystems/NestBridge/NestHome.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.nest.controller.Home;
|
||||||
|
import com.bwssystems.nest.controller.Nest;
|
||||||
|
import com.bwssystems.nest.controller.NestSession;
|
||||||
|
import com.bwssystems.nest.controller.Thermostat;
|
||||||
|
import com.bwssystems.nest.protocol.error.LoginException;
|
||||||
|
import com.bwssystems.nest.protocol.status.WhereDetail;
|
||||||
|
import com.bwssystems.nest.protocol.status.WhereItem;
|
||||||
|
|
||||||
|
public class NestHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NestHome.class);
|
||||||
|
private NestSession theSession;
|
||||||
|
private Nest theNest;
|
||||||
|
private ArrayList<NestItem> nestItems;
|
||||||
|
|
||||||
|
public NestHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
theSession = null;
|
||||||
|
theNest = null;
|
||||||
|
nestItems = null;
|
||||||
|
|
||||||
|
if(!bridgeSettings.isValidNest()) {
|
||||||
|
log.debug("not a valid nest");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
theSession = new NestSession(bridgeSettings.getNestuser(), bridgeSettings.getNestpwd());
|
||||||
|
theNest = new Nest(theSession);
|
||||||
|
} catch (LoginException e) {
|
||||||
|
log.error("Caught Login Exception, exiting....");
|
||||||
|
theSession = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NestItem> getItems() {
|
||||||
|
if(theNest == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if(nestItems == null) {
|
||||||
|
nestItems = new ArrayList<NestItem>();
|
||||||
|
Set<String> homeNames = theNest.getHomeNames();
|
||||||
|
Home aHome = null;
|
||||||
|
NestItem anItem = null;
|
||||||
|
for(String name : homeNames) {
|
||||||
|
aHome = theNest.getHome(name);
|
||||||
|
anItem = new NestItem();
|
||||||
|
anItem.setId(name);
|
||||||
|
anItem.setName(aHome.getDetail().getName());
|
||||||
|
anItem.setType("Home");
|
||||||
|
anItem.setLocation(aHome.getDetail().getLocation());
|
||||||
|
nestItems.add(anItem);
|
||||||
|
}
|
||||||
|
Thermostat thermo = null;
|
||||||
|
Set<String> thermoNames = theNest.getThermostatNames();
|
||||||
|
for(String name : thermoNames) {
|
||||||
|
thermo = theNest.getThermostat(name);
|
||||||
|
anItem = new NestItem();
|
||||||
|
anItem.setId(name);
|
||||||
|
anItem.setType("Thermostat");
|
||||||
|
String where = null;
|
||||||
|
String homeName= null;
|
||||||
|
Boolean found = false;
|
||||||
|
for(String aHomeName : homeNames) {
|
||||||
|
WhereDetail aDetail = theNest.getWhere(aHomeName);
|
||||||
|
ListIterator<WhereItem> anIterator = aDetail.getWheres().listIterator();
|
||||||
|
while(anIterator.hasNext()) {
|
||||||
|
WhereItem aWhereItem = (WhereItem) anIterator.next();
|
||||||
|
if(aWhereItem.getWhereId().equals(thermo.getDeviceDetail().getWhereId())) {
|
||||||
|
where = aWhereItem.getName();
|
||||||
|
homeName = theNest.getHome(aHomeName).getDetail().getName();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
anItem.setName(where + "(" + name.substring(name.length() - 4) + ")");
|
||||||
|
anItem.setLocation(where + " - " + homeName);
|
||||||
|
nestItems.add(anItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nestItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Nest getTheNest() {
|
||||||
|
return theNest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeTheNest() {
|
||||||
|
if(theSession != null) {
|
||||||
|
theNest.endNestSession();
|
||||||
|
theNest = null;
|
||||||
|
theSession = null;
|
||||||
|
nestItems = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
33
src/main/java/com/bwssystems/NestBridge/NestInstruction.java
Normal file
33
src/main/java/com/bwssystems/NestBridge/NestInstruction.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
public class NestInstruction {
|
||||||
|
private String name;
|
||||||
|
private Boolean away;
|
||||||
|
private String control;
|
||||||
|
private String temp;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Boolean getAway() {
|
||||||
|
return away;
|
||||||
|
}
|
||||||
|
public void setAway(Boolean away) {
|
||||||
|
this.away = away;
|
||||||
|
}
|
||||||
|
public String getControl() {
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
public void setControl(String control) {
|
||||||
|
this.control = control;
|
||||||
|
}
|
||||||
|
public String getTemp() {
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
public void setTemp(String temp) {
|
||||||
|
this.temp = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/com/bwssystems/NestBridge/NestItem.java
Normal file
41
src/main/java/com/bwssystems/NestBridge/NestItem.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package com.bwssystems.NestBridge;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
public class NestItem {
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
private String type;
|
||||||
|
private String location;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
byte ptext[];
|
||||||
|
String theLabel = new String(name);
|
||||||
|
try {
|
||||||
|
ptext = theLabel.getBytes("ISO-8859-1");
|
||||||
|
this.name = new String(ptext, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
this.name = theLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(String anid) {
|
||||||
|
id = anid;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceElements.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class DeviceElements {
|
||||||
|
@SerializedName(value="DeviceElements", alternate={"SceneElements", "GroupElements", "HVACElements", "MacroElements", "IrElements", "IrButtons"})
|
||||||
|
private List<DeviceName> DeviceElements;
|
||||||
|
|
||||||
|
public List<DeviceName> getDeviceElements() {
|
||||||
|
return DeviceElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceElements(List<DeviceName> deviceElements) {
|
||||||
|
DeviceElements = deviceElements;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
17
src/main/java/com/bwssystems/hal/DeviceName.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class DeviceName {
|
||||||
|
@SerializedName(value="DeviceName", alternate={"SceneName", "GroupName", "HVACName", "MacroName", "IrName", "IrButton"})
|
||||||
|
private String DeviceName;
|
||||||
|
|
||||||
|
public String getDeviceName() {
|
||||||
|
return DeviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceName(String deviceName) {
|
||||||
|
DeviceName = deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
39
src/main/java/com/bwssystems/hal/HalDevice.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
public class HalDevice {
|
||||||
|
private String haldevicetype;
|
||||||
|
private String haldevicename;
|
||||||
|
private String haladdress;
|
||||||
|
private String halname;
|
||||||
|
private DeviceElements buttons;
|
||||||
|
public String getHaldevicetype() {
|
||||||
|
return haldevicetype;
|
||||||
|
}
|
||||||
|
public void setHaldevicetype(String haldevicetype) {
|
||||||
|
this.haldevicetype = haldevicetype;
|
||||||
|
}
|
||||||
|
public String getHaldevicename() {
|
||||||
|
return haldevicename;
|
||||||
|
}
|
||||||
|
public void setHaldevicename(String haldevicename) {
|
||||||
|
this.haldevicename = haldevicename;
|
||||||
|
}
|
||||||
|
public String getHaladdress() {
|
||||||
|
return haladdress;
|
||||||
|
}
|
||||||
|
public void setHaladdress(String haladdress) {
|
||||||
|
this.haladdress = haladdress;
|
||||||
|
}
|
||||||
|
public String getHalname() {
|
||||||
|
return halname;
|
||||||
|
}
|
||||||
|
public void setHalname(String halname) {
|
||||||
|
this.halname = halname;
|
||||||
|
}
|
||||||
|
public DeviceElements getButtons() {
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
public void setButtons(DeviceElements buttons) {
|
||||||
|
this.buttons = buttons;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
113
src/main/java/com/bwssystems/hal/HalHome.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
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.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
|
||||||
|
public class HalHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
|
||||||
|
private Map<String, HalInfo> hals;
|
||||||
|
|
||||||
|
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
super();
|
||||||
|
hals = new HashMap<String, HalInfo>();
|
||||||
|
if(!bridgeSettings.isValidHal())
|
||||||
|
return;
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aHal = theList.next();
|
||||||
|
try {
|
||||||
|
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get harmony client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getDevices() {
|
||||||
|
log.debug("consolidating devices for hues");
|
||||||
|
List<HalDevice> theResponse = null;
|
||||||
|
Iterator<String> keys = hals.keySet().iterator();
|
||||||
|
List<HalDevice> deviceList = new ArrayList<HalDevice>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
theResponse = hals.get(key).getLights();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get lights for Hal with name: " + key + ", skipping this HAL.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
theResponse = hals.get(key).getAppliances();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get appliances for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getTheatre();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get theatre for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getCustom();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get custom for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getHVAC();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get HVAC for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getHome(key);
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get Homes for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getGroups();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get Groups for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getMacros();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get Macros for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getScenes();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get Scenes for Hal with name: " + key);
|
||||||
|
theResponse = hals.get(key).getButtons();
|
||||||
|
if(theResponse != null)
|
||||||
|
addHalDevices(deviceList, theResponse, key);
|
||||||
|
else
|
||||||
|
log.warn("Cannot get Buttons for Hal with name: " + key);
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
|
||||||
|
Iterator<HalDevice> devices = theSourceList.iterator();
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
HalDevice theDevice = devices.next();
|
||||||
|
HalDevice aNewHalDevice = new HalDevice();
|
||||||
|
aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype());
|
||||||
|
aNewHalDevice.setHaldevicename(theDevice.getHaldevicename());
|
||||||
|
aNewHalDevice.setButtons(theDevice.getButtons());
|
||||||
|
aNewHalDevice.setHaladdress(hals.get(theKey).getHalAddress().getIp());
|
||||||
|
aNewHalDevice.setHalname(theKey);
|
||||||
|
theDeviceList.add(aNewHalDevice);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
206
src/main/java/com/bwssystems/hal/HalInfo.java
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.util.TextStringFormatter;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class HalInfo {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HalInfo.class);
|
||||||
|
private static final String DEVICE_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType=";
|
||||||
|
private static final String HVAC_REQUEST = "/HVACData!HVACCmd=GetNames";
|
||||||
|
private static final String GROUP_REQUEST = "/GroupData!GroupCmd=GetNames";
|
||||||
|
private static final String MACRO_REQUEST = "/MacroData!MacroCmd=GetNames";
|
||||||
|
private static final String SCENE_REQUEST = "/SceneData!SceneCmd=GetNames";
|
||||||
|
private static final String IRDATA_REQUEST = "/IrData!IRCmd=GetNames";
|
||||||
|
private static final String IRBUTTON_REQUEST = "/IrData!IRCmd=GetButtons!IrDevice=";
|
||||||
|
private static final String TOKEN_REQUEST = "?Token=";
|
||||||
|
private static final String LIGHT_REQUEST = "Light";
|
||||||
|
private static final String APPL_REQUEST = "Appl";
|
||||||
|
// private static final String VIDEO_REQUEST = "Video";
|
||||||
|
private static final String THEATRE_REQUEST = "Theatre";
|
||||||
|
private static final String CUSTOM_REQUEST = "Custom";
|
||||||
|
private static final String HVAC_TYPE = "HVAC";
|
||||||
|
private static final String HOME_TYPE = "Home";
|
||||||
|
private static final String GROUP_TYPE = "Group";
|
||||||
|
private static final String MACRO_TYPE = "Macro";
|
||||||
|
private static final String SCENE_TYPE = "Scene";
|
||||||
|
private static final String IRDATA_TYPE = "IrData";
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private NamedIP halAddress;
|
||||||
|
private String theToken;
|
||||||
|
|
||||||
|
public HalInfo(NamedIP addressName, String aGivenToken) {
|
||||||
|
super();
|
||||||
|
httpClient = HttpClients.createDefault();
|
||||||
|
halAddress = addressName;
|
||||||
|
theToken = aGivenToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getLights() {
|
||||||
|
return getHalDevices(DEVICE_REQUEST + LIGHT_REQUEST + TOKEN_REQUEST, LIGHT_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getAppliances() {
|
||||||
|
return getHalDevices(DEVICE_REQUEST + APPL_REQUEST + TOKEN_REQUEST, APPL_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getTheatre() {
|
||||||
|
return getHalDevices(DEVICE_REQUEST + THEATRE_REQUEST + TOKEN_REQUEST, THEATRE_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getCustom() {
|
||||||
|
return getHalDevices(DEVICE_REQUEST + CUSTOM_REQUEST + TOKEN_REQUEST, CUSTOM_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getHVAC() {
|
||||||
|
return getHalDevices(HVAC_REQUEST + TOKEN_REQUEST, HVAC_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getGroups() {
|
||||||
|
return getHalDevices(GROUP_REQUEST + TOKEN_REQUEST, GROUP_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getMacros() {
|
||||||
|
return getHalDevices(MACRO_REQUEST + TOKEN_REQUEST, MACRO_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getScenes() {
|
||||||
|
return getHalDevices(SCENE_REQUEST + TOKEN_REQUEST, SCENE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getButtons() {
|
||||||
|
List<HalDevice> irDataDevices = getHalDevices(IRDATA_REQUEST + TOKEN_REQUEST, IRDATA_TYPE);
|
||||||
|
|
||||||
|
return getDeviceButtons(irDataDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HalDevice> getHome(String theDeviceName) {
|
||||||
|
List<HalDevice> deviceList = null;
|
||||||
|
deviceList = new ArrayList<HalDevice>();
|
||||||
|
HalDevice aNewHalDevice = new HalDevice();
|
||||||
|
aNewHalDevice.setHaldevicetype(HOME_TYPE);
|
||||||
|
aNewHalDevice.setHaldevicename(theDeviceName);
|
||||||
|
deviceList.add(aNewHalDevice);
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<HalDevice> getHalDevices(String apiType, String deviceType) {
|
||||||
|
DeviceElements theHalApiResponse = null;
|
||||||
|
List<HalDevice> deviceList = null;
|
||||||
|
|
||||||
|
String theUrl = null;
|
||||||
|
String theData;
|
||||||
|
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
|
||||||
|
theData = doHttpGETRequest(theUrl);
|
||||||
|
if(theData != null) {
|
||||||
|
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
|
||||||
|
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||||
|
if(theHalApiResponse.getDeviceElements() == null) {
|
||||||
|
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||||
|
if(theStatus.getStatus() == null) {
|
||||||
|
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: " + theStatus.getDescription());
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
deviceList = new ArrayList<HalDevice>();
|
||||||
|
|
||||||
|
Iterator<DeviceName> theDeviceNames = theHalApiResponse.getDeviceElements().iterator();
|
||||||
|
while(theDeviceNames.hasNext()) {
|
||||||
|
DeviceName theDevice = theDeviceNames.next();
|
||||||
|
HalDevice aNewHalDevice = new HalDevice();
|
||||||
|
aNewHalDevice.setHaldevicetype(deviceType);
|
||||||
|
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
|
||||||
|
deviceList.add(aNewHalDevice);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("Get Hal device types " + deviceType + " for " + halAddress.getName() + " - returned null, no data.");
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<HalDevice> getDeviceButtons(List<HalDevice> theIrDevices) {
|
||||||
|
DeviceElements theHalApiResponse = null;
|
||||||
|
List<HalDevice> deviceList = null;
|
||||||
|
|
||||||
|
String theUrl = null;
|
||||||
|
String theData;
|
||||||
|
if(theIrDevices == null)
|
||||||
|
return null;
|
||||||
|
Iterator<HalDevice> theHalDevices = theIrDevices.iterator();
|
||||||
|
deviceList = new ArrayList<HalDevice>();
|
||||||
|
while (theHalDevices.hasNext()) {
|
||||||
|
HalDevice theHalDevice = theHalDevices.next();
|
||||||
|
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
|
||||||
|
theData = doHttpGETRequest(theUrl);
|
||||||
|
if (theData != null) {
|
||||||
|
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
|
||||||
|
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
|
||||||
|
if (theHalApiResponse.getDeviceElements() == null) {
|
||||||
|
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
|
||||||
|
if (theStatus.getStatus() == null) {
|
||||||
|
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||||
|
+ halAddress.getName() + " as response is not parsable.");
|
||||||
|
} else {
|
||||||
|
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
|
||||||
|
+ halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: "
|
||||||
|
+ theStatus.getDescription());
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
theHalDevice.setButtons(theHalApiResponse);
|
||||||
|
deviceList.add(theHalDevice);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.warn("Get Hal buttons for IR Device " + theHalDevice.getHaldevicename() + " for "
|
||||||
|
+ halAddress.getName() + " - returned null, no data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function executes the url against the hal
|
||||||
|
protected String doHttpGETRequest(String url) {
|
||||||
|
String theContent = null;
|
||||||
|
log.debug("calling GET on URL: " + url);
|
||||||
|
HttpGet httpGet = new HttpGet(url);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(httpGet);
|
||||||
|
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return theContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedIP getHalAddress() {
|
||||||
|
return halAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHalAddress(NamedIP halAddress) {
|
||||||
|
this.halAddress = halAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
18
src/main/java/com/bwssystems/hal/StatusDescription.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.hal;
|
||||||
|
|
||||||
|
public class StatusDescription {
|
||||||
|
private String Status;
|
||||||
|
private String Description;
|
||||||
|
public String getStatus() {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
public void setStatus(String status) {
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
public String getDescription() {
|
||||||
|
return Description;
|
||||||
|
}
|
||||||
|
public void setDescription(String description) {
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
25
src/main/java/com/bwssystems/harmony/ButtonPress.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
public class ButtonPress {
|
||||||
|
private String device;
|
||||||
|
private String button;
|
||||||
|
public String getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(String device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
public String getButton() {
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
public void setButton(String button) {
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
public Boolean isValid() {
|
||||||
|
if (device != null && !device.isEmpty()){
|
||||||
|
if (button != null && !button.isEmpty())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
69
src/main/java/com/bwssystems/harmony/DevModeResponse.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||||
|
|
||||||
|
public class DevModeResponse {
|
||||||
|
final Logger log = LoggerFactory.getLogger(DevModeResponse.class);
|
||||||
|
|
||||||
|
private final static String powerOff = "PowerOff";
|
||||||
|
private HarmonyConfig harmonyConfig;
|
||||||
|
private Activity currentActivity;
|
||||||
|
|
||||||
|
public DevModeResponse() {
|
||||||
|
super();
|
||||||
|
harmonyConfig = HarmonyConfig.parse(dataReader("/config.data"));
|
||||||
|
this.currentActivity = harmonyConfig.getActivityByName(powerOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity getCurrentActivity() {
|
||||||
|
return currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentActivity(Activity currentActivity) {
|
||||||
|
this.currentActivity = currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Activity> getActivities() {
|
||||||
|
return harmonyConfig.getActivities();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
return harmonyConfig.getDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyConfig getConfig() {
|
||||||
|
return harmonyConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String dataReader(String filePath) {
|
||||||
|
|
||||||
|
String content = null;
|
||||||
|
try {
|
||||||
|
InputStream input = getClass().getResourceAsStream(filePath);
|
||||||
|
OutputStream out = new ByteArrayOutputStream();
|
||||||
|
int read;
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
|
||||||
|
while ((read = input.read(bytes)) != -1) {
|
||||||
|
out.write(bytes, 0, read);
|
||||||
|
}
|
||||||
|
content = out.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
31
src/main/java/com/bwssystems/harmony/HarmonyActivity.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
|
||||||
|
public class HarmonyActivity {
|
||||||
|
private String hub;
|
||||||
|
private Activity activity;
|
||||||
|
public String getHub() {
|
||||||
|
return hub;
|
||||||
|
}
|
||||||
|
public void setHub(String hub) {
|
||||||
|
this.hub = hub;
|
||||||
|
}
|
||||||
|
public Activity getActivity() {
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
public void setActivity(Activity activity) {
|
||||||
|
byte ptext[];
|
||||||
|
String theLabel = activity.getLabel();
|
||||||
|
try {
|
||||||
|
ptext = theLabel.getBytes("ISO-8859-1");
|
||||||
|
activity.setLabel(new String(ptext, "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
activity.setLabel(theLabel);
|
||||||
|
}
|
||||||
|
this.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
30
src/main/java/com/bwssystems/harmony/HarmonyDevice.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
|
||||||
|
public class HarmonyDevice {
|
||||||
|
private Device device;
|
||||||
|
private String hub;
|
||||||
|
public Device getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(Device device) {
|
||||||
|
byte ptext[];
|
||||||
|
String theLabel = device.getLabel();
|
||||||
|
try {
|
||||||
|
ptext = theLabel.getBytes("ISO-8859-1");
|
||||||
|
device.setLabel(new String(ptext, "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
device.setLabel(theLabel);
|
||||||
|
}
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
public String getHub() {
|
||||||
|
return hub;
|
||||||
|
}
|
||||||
|
public void setHub(String hub) {
|
||||||
|
this.hub = hub;
|
||||||
|
}
|
||||||
|
}
|
||||||
132
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
132
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.HarmonyClient;
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||||
|
|
||||||
|
public class HarmonyHandler {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||||
|
private HarmonyClient harmonyClient;
|
||||||
|
private Boolean noopCalls;
|
||||||
|
private Boolean devMode;
|
||||||
|
private DevModeResponse devResponse;
|
||||||
|
|
||||||
|
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
|
||||||
|
super();
|
||||||
|
noopCalls = noopCallsSetting;
|
||||||
|
devMode = Boolean.TRUE;
|
||||||
|
devResponse = null;
|
||||||
|
if(devResponseSetting == null)
|
||||||
|
devMode = Boolean.FALSE;
|
||||||
|
else
|
||||||
|
devResponse = devResponseSetting;
|
||||||
|
harmonyClient = theClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Activity> getActivities() {
|
||||||
|
log.debug("Harmony api activities list requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getActivities();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig().getActivities();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
log.debug("Harmony api device list requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getDevices();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig().getDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyConfig getConfig() {
|
||||||
|
log.debug("Harmony api config requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getConfig();
|
||||||
|
|
||||||
|
return harmonyClient.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity getCurrentActivity() {
|
||||||
|
log.debug("Harmony api current sctivity requested.");
|
||||||
|
if(devMode)
|
||||||
|
return devResponse.getCurrentActivity();
|
||||||
|
|
||||||
|
return harmonyClient.getCurrentActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean startActivity(RunActivity anActivity) {
|
||||||
|
log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls);
|
||||||
|
if (anActivity.isValid()) {
|
||||||
|
try {
|
||||||
|
if (noopCalls || devMode) {
|
||||||
|
if(devMode)
|
||||||
|
{
|
||||||
|
if(anActivity != null)
|
||||||
|
devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
harmonyClient.startActivity(Integer.parseInt(anActivity.getName()));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
if (!noopCalls)
|
||||||
|
harmonyClient.startActivityByName(anActivity.getName());
|
||||||
|
} catch (IllegalArgumentException ei) {
|
||||||
|
log.error("Error in finding activity: " + anActivity.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Error in finding activity: " + anActivity.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean pressButton(ButtonPress aDeviceButton) {
|
||||||
|
log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls);
|
||||||
|
if (aDeviceButton.isValid()) {
|
||||||
|
try {
|
||||||
|
if (noopCalls || devMode) {
|
||||||
|
log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton());
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
if (!noopCalls)
|
||||||
|
harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton());
|
||||||
|
} catch (IllegalArgumentException ei) {
|
||||||
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
log.debug("Harmony api shutdown requested.");
|
||||||
|
if(devMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
harmonyClient.disconnect();
|
||||||
|
harmonyClient = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
127
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
127
src/main/java/com/bwssystems/harmony/HarmonyHome.java
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.IpList;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.config.Device;
|
||||||
|
|
||||||
|
public class HarmonyHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
|
||||||
|
private Map<String, HarmonyServer> hubs;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
|
||||||
|
public HarmonyHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
super();
|
||||||
|
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||||
|
hubs = new HashMap<String, HarmonyServer>();
|
||||||
|
if(!bridgeSettings.isValidHarmony() && !isDevMode)
|
||||||
|
return;
|
||||||
|
if(isDevMode) {
|
||||||
|
NamedIP devModeIp = new NamedIP();
|
||||||
|
devModeIp.setIp("10.10.10.10");
|
||||||
|
devModeIp.setName("devMode");
|
||||||
|
List<NamedIP> theList = new ArrayList<NamedIP>();
|
||||||
|
theList.add(devModeIp);
|
||||||
|
IpList thedevList = new IpList();
|
||||||
|
thedevList.setDevices(theList);
|
||||||
|
bridgeSettings.setHarmonyAddress(thedevList);
|
||||||
|
}
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aHub = theList.next();
|
||||||
|
try {
|
||||||
|
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, isDevMode, aHub));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdownHarmonyHubs() {
|
||||||
|
if(isDevMode)
|
||||||
|
return;
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
hubs.get(key).getMyHarmony().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyHandler getHarmonyHandler(String aName) {
|
||||||
|
HarmonyHandler aHandler = null;
|
||||||
|
if(aName == null || aName.equals("")) {
|
||||||
|
aName = "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hubs.get(aName) == null) {
|
||||||
|
Set<String> keys = hubs.keySet();
|
||||||
|
if(!keys.isEmpty()) {
|
||||||
|
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aHandler = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aHandler = hubs.get(aName).getMyHarmony();
|
||||||
|
return aHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HarmonyActivity> getActivities() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
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>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
|
||||||
|
while(activities.hasNext()) {
|
||||||
|
HarmonyActivity anActivity = new HarmonyActivity();
|
||||||
|
anActivity.setActivity(activities.next());
|
||||||
|
anActivity.setHub(key);
|
||||||
|
activityList.add(anActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activityList;
|
||||||
|
}
|
||||||
|
public List<HarmonyDevice> getDevices() {
|
||||||
|
Iterator<String> keys = hubs.keySet().iterator();
|
||||||
|
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
86
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import net.whistlingfish.harmony.ActivityChangeListener;
|
||||||
|
import net.whistlingfish.harmony.HarmonyClient;
|
||||||
|
import net.whistlingfish.harmony.HarmonyClientModule;
|
||||||
|
import net.whistlingfish.harmony.config.Activity;
|
||||||
|
import net.whistlingfish.harmony.protocol.OAReplyProvider;
|
||||||
|
|
||||||
|
public class HarmonyServer {
|
||||||
|
@Inject
|
||||||
|
private HarmonyClient harmonyClient;
|
||||||
|
|
||||||
|
private HarmonyHandler myHarmony;
|
||||||
|
private DevModeResponse devResponse;
|
||||||
|
private OAReplyProvider dummyProvider;
|
||||||
|
private NamedIP myNameAndIP;
|
||||||
|
private Boolean isDevMode;
|
||||||
|
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||||
|
|
||||||
|
public HarmonyServer(NamedIP theHarmonyAddress) {
|
||||||
|
super();
|
||||||
|
myHarmony = null;
|
||||||
|
dummyProvider = null;
|
||||||
|
myNameAndIP = theHarmonyAddress;
|
||||||
|
isDevMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HarmonyServer setup(BridgeSettingsDescriptor bridgeSettings, Boolean harmonyDevMode, NamedIP theHarmonyAddress) throws Exception {
|
||||||
|
if(!bridgeSettings.isValidHarmony() && harmonyDevMode) {
|
||||||
|
return new HarmonyServer(theHarmonyAddress);
|
||||||
|
}
|
||||||
|
Injector injector = null;
|
||||||
|
if(!harmonyDevMode)
|
||||||
|
injector = Guice.createInjector(new HarmonyClientModule());
|
||||||
|
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
|
||||||
|
if(!harmonyDevMode)
|
||||||
|
injector.injectMembers(mainObject);
|
||||||
|
mainObject.execute(bridgeSettings, harmonyDevMode);
|
||||||
|
return mainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
|
||||||
|
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||||
|
isDevMode = harmonyDevMode;
|
||||||
|
String modeString = "";
|
||||||
|
if(dummyProvider != null)
|
||||||
|
log.debug("something is very wrong as dummyProvider is not null...");
|
||||||
|
if(isDevMode)
|
||||||
|
modeString = " (development mode)";
|
||||||
|
else if(noopCalls)
|
||||||
|
modeString = " (no op calls to harmony)";
|
||||||
|
log.info("setup initiated " + modeString + "....");
|
||||||
|
if(isDevMode)
|
||||||
|
{
|
||||||
|
harmonyClient = null;
|
||||||
|
devResponse = new DevModeResponse();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
devResponse = null;
|
||||||
|
harmonyClient.addListener(new ActivityChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void activityStarted(Activity activity) {
|
||||||
|
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
harmonyClient.connect(myNameAndIP.getIp(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||||
|
}
|
||||||
|
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HarmonyHandler getMyHarmony() {
|
||||||
|
return myHarmony;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
18
src/main/java/com/bwssystems/harmony/RunActivity.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.harmony;
|
||||||
|
|
||||||
|
public class RunActivity {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Boolean isValid() {
|
||||||
|
if (name != null && !name.isEmpty())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main/java/com/bwssystems/hue/HueDevice.java
Normal file
35
src/main/java/com/bwssystems/hue/HueDevice.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
|
||||||
|
|
||||||
|
public class HueDevice {
|
||||||
|
private DeviceResponse device;
|
||||||
|
private String huedeviceid;
|
||||||
|
private String hueaddress;
|
||||||
|
private String huename;
|
||||||
|
public DeviceResponse getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(DeviceResponse adevice) {
|
||||||
|
this.device = adevice;
|
||||||
|
}
|
||||||
|
public String getHuedeviceid() {
|
||||||
|
return huedeviceid;
|
||||||
|
}
|
||||||
|
public void setHuedeviceid(String huedeviceid) {
|
||||||
|
this.huedeviceid = huedeviceid;
|
||||||
|
}
|
||||||
|
public String getHueaddress() {
|
||||||
|
return hueaddress;
|
||||||
|
}
|
||||||
|
public void setHueaddress(String ahueaddress) {
|
||||||
|
this.hueaddress = ahueaddress;
|
||||||
|
}
|
||||||
|
public String getHuename() {
|
||||||
|
return huename;
|
||||||
|
}
|
||||||
|
public void setHuename(String ahuename) {
|
||||||
|
this.huename = ahuename;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/hue/HueDeviceIdentifier.java
Normal file
18
src/main/java/com/bwssystems/hue/HueDeviceIdentifier.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
public class HueDeviceIdentifier {
|
||||||
|
private String ipAddress;
|
||||||
|
private String deviceId;
|
||||||
|
public String getIpAddress() {
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
public void setIpAddress(String ipAddress) {
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
}
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
public interface HueErrorStringSet {
|
||||||
|
public void setErrorString(String anError);
|
||||||
|
}
|
||||||
73
src/main/java/com/bwssystems/hue/HueHome.java
Normal file
73
src/main/java/com/bwssystems/hue/HueHome.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
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.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
|
|
||||||
|
public class HueHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueHome.class);
|
||||||
|
private Map<String, HueInfo> hues;
|
||||||
|
private String theHUERegisteredUser;
|
||||||
|
|
||||||
|
public HueHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
hues = new HashMap<String, HueInfo>();
|
||||||
|
if(!bridgeSettings.isValidHue())
|
||||||
|
return;
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getHueaddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aHue = theList.next();
|
||||||
|
hues.put(aHue.getName(), new HueInfo(aHue, this));
|
||||||
|
}
|
||||||
|
theHUERegisteredUser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HueDevice> getDevices() {
|
||||||
|
log.debug("consolidating devices for hues");
|
||||||
|
Iterator<String> keys = hues.keySet().iterator();
|
||||||
|
ArrayList<HueDevice> deviceList = new ArrayList<HueDevice>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
HueApiResponse theResponse = hues.get(key).getHueApiResponse();
|
||||||
|
if(theResponse != null) {
|
||||||
|
Map<String, DeviceResponse> theDevices = theResponse.getLights();
|
||||||
|
if(theDevices != null) {
|
||||||
|
Iterator<String> deviceKeys = theDevices.keySet().iterator();
|
||||||
|
while(deviceKeys.hasNext()) {
|
||||||
|
String theDeviceKey = deviceKeys.next();
|
||||||
|
HueDevice aNewHueDevice = new HueDevice();
|
||||||
|
aNewHueDevice.setDevice(theDevices.get(theDeviceKey));
|
||||||
|
aNewHueDevice.setHuedeviceid(theDeviceKey);
|
||||||
|
aNewHueDevice.setHueaddress(hues.get(key).getHueAddress().getIp());
|
||||||
|
aNewHueDevice.setHuename(key);
|
||||||
|
deviceList.add(aNewHueDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deviceList = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("Cannot get lights for Hue with name: " + key);
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTheHUERegisteredUser() {
|
||||||
|
return theHUERegisteredUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTheHUERegisteredUser(String theHUERegisteredUser) {
|
||||||
|
this.theHUERegisteredUser = theHUERegisteredUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
111
src/main/java/com/bwssystems/hue/HueInfo.java
Normal file
111
src/main/java/com/bwssystems/hue/HueInfo.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
|
||||||
|
public class HueInfo implements HueErrorStringSet {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueInfo.class);
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private NamedIP hueAddress;
|
||||||
|
private String theUser;
|
||||||
|
private HueHome theHueHome;
|
||||||
|
private String errorString = null;
|
||||||
|
|
||||||
|
public HueInfo(NamedIP addressName, HueHome aHueHome) {
|
||||||
|
super();
|
||||||
|
httpClient = HttpClients.createDefault();
|
||||||
|
hueAddress = addressName;
|
||||||
|
theUser = "habridge";
|
||||||
|
theHueHome = aHueHome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueApiResponse getHueApiResponse() {
|
||||||
|
HueApiResponse theHueApiResponse = null;
|
||||||
|
|
||||||
|
String theUrl = "http://" + hueAddress.getIp() + HueUtil.HUE_REQUEST + "/" + theUser;
|
||||||
|
String theData;
|
||||||
|
boolean loopControl = true;
|
||||||
|
int retryCount = 0;
|
||||||
|
while(loopControl) {
|
||||||
|
if(retryCount > 3) {
|
||||||
|
log.warn("Max Retry reached to get Hue data from " + hueAddress.getName());
|
||||||
|
loopControl = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
theUrl = "http://" + hueAddress.getIp() + HueUtil.HUE_REQUEST + "/" + theUser;
|
||||||
|
theData = doHttpGETRequest(theUrl);
|
||||||
|
if(theData != null) {
|
||||||
|
log.debug("GET HueApiResponse - data: " + theData);
|
||||||
|
if(theData.contains("[{\"error\":")) {
|
||||||
|
if(theData.contains("unauthorized user")) {
|
||||||
|
theUser = HueUtil.registerWithHue(httpClient, hueAddress.getIp(), hueAddress.getName(), theHueHome.getTheHUERegisteredUser(), this);
|
||||||
|
if(theUser == null) {
|
||||||
|
log.warn("Register to Hue for " + hueAddress.getName() + " returned error: " + errorString);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
theHueHome.setTheHUERegisteredUser(theUser);
|
||||||
|
retryCount++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("GET HueApiResponse for " + hueAddress.getName() + " - returned error: " + theData);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theHueApiResponse = new Gson().fromJson(theData, HueApiResponse.class);
|
||||||
|
log.debug("GET HueApiResponse for " + hueAddress.getName() + " - Gson parse - name: " + theHueApiResponse.getConfig().getName() + ", mac addr: " + theHueApiResponse.getConfig().getMac());
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("GET HueApiResponse for " + hueAddress.getName() + " - returned null, no data.");
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theHueApiResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function executes the url against the vera
|
||||||
|
protected String doHttpGETRequest(String url) {
|
||||||
|
String theContent = null;
|
||||||
|
log.debug("calling GET on URL: " + url);
|
||||||
|
HttpGet httpGet = new HttpGet(url);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(httpGet);
|
||||||
|
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return theContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedIP getHueAddress() {
|
||||||
|
return hueAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHueAddress(NamedIP hueAddress) {
|
||||||
|
this.hueAddress = hueAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setErrorString(String anError) {
|
||||||
|
errorString = anError;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/main/java/com/bwssystems/hue/HueUtil.java
Normal file
55
src/main/java/com/bwssystems/hue/HueUtil.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.SuccessUserResponse;
|
||||||
|
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class HueUtil {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueUtil.class);
|
||||||
|
public static final String HUE_REQUEST = "/api";
|
||||||
|
|
||||||
|
public static final String registerWithHue(HttpClient anHttpClient, String ipAddress, String aName, String theUser, HueErrorStringSet errorStringSet) {
|
||||||
|
UserCreateRequest theLogin = new UserCreateRequest();
|
||||||
|
theLogin.setDevicetype("HABridge#MyMachine");
|
||||||
|
HttpPost postRequest = new HttpPost("http://" + ipAddress + HUE_REQUEST);
|
||||||
|
ContentType parsedContentType = ContentType.parse("application/json");
|
||||||
|
StringEntity requestBody = new StringEntity(new Gson().toJson(theLogin), parsedContentType);
|
||||||
|
HttpResponse response = null;
|
||||||
|
postRequest.setEntity(requestBody);
|
||||||
|
try {
|
||||||
|
response = anHttpClient.execute(postRequest);
|
||||||
|
log.debug("POST execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
|
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
|
||||||
|
String theBody = EntityUtils.toString(response.getEntity());
|
||||||
|
log.debug("registerWithHue response data: " + theBody);
|
||||||
|
if(theBody.contains("[{\"error\":")) {
|
||||||
|
if(theBody.contains("link button not")) {
|
||||||
|
log.warn("registerWithHue needs link button pressed on HUE bridge: " + aName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("registerWithHue returned an unexpected error: " + theBody);
|
||||||
|
errorStringSet.setErrorString(theBody);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SuccessUserResponse[] theResponses = new Gson().fromJson(theBody, SuccessUserResponse[].class); //read content for data, SuccessUserResponse[].class);
|
||||||
|
theUser = theResponses[0].getSuccess().getUsername();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error logging into HUE: IOException in log", e);
|
||||||
|
}
|
||||||
|
return theUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/java/com/bwssystems/logservices/LogFileInfo.java
Normal file
50
src/main/java/com/bwssystems/logservices/LogFileInfo.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* http://www.jrecruiter.org
|
||||||
|
*
|
||||||
|
* Disclaimer of Warranty.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, Licensor provides
|
||||||
|
* the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||||
|
* including, without limitation, any warranties or conditions of TITLE,
|
||||||
|
* NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||||
|
* solely responsible for determining the appropriateness of using or
|
||||||
|
* redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
* permissions under this License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.bwssystems.logservices;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log file information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LogFileInfo {
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
private Long fileSize;
|
||||||
|
private Date fileLastChanged;
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
public Long getFileSize() {
|
||||||
|
return fileSize;
|
||||||
|
}
|
||||||
|
public void setFileSize(Long fileSize) {
|
||||||
|
this.fileSize = fileSize;
|
||||||
|
}
|
||||||
|
public Date getFileLastChanged() {
|
||||||
|
return fileLastChanged;
|
||||||
|
}
|
||||||
|
public void setFileLastChanged(Date fileLastChanged) {
|
||||||
|
this.fileLastChanged = fileLastChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
51
src/main/java/com/bwssystems/logservices/LoggerInfo.java
Normal file
51
src/main/java/com/bwssystems/logservices/LoggerInfo.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package com.bwssystems.logservices;
|
||||||
|
|
||||||
|
import com.bwssystems.logservices.LoggingUtil.LogLevels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger information.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LoggerInfo {
|
||||||
|
|
||||||
|
private String loggerName;
|
||||||
|
private LogLevels logLevel;
|
||||||
|
private LogLevels newLogLevel;
|
||||||
|
|
||||||
|
//~~~~~Constructors~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public LoggerInfo() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
public LoggerInfo(String loggerName, int logLevelAsInt) {
|
||||||
|
super();
|
||||||
|
this.loggerName = loggerName;
|
||||||
|
this.logLevel = LogLevels.getLogLevelFromId(logLevelAsInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~Getters and Setters~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
public String getLoggerName() {
|
||||||
|
return loggerName;
|
||||||
|
}
|
||||||
|
public void setLoggerName(String loggerName) {
|
||||||
|
this.loggerName = loggerName;
|
||||||
|
}
|
||||||
|
public LogLevels getLogLevel() {
|
||||||
|
return logLevel;
|
||||||
|
}
|
||||||
|
public void setLogLevel(LogLevels logLevel) {
|
||||||
|
this.logLevel = logLevel;
|
||||||
|
}
|
||||||
|
public LogLevels getNewLogLevel() {
|
||||||
|
return newLogLevel;
|
||||||
|
}
|
||||||
|
public void setNewLogLevel(LogLevels newLogLevel) {
|
||||||
|
this.newLogLevel = newLogLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
src/main/java/com/bwssystems/logservices/LoggingForm.java
Normal file
58
src/main/java/com/bwssystems/logservices/LoggingForm.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package com.bwssystems.logservices;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for the Logging Action.
|
||||||
|
*/
|
||||||
|
public class LoggingForm implements Serializable {
|
||||||
|
|
||||||
|
/** serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = 5970927715241338665L;
|
||||||
|
|
||||||
|
/** List of Loggers, simplified for display purposes */
|
||||||
|
private List<LoggerInfo> updatedLoggers = new ArrayList<LoggerInfo>();
|
||||||
|
|
||||||
|
/** The user can enter a new logger to be configured */
|
||||||
|
private LoggerInfo newLogger;
|
||||||
|
|
||||||
|
/** Used for requesting a logfile download */
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
//~~~~~Constructors~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
public LoggingForm() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~Getters and Setters~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
public List<LoggerInfo> getUpdatedLoggers() {
|
||||||
|
return updatedLoggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedLoggers(List<LoggerInfo> updatedLoggers) {
|
||||||
|
this.updatedLoggers = updatedLoggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoggerInfo getNewLogger() {
|
||||||
|
return newLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewLogger(LoggerInfo newLogger) {
|
||||||
|
this.newLogger = newLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
163
src/main/java/com/bwssystems/logservices/LoggingManager.java
Normal file
163
src/main/java/com/bwssystems/logservices/LoggingManager.java
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
package com.bwssystems.logservices;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.bwssystems.logservices.LoggingUtil;
|
||||||
|
import com.bwssystems.logservices.LoggingUtil.LogLevels;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show log files and allow to set log levels for the configured loggers (logback)
|
||||||
|
* to be changed dynamically at runtime.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class LoggingManager {
|
||||||
|
|
||||||
|
/** Show all loggers or only the configured loggers */
|
||||||
|
private boolean showAll = false;
|
||||||
|
|
||||||
|
/** List of log files and associated information */
|
||||||
|
private List<LogFileInfo> logFileInfos = new ArrayList<LogFileInfo>();
|
||||||
|
|
||||||
|
/** List of Loggers, simplified for display purposes */
|
||||||
|
private List<LoggerInfo> configuredLoggers = new ArrayList<LoggerInfo>();
|
||||||
|
|
||||||
|
/** Used to stream a logfile back to the client */
|
||||||
|
private transient InputStream fileToDownLoad;
|
||||||
|
|
||||||
|
private LoggingForm model = new LoggingForm();
|
||||||
|
|
||||||
|
//~~~~~Reference Data~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/** Defines a collection of log levels. Unfortunately logback does not use
|
||||||
|
* enums to define its log levels. */
|
||||||
|
private Set<LogLevels> logLevels = EnumSet.allOf(LogLevels.class);
|
||||||
|
|
||||||
|
//~~~~~Prepare data~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
loadLoggers();
|
||||||
|
loadLogFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~Helper Methods~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private void loadLoggers() {
|
||||||
|
this.configuredLoggers.clear();
|
||||||
|
|
||||||
|
final List<Logger> loggers = LoggingUtil.getLoggers(this.showAll);
|
||||||
|
|
||||||
|
for (Logger logger : loggers) {
|
||||||
|
|
||||||
|
this.configuredLoggers.add(new LoggerInfo(logger.getName(), logger.getEffectiveLevel().levelInt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadLogFiles() {
|
||||||
|
this.logFileInfos = LoggingUtil.getLogFileInfos();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Updates loglevels for loggers */
|
||||||
|
public String updateLogLevels() {
|
||||||
|
|
||||||
|
if (this.model.getUpdatedLoggers() != null && !this.model.getUpdatedLoggers().isEmpty()) {
|
||||||
|
|
||||||
|
for (LoggerInfo loggerInfo : this.model.getUpdatedLoggers()) {
|
||||||
|
|
||||||
|
if (loggerInfo != null && loggerInfo.getNewLogLevel() != null) {
|
||||||
|
|
||||||
|
LoggingUtil.getLogger(loggerInfo.getLoggerName())
|
||||||
|
.setLevel(Level.toLevel(loggerInfo.getNewLogLevel().getLogLevel()));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Need to refresh the loggers
|
||||||
|
loadLoggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return "successRedirect";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds a new logger at runtime. */
|
||||||
|
public String addNewLogger() {
|
||||||
|
|
||||||
|
if (this.model.getNewLogger() != null
|
||||||
|
&& this.model.getNewLogger().getLoggerName() != null
|
||||||
|
&& this.model.getNewLogger().getNewLogLevel() != null) {
|
||||||
|
final Logger newLogger = LoggingUtil.getLogger(this.model.getNewLogger().getLoggerName());
|
||||||
|
newLogger.setLevel(Level.toLevel(this.model.getNewLogger().getNewLogLevel().getLogLevel()));
|
||||||
|
|
||||||
|
//Need to refresh the loggers
|
||||||
|
loadLoggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "successRedirect";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the requested log file.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String download() throws Exception {
|
||||||
|
|
||||||
|
if (this.model.getFileName() == null) {
|
||||||
|
throw new IllegalArgumentException("FileName must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final File logFile = LoggingUtil.getLogFile(this.model.getFileName());
|
||||||
|
|
||||||
|
if (logFile != null) {
|
||||||
|
this.fileToDownLoad = new FileInputStream(logFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "download";
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~Getters and Setters~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
public List<LogFileInfo> getLogFileInfos() {
|
||||||
|
return logFileInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getFileToDownLoad() {
|
||||||
|
return fileToDownLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LoggerInfo> getConfiguredLoggers() {
|
||||||
|
return configuredLoggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowAll() {
|
||||||
|
return showAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowAll(boolean showAll) {
|
||||||
|
this.showAll = showAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<LogLevels> getLogLevels() {
|
||||||
|
return logLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoggingForm getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(LoggingForm model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
198
src/main/java/com/bwssystems/logservices/LoggingUtil.java
Normal file
198
src/main/java/com/bwssystems/logservices/LoggingUtil.java
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package com.bwssystems.logservices;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bwssystems.logservices.LogFileInfo;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.Appender;
|
||||||
|
import ch.qos.logback.core.FileAppender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains utility methods to interact with the logback during runtime.
|
||||||
|
*/
|
||||||
|
public class LoggingUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* re-defines the logback logging levels as a Java enumeration. This is quite
|
||||||
|
* helpful if you need to render the various log-levels as select-box. I wish
|
||||||
|
* logback @see {@link ch.qos.logback.classic.Level} would not use static variables
|
||||||
|
* but use enums instead.
|
||||||
|
*/
|
||||||
|
public enum LogLevels {
|
||||||
|
|
||||||
|
OFF(Integer.MAX_VALUE, "Off"),
|
||||||
|
ERROR_INT(40000, "Error"),
|
||||||
|
WARN_INT(30000, "Warn"),
|
||||||
|
INFO_INT(20000, "Info"),
|
||||||
|
DEBUG_INT(10000, "Debug"),
|
||||||
|
TRACE(5000, "Trace"),
|
||||||
|
ALL(Integer.MIN_VALUE, "All");
|
||||||
|
|
||||||
|
private int logLevel;
|
||||||
|
private String logLevelName;
|
||||||
|
|
||||||
|
LogLevels(final int logLevel, final String logLevelName) {
|
||||||
|
this.logLevel = logLevel;
|
||||||
|
this.logLevelName = logLevelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLogLevel() {
|
||||||
|
return this.logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogLevelName() {
|
||||||
|
return this.logLevelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LogLevels getLogLevelFromId(final int logLevelAsInt) {
|
||||||
|
|
||||||
|
for (LogLevels logLevel : LogLevels.values()) {
|
||||||
|
|
||||||
|
if (logLevelAsInt == logLevel.logLevel) {
|
||||||
|
return logLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Loglevel " + logLevelAsInt + " does not exist.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.logLevelName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all configured logback loggers.
|
||||||
|
*
|
||||||
|
* @param showAll If set return ALL loggers, not only the configured ones.
|
||||||
|
* @return List of Loggers
|
||||||
|
*/
|
||||||
|
public static List<ch.qos.logback.classic.Logger> getLoggers(final boolean showAll) {
|
||||||
|
|
||||||
|
final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
final List<ch.qos.logback.classic.Logger> loggers = new ArrayList<ch.qos.logback.classic.Logger>();
|
||||||
|
|
||||||
|
for (ch.qos.logback.classic.Logger log : lc.getLoggerList()) {
|
||||||
|
if(showAll == false) {
|
||||||
|
if(log.getLevel() != null || LoggingUtil.hasAppenders(log)) {
|
||||||
|
loggers.add(log);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loggers.add(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single logger.
|
||||||
|
*
|
||||||
|
* @return Logger
|
||||||
|
*/
|
||||||
|
public static ch.qos.logback.classic.Logger getLogger(final String loggerName) {
|
||||||
|
|
||||||
|
final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
|
||||||
|
return lc.getLogger(loggerName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the provided logger has appenders.
|
||||||
|
*
|
||||||
|
* @param logger The logger to test
|
||||||
|
* @return true if the logger has appenders.
|
||||||
|
*/
|
||||||
|
public static boolean hasAppenders(ch.qos.logback.classic.Logger logger) {
|
||||||
|
Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the logfile information for the roor logger.
|
||||||
|
*
|
||||||
|
* @return List of LogFileInfo obejcts
|
||||||
|
*/
|
||||||
|
public static List<LogFileInfo> getLogFileInfos() {
|
||||||
|
|
||||||
|
final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
|
||||||
|
final List<LogFileInfo> logFileInfos = new ArrayList<LogFileInfo>();
|
||||||
|
|
||||||
|
final Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
|
|
||||||
|
final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
|
||||||
|
final Appender<ILoggingEvent> appender = it.next();
|
||||||
|
|
||||||
|
if (appender instanceof FileAppender) {
|
||||||
|
|
||||||
|
final FileAppender<ILoggingEvent> fileAppender = (FileAppender<ILoggingEvent>) appender;
|
||||||
|
|
||||||
|
final File logFile = new File(fileAppender.getFile());
|
||||||
|
final LogFileInfo logFileInfo = new LogFileInfo();
|
||||||
|
|
||||||
|
logFileInfo.setFileName(logFile.getName());
|
||||||
|
logFileInfo.setFileLastChanged(new Date(logFile.lastModified()));
|
||||||
|
logFileInfo.setFileSize(logFile.length());
|
||||||
|
logFileInfos.add(logFileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return logFileInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the log file.
|
||||||
|
*
|
||||||
|
* @param logFileName The name of the log file
|
||||||
|
* @return The actual file
|
||||||
|
*/
|
||||||
|
public static File getLogFile(final String logFileName) {
|
||||||
|
|
||||||
|
if (logFileName == null) {
|
||||||
|
throw new IllegalArgumentException("logFileName cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
|
||||||
|
final Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
|
|
||||||
|
final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
|
||||||
|
final Appender<ILoggingEvent> appender = it.next();
|
||||||
|
|
||||||
|
if (appender instanceof FileAppender) {
|
||||||
|
|
||||||
|
final FileAppender<ILoggingEvent> fileAppender = (FileAppender<ILoggingEvent>) appender;
|
||||||
|
|
||||||
|
final File logFile = new File(fileAppender.getFile());
|
||||||
|
|
||||||
|
if (logFile.getName().equalsIgnoreCase(logFileName)) {
|
||||||
|
return logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ public class Device {
|
|||||||
private String level;
|
private String level;
|
||||||
private String state;
|
private String state;
|
||||||
private String comment;
|
private String comment;
|
||||||
|
private String veraname;
|
||||||
|
private String veraaddress;
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -79,5 +81,17 @@ public class Device {
|
|||||||
public void setComment(String comment) {
|
public void setComment(String comment) {
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
}
|
}
|
||||||
|
public String getVeraname() {
|
||||||
|
return veraname;
|
||||||
|
}
|
||||||
|
public void setVeraname(String veraname) {
|
||||||
|
this.veraname = veraname;
|
||||||
|
}
|
||||||
|
public String getVeraaddress() {
|
||||||
|
return veraaddress;
|
||||||
|
}
|
||||||
|
public void setVeraaddress(String veraaddress) {
|
||||||
|
this.veraaddress = veraaddress;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ public class Scene {
|
|||||||
private String name;
|
private String name;
|
||||||
private String id;
|
private String id;
|
||||||
private String room;
|
private String room;
|
||||||
|
private String veraname;
|
||||||
|
private String veraaddress;
|
||||||
public String getActive() {
|
public String getActive() {
|
||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
@@ -29,5 +31,17 @@ public class Scene {
|
|||||||
public void setRoom(String room) {
|
public void setRoom(String room) {
|
||||||
this.room = room;
|
this.room = room;
|
||||||
}
|
}
|
||||||
|
public String getVeraname() {
|
||||||
|
return veraname;
|
||||||
|
}
|
||||||
|
public void setVeraname(String veraname) {
|
||||||
|
this.veraname = veraname;
|
||||||
|
}
|
||||||
|
public String getVeraaddress() {
|
||||||
|
return veraaddress;
|
||||||
|
}
|
||||||
|
public void setVeraaddress(String veraaddress) {
|
||||||
|
this.veraaddress = veraaddress;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
95
src/main/java/com/bwssystems/util/BackupHandler.java
Normal file
95
src/main/java/com/bwssystems/util/BackupHandler.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package com.bwssystems.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public abstract class BackupHandler {
|
||||||
|
final Logger log = LoggerFactory.getLogger(BackupHandler.class);
|
||||||
|
private Path repositoryPath;
|
||||||
|
private String fileExtension;
|
||||||
|
private String defaultName;
|
||||||
|
|
||||||
|
protected void setupParams(Path aPath, String anExtension, String adefaultName) {
|
||||||
|
repositoryPath = aPath;
|
||||||
|
if(anExtension.substring(0, 1).equalsIgnoreCase("."))
|
||||||
|
fileExtension = anExtension;
|
||||||
|
else
|
||||||
|
fileExtension = "." + anExtension;
|
||||||
|
|
||||||
|
defaultName = adefaultName;
|
||||||
|
|
||||||
|
log.debug("setupParams has defaultName: " + defaultName + " and file extension as: " + fileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String backup(String aFilename) {
|
||||||
|
if(aFilename == null || aFilename.equalsIgnoreCase("")) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||||
|
aFilename = defaultName + dateFormat.format(Calendar.getInstance().getTime()) + fileExtension;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aFilename = aFilename + fileExtension;
|
||||||
|
try {
|
||||||
|
Files.copy(repositoryPath, FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), StandardCopyOption.COPY_ATTRIBUTES);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not backup to file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
log.debug("Backup repository: " + aFilename);
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String deleteBackup(String aFilename) {
|
||||||
|
log.debug("Delete backup repository: " + aFilename);
|
||||||
|
try {
|
||||||
|
Files.delete(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not delete file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String restoreBackup(String aFilename) {
|
||||||
|
log.debug("Restore backup repository: " + aFilename);
|
||||||
|
try {
|
||||||
|
Path target = null;
|
||||||
|
if(Files.exists(repositoryPath)) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||||
|
target = FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), defaultName + dateFormat.format(Calendar.getInstance().getTime()) + fileExtension);
|
||||||
|
Files.move(repositoryPath, target);
|
||||||
|
}
|
||||||
|
Files.copy(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), repositoryPath, StandardCopyOption.COPY_ATTRIBUTES);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error restoring the file: " + aFilename + " message: " + e.getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getBackups() {
|
||||||
|
List<String> theFilenames = new ArrayList<String>();
|
||||||
|
Path dir = repositoryPath.getParent();
|
||||||
|
try (DirectoryStream<Path> stream =
|
||||||
|
Files.newDirectoryStream(dir, "*.{"+ fileExtension.substring(1) + "}")) {
|
||||||
|
for (Path entry: stream) {
|
||||||
|
theFilenames.add(entry.getFileName().toString());
|
||||||
|
}
|
||||||
|
} catch (IOException x) {
|
||||||
|
// IOException can never be thrown by the iteration.
|
||||||
|
// In this snippet, it can // only be thrown by newDirectoryStream.
|
||||||
|
log.warn("Issue getting directory listing for backups in directory: " + x.getMessage());
|
||||||
|
}
|
||||||
|
return theFilenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.util;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import spark.ResponseTransformer;
|
import spark.ResponseTransformer;
|
||||||
262
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
262
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
package com.bwssystems.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.text.CharacterIterator;
|
||||||
|
import java.text.StringCharacterIterator;
|
||||||
|
|
||||||
|
public final class TextStringFormatter {
|
||||||
|
private TextStringFormatter() {
|
||||||
|
// empty - prevent construction
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Escapes characters for text appearing as data in the
|
||||||
|
<a href='http://www.json.org/'>Javascript Object Notation</a>
|
||||||
|
(JSON) data interchange format.
|
||||||
|
|
||||||
|
<P>The following commonly used control characters are escaped :
|
||||||
|
<table border='1' cellpadding='3' cellspacing='0'>
|
||||||
|
<tr><th> Character </th><th> Escaped As </th></tr>
|
||||||
|
<tr><td> " </td><td> \" </td></tr>
|
||||||
|
<tr><td> \ </td><td> \\ </td></tr>
|
||||||
|
<tr><td> / </td><td> \/ </td></tr>
|
||||||
|
<tr><td> back space </td><td> \b </td></tr>
|
||||||
|
<tr><td> form feed </td><td> \f </td></tr>
|
||||||
|
<tr><td> line feed </td><td> \n </td></tr>
|
||||||
|
<tr><td> carriage return </td><td> \r </td></tr>
|
||||||
|
<tr><td> tab </td><td> \t </td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<P>See <a href='http://www.ietf.org/rfc/rfc4627.txt'>RFC 4627</a> for more information.
|
||||||
|
*/
|
||||||
|
public static String forJSON(String aText) {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||||
|
char character = iterator.current();
|
||||||
|
while (character != StringCharacterIterator.DONE) {
|
||||||
|
if (character == '\"') {
|
||||||
|
result.append("\\\"");
|
||||||
|
} else if (character == '\\') {
|
||||||
|
result.append("\\\\");
|
||||||
|
} else if (character == '/') {
|
||||||
|
result.append("\\/");
|
||||||
|
} else if (character == '\b') {
|
||||||
|
result.append("\\b");
|
||||||
|
} else if (character == '\f') {
|
||||||
|
result.append("\\f");
|
||||||
|
} else if (character == '\n') {
|
||||||
|
result.append("\\n");
|
||||||
|
} else if (character == '\r') {
|
||||||
|
result.append("\\r");
|
||||||
|
} else if (character == '\t') {
|
||||||
|
result.append("\\t");
|
||||||
|
} else {
|
||||||
|
// the char is not a special one
|
||||||
|
// add it to the result as is
|
||||||
|
result.append(character);
|
||||||
|
}
|
||||||
|
character = iterator.next();
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Escape characters for text appearing in HTML markup.
|
||||||
|
|
||||||
|
<P>This method exists as a defence against Cross Site Scripting (XSS) hacks.
|
||||||
|
The idea is to neutralize control characters commonly used by scripts, such that
|
||||||
|
they will not be executed by the browser. This is done by replacing the control
|
||||||
|
characters with their escaped equivalents.
|
||||||
|
See {@link hirondelle.web4j.security.SafeText} as well.
|
||||||
|
|
||||||
|
<P>The following characters are replaced with corresponding
|
||||||
|
HTML character entities :
|
||||||
|
<table border='1' cellpadding='3' cellspacing='0'>
|
||||||
|
<tr><th> Character </th><th>Replacement</th></tr>
|
||||||
|
<tr><td> < </td><td> < </td></tr>
|
||||||
|
<tr><td> > </td><td> > </td></tr>
|
||||||
|
<tr><td> & </td><td> & </td></tr>
|
||||||
|
<tr><td> " </td><td> "</td></tr>
|
||||||
|
<tr><td> \t </td><td> 	</td></tr>
|
||||||
|
<tr><td> ! </td><td> !</td></tr>
|
||||||
|
<tr><td> # </td><td> #</td></tr>
|
||||||
|
<tr><td> $ </td><td> $</td></tr>
|
||||||
|
<tr><td> % </td><td> %</td></tr>
|
||||||
|
<tr><td> ' </td><td> '</td></tr>
|
||||||
|
<tr><td> ( </td><td> (</td></tr>
|
||||||
|
<tr><td> ) </td><td> )</td></tr>
|
||||||
|
<tr><td> * </td><td> *</td></tr>
|
||||||
|
<tr><td> + </td><td> + </td></tr>
|
||||||
|
<tr><td> , </td><td> , </td></tr>
|
||||||
|
<tr><td> - </td><td> - </td></tr>
|
||||||
|
<tr><td> . </td><td> . </td></tr>
|
||||||
|
<tr><td> / </td><td> / </td></tr>
|
||||||
|
<tr><td> : </td><td> :</td></tr>
|
||||||
|
<tr><td> ; </td><td> ;</td></tr>
|
||||||
|
<tr><td> = </td><td> =</td></tr>
|
||||||
|
<tr><td> ? </td><td> ?</td></tr>
|
||||||
|
<tr><td> @ </td><td> @</td></tr>
|
||||||
|
<tr><td> [ </td><td> [</td></tr>
|
||||||
|
<tr><td> \ </td><td> \</td></tr>
|
||||||
|
<tr><td> ] </td><td> ]</td></tr>
|
||||||
|
<tr><td> ^ </td><td> ^</td></tr>
|
||||||
|
<tr><td> _ </td><td> _</td></tr>
|
||||||
|
<tr><td> ` </td><td> `</td></tr>
|
||||||
|
<tr><td> { </td><td> {</td></tr>
|
||||||
|
<tr><td> | </td><td> |</td></tr>
|
||||||
|
<tr><td> } </td><td> }</td></tr>
|
||||||
|
<tr><td> ~ </td><td> ~</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<P>Note that JSTL's {@code <c:out>} escapes <em>only the first
|
||||||
|
five</em> of the above characters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String forHTML(String aText) {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
final StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||||
|
char character = iterator.current();
|
||||||
|
while (character != CharacterIterator.DONE) {
|
||||||
|
if (character == '<') {
|
||||||
|
result.append("<");
|
||||||
|
} else if (character == '>') {
|
||||||
|
result.append(">");
|
||||||
|
} else if (character == '&') {
|
||||||
|
result.append("&");
|
||||||
|
} else if (character == '\"') {
|
||||||
|
result.append(""");
|
||||||
|
} else if (character == '\t') {
|
||||||
|
addCharEntity(9, result);
|
||||||
|
} else if (character == '!') {
|
||||||
|
addCharEntity(33, result);
|
||||||
|
} else if (character == '#') {
|
||||||
|
addCharEntity(35, result);
|
||||||
|
} else if (character == '$') {
|
||||||
|
addCharEntity(36, result);
|
||||||
|
} else if (character == '%') {
|
||||||
|
addCharEntity(37, result);
|
||||||
|
} else if (character == '\'') {
|
||||||
|
addCharEntity(39, result);
|
||||||
|
} else if (character == '(') {
|
||||||
|
addCharEntity(40, result);
|
||||||
|
} else if (character == ')') {
|
||||||
|
addCharEntity(41, result);
|
||||||
|
} else if (character == '*') {
|
||||||
|
addCharEntity(42, result);
|
||||||
|
} else if (character == '+') {
|
||||||
|
addCharEntity(43, result);
|
||||||
|
} else if (character == ',') {
|
||||||
|
addCharEntity(44, result);
|
||||||
|
} else if (character == '-') {
|
||||||
|
addCharEntity(45, result);
|
||||||
|
} else if (character == '.') {
|
||||||
|
addCharEntity(46, result);
|
||||||
|
} else if (character == '/') {
|
||||||
|
addCharEntity(47, result);
|
||||||
|
} else if (character == ':') {
|
||||||
|
addCharEntity(58, result);
|
||||||
|
} else if (character == ';') {
|
||||||
|
addCharEntity(59, result);
|
||||||
|
} else if (character == '=') {
|
||||||
|
addCharEntity(61, result);
|
||||||
|
} else if (character == '?') {
|
||||||
|
addCharEntity(63, result);
|
||||||
|
} else if (character == '@') {
|
||||||
|
addCharEntity(64, result);
|
||||||
|
} else if (character == '[') {
|
||||||
|
addCharEntity(91, result);
|
||||||
|
} else if (character == '\\') {
|
||||||
|
addCharEntity(92, result);
|
||||||
|
} else if (character == ']') {
|
||||||
|
addCharEntity(93, result);
|
||||||
|
} else if (character == '^') {
|
||||||
|
addCharEntity(94, result);
|
||||||
|
} else if (character == '_') {
|
||||||
|
addCharEntity(95, result);
|
||||||
|
} else if (character == '`') {
|
||||||
|
addCharEntity(96, result);
|
||||||
|
} else if (character == '{') {
|
||||||
|
addCharEntity(123, result);
|
||||||
|
} else if (character == '|') {
|
||||||
|
addCharEntity(124, result);
|
||||||
|
} else if (character == '}') {
|
||||||
|
addCharEntity(125, result);
|
||||||
|
} else if (character == '~') {
|
||||||
|
addCharEntity(126, result);
|
||||||
|
} else {
|
||||||
|
// the char is not a special one
|
||||||
|
// add it to the result as is
|
||||||
|
result.append(character);
|
||||||
|
}
|
||||||
|
character = iterator.next();
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape all ampersand characters in a URL.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Replaces all <tt>'&'</tt> characters with <tt>'&'</tt>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* An ampersand character may appear in the query string of a URL. The
|
||||||
|
* ampersand character is indeed valid in a URL.
|
||||||
|
* <em>However, URLs usually appear as an <tt>HREF</tt> attribute, and such
|
||||||
|
* attributes have the additional constraint that ampersands must be
|
||||||
|
* escaped.</em>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The JSTL <c:url> tag does indeed perform proper URL encoding of query
|
||||||
|
* parameters. But it does not, in general, produce text which is valid as
|
||||||
|
* an <tt>HREF</tt> attribute, simply because it does not escape the
|
||||||
|
* ampersand character. This is a nuisance when multiple query parameters
|
||||||
|
* appear in the URL, since it requires a little extra work.
|
||||||
|
*/
|
||||||
|
public static String forHrefAmpersand(String aURL) {
|
||||||
|
return aURL.replace("&", "&");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String forQuerySpace(String aURL) {
|
||||||
|
return aURL.replace(" ", "\u0020");
|
||||||
|
}
|
||||||
|
public static String forQuerySpaceUrl(String aURL) {
|
||||||
|
return aURL.replace(" ", "%20");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Used to ensure that HTTP query strings are in proper form, by escaping
|
||||||
|
* special characters such as spaces.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* It is important to note that if a query string appears in an
|
||||||
|
* <tt>HREF</tt> attribute, then there are two issues - ensuring the query
|
||||||
|
* string is valid HTTP (it is URL-encoded), and ensuring it is valid HTML
|
||||||
|
* (ensuring the ampersand is escaped).
|
||||||
|
*/
|
||||||
|
public static String forURL(String aURLFragment) {
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
result = URLEncoder.encode(aURLFragment, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new RuntimeException("UTF-8 not supported", ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addCharEntity(Integer aIdx, StringBuilder aBuilder) {
|
||||||
|
String padding = "";
|
||||||
|
if (aIdx <= 9) {
|
||||||
|
padding = "00";
|
||||||
|
} else if (aIdx <= 99) {
|
||||||
|
padding = "0";
|
||||||
|
} else {
|
||||||
|
// no prefix
|
||||||
|
}
|
||||||
|
String number = padding + aIdx.toString();
|
||||||
|
aBuilder.append("&#" + number + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/main/java/com/bwssystems/vera/VeraHome.java
Normal file
73
src/main/java/com/bwssystems/vera/VeraHome.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package com.bwssystems.vera;
|
||||||
|
|
||||||
|
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.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.luupRequests.Device;
|
||||||
|
import com.bwssystems.luupRequests.Scene;
|
||||||
|
import com.bwssystems.luupRequests.Sdata;
|
||||||
|
|
||||||
|
public class VeraHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VeraHome.class);
|
||||||
|
private Map<String, VeraInfo> veras;
|
||||||
|
|
||||||
|
public VeraHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
veras = new HashMap<String, VeraInfo>();
|
||||||
|
if(!bridgeSettings.isValidVera())
|
||||||
|
return;
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getVeraAddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aVera = theList.next();
|
||||||
|
veras.put(aVera.getName(), new VeraInfo(aVera));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Device> getDevices() {
|
||||||
|
log.debug("consolidating devices for veras");
|
||||||
|
Iterator<String> keys = veras.keySet().iterator();
|
||||||
|
ArrayList<Device> deviceList = new ArrayList<Device>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Sdata theSdata = veras.get(key).getSdata();
|
||||||
|
if(theSdata != null) {
|
||||||
|
Iterator<Device> devices = theSdata.getDevices().iterator();
|
||||||
|
while(devices.hasNext()) {
|
||||||
|
deviceList.add(devices.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deviceList = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
public List<Scene> getScenes() {
|
||||||
|
log.debug("consolidating scenes for veras");
|
||||||
|
Iterator<String> keys = veras.keySet().iterator();
|
||||||
|
ArrayList<Scene> sceneList = new ArrayList<Scene>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
Sdata theSdata = veras.get(key).getSdata();
|
||||||
|
if(theSdata != null) {
|
||||||
|
Iterator<Scene> scenes = theSdata.getScenes().iterator();
|
||||||
|
while(scenes.hasNext()) {
|
||||||
|
sceneList.add(scenes.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sceneList = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sceneList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bwssystems.vera;
|
package com.bwssystems.vera;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -13,6 +14,7 @@ import org.apache.http.util.EntityUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
import com.bwssystems.luupRequests.Categorie;
|
import com.bwssystems.luupRequests.Categorie;
|
||||||
import com.bwssystems.luupRequests.Device;
|
import com.bwssystems.luupRequests.Device;
|
||||||
import com.bwssystems.luupRequests.Room;
|
import com.bwssystems.luupRequests.Room;
|
||||||
@@ -25,22 +27,26 @@ public class VeraInfo {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(VeraInfo.class);
|
private static final Logger log = LoggerFactory.getLogger(VeraInfo.class);
|
||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
||||||
private String veraAddressString;
|
private NamedIP veraAddress;
|
||||||
|
|
||||||
public VeraInfo(String addressString) {
|
public VeraInfo(NamedIP addressName) {
|
||||||
super();
|
super();
|
||||||
httpClient = HttpClients.createMinimal();
|
httpClient = HttpClients.createDefault();
|
||||||
veraAddressString = addressString;
|
veraAddress = addressName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sdata getSdata() {
|
public Sdata getSdata() {
|
||||||
String theUrl = "http://" + veraAddressString + SDATA_REQUEST;
|
Sdata theSdata = null;
|
||||||
|
|
||||||
|
String theUrl = "http://" + veraAddress.getIp() + SDATA_REQUEST;
|
||||||
String theData;
|
String theData;
|
||||||
|
|
||||||
theData = doHttpGETRequest(theUrl);
|
theData = doHttpGETRequest(theUrl);
|
||||||
Sdata theSdata = new Gson().fromJson(theData, Sdata.class);
|
if(theData != null) {
|
||||||
log.debug("GET sdata - full: " + theSdata.getFull() + ", version: " + theSdata.getVersion());
|
theSdata = new Gson().fromJson(theData, Sdata.class);
|
||||||
denormalizeSdata(theSdata);
|
log.debug("GET sdata - full: " + theSdata.getFull() + ", version: " + theSdata.getVersion());
|
||||||
|
denormalizeSdata(theSdata);
|
||||||
|
}
|
||||||
return theSdata;
|
return theSdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,35 +67,43 @@ public class VeraInfo {
|
|||||||
theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName());
|
theDevice.setRoom(roomMap.get(theDevice.getRoom()).getName());
|
||||||
else
|
else
|
||||||
theDevice.setRoom("no room");
|
theDevice.setRoom("no room");
|
||||||
|
|
||||||
if(theDevice.getCategory() != null && categoryMap.get(theDevice.getCategory()) != null)
|
if(theDevice.getCategory() != null && categoryMap.get(theDevice.getCategory()) != null)
|
||||||
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
theDevice.setCategory(categoryMap.get(theDevice.getCategory()).getName());
|
||||||
else
|
else
|
||||||
theDevice.setCategory("<unknown>");
|
theDevice.setCategory("<unknown>");
|
||||||
|
theDevice.setVeraaddress(veraAddress.getIp());
|
||||||
|
theDevice.setVeraname(veraAddress.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
ListIterator<Scene> theSecneIter = theSdata.getScenes().listIterator();
|
||||||
Scene theScene = null;
|
Scene theScene = null;
|
||||||
while (theSecneIter.hasNext()) {
|
while (theSecneIter.hasNext()) {
|
||||||
theScene = theSecneIter.next();
|
theScene = theSecneIter.next();
|
||||||
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
if(theScene.getRoom() != null && roomMap.get(theScene.getRoom()) != null)
|
||||||
|
theScene.setRoom(roomMap.get(theScene.getRoom()).getName());
|
||||||
|
else
|
||||||
|
theScene.setRoom("no room");
|
||||||
|
theScene.setVeraaddress(veraAddress.getIp());
|
||||||
|
theScene.setVeraname(veraAddress.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function executes the url against the vera
|
// This function executes the url against the vera
|
||||||
protected String doHttpGETRequest(String url) {
|
protected String doHttpGETRequest(String url) {
|
||||||
|
String theContent = null;
|
||||||
log.debug("calling GET on URL: " + url);
|
log.debug("calling GET on URL: " + url);
|
||||||
HttpGet httpGet = new HttpGet(url);
|
HttpGet httpGet = new HttpGet(url);
|
||||||
try {
|
try {
|
||||||
HttpResponse response = httpClient.execute(httpGet);
|
HttpResponse response = httpClient.execute(httpGet);
|
||||||
String theContent = EntityUtils.toString(response.getEntity()); //read content for data
|
|
||||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
|
||||||
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
if(response.getStatusLine().getStatusCode() == 200){
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
return theContent;
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error calling out to HA gateway", e);
|
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return null;
|
return theContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/main/resources/config.data
Normal file
1
src/main/resources/config.data
Normal file
File diff suppressed because one or more lines are too long
18
src/main/resources/logback.xml
Normal file
18
src/main/resources/logback.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d [%thread] %-5level %logger - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="CYCLIC" class="ch.qos.logback.core.read.CyclicBufferAppender">
|
||||||
|
<MaxSize>512</MaxSize>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="CYCLIC" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
6
src/main/resources/public/css/bootstrap-theme.min.css
vendored
Normal file
6
src/main/resources/public/css/bootstrap-theme.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
11
src/main/resources/public/css/main.css
Normal file
11
src/main/resources/public/css/main.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
body {
|
||||||
|
padding-top: 60px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortorder:after {
|
||||||
|
content: '\25b2';
|
||||||
|
}
|
||||||
|
.sortorder.reverse:after {
|
||||||
|
content: '\25bc';
|
||||||
|
}
|
||||||
1
src/main/resources/public/css/ngDialog-theme-default.min.css
vendored
Normal file
1
src/main/resources/public/css/ngDialog-theme-default.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes ngdialog-flyin{0%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes ngdialog-flyin{0%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes ngdialog-flyout{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes ngdialog-flyout{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}}.ngdialog.ngdialog-theme-default{padding-bottom:160px;padding-top:160px}.ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content{-webkit-animation:ngdialog-flyout .5s;animation:ngdialog-flyout .5s}.ngdialog.ngdialog-theme-default .ngdialog-content{-webkit-animation:ngdialog-flyin .5s;animation:ngdialog-flyin .5s;background:#f0f0f0;border-radius:5px;color:#444;font-family:Helvetica,sans-serif;font-size:1.1em;line-height:1.5em;margin:0 auto;max-width:100%;padding:1em;position:relative;width:450px}.ngdialog.ngdialog-theme-default .ngdialog-close{border-radius:5px;cursor:pointer;position:absolute;right:0;top:0}.ngdialog.ngdialog-theme-default .ngdialog-close:before{background:0 0;border-radius:3px;color:#bbb;content:'\00D7';font-size:26px;font-weight:400;height:30px;line-height:26px;position:absolute;right:3px;text-align:center;top:3px;width:30px}.ngdialog.ngdialog-theme-default .ngdialog-close:active:before,.ngdialog.ngdialog-theme-default .ngdialog-close:hover:before{color:#777}.ngdialog.ngdialog-theme-default .ngdialog-message{margin-bottom:.5em}.ngdialog.ngdialog-theme-default .ngdialog-input{margin-bottom:1em}.ngdialog.ngdialog-theme-default .ngdialog-input input[type=text],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=password],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=email],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=url],.ngdialog.ngdialog-theme-default .ngdialog-input textarea{background:#fff;border:0;border-radius:3px;font-family:inherit;font-size:inherit;font-weight:inherit;margin:0 0 .25em;min-height:2.5em;padding:.25em .67em;width:100%}.ngdialog.ngdialog-theme-default .ngdialog-input input[type=text]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=password]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=email]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=url]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus{box-shadow:inset 0 0 0 2px #8dbdf1;outline:0}.ngdialog.ngdialog-theme-default .ngdialog-buttons:after{content:'';display:table;clear:both}.ngdialog.ngdialog-theme-default .ngdialog-button{border:0;border-radius:3px;cursor:pointer;float:right;font-family:inherit;font-size:.8em;letter-spacing:.1em;line-height:1em;margin:0 0 0 .5em;padding:.75em 2em;text-transform:uppercase}.ngdialog.ngdialog-theme-default .ngdialog-button:focus{-webkit-animation:ngdialog-pulse 1.1s infinite;animation:ngdialog-pulse 1.1s infinite;outline:0}@media (max-width:568px){.ngdialog.ngdialog-theme-default .ngdialog-button:focus{-webkit-animation:none;animation:none}}.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary{background:#3288e6;color:#fff}.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary{background:#e0e0e0;color:#777}
|
||||||
1
src/main/resources/public/css/ngDialog.min.css
vendored
Normal file
1
src/main/resources/public/css/ngDialog.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.ngdialog,.ngdialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0}@-webkit-keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@-webkit-keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{box-sizing:border-box;overflow:auto;-webkit-overflow-scrolling:touch;z-index:10000}.ngdialog *,.ngdialog :after,.ngdialog :before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation,.ngdialog.ngdialog-disabled-animation .ngdialog-content,.ngdialog.ngdialog-disabled-animation .ngdialog-overlay{-webkit-animation:none!important;animation:none!important}.ngdialog-overlay{background:rgba(0,0,0,.4);-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadein .5s;animation:ngdialog-fadein .5s}.ngdialog-no-overlay{pointer-events:none}.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadeout .5s;animation:ngdialog-fadeout .5s}.ngdialog-content{background:#fff;-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadein .5s;animation:ngdialog-fadein .5s;pointer-events:all}.ngdialog.ngdialog-closing .ngdialog-content{-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadeout .5s;animation:ngdialog-fadeout .5s}.ngdialog-close:before{font-family:Helvetica,Arial,sans-serif;content:'\00D7';cursor:pointer}body.ngdialog-open,html.ngdialog-open{overflow:hidden}
|
||||||
7
src/main/resources/public/css/ngToast.min.css
vendored
Normal file
7
src/main/resources/public/css/ngToast.min.css
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
* ngToast v1.5.6 (http://tameraydin.github.io/ngToast)
|
||||||
|
* Copyright 2015 Tamer Aydin (http://tamerayd.in)
|
||||||
|
* Licensed under MIT (http://tameraydin.mit-license.org/)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ng-toast{position:fixed;z-index:1080;width:100%;height:0;margin-top:20px;text-align:center}.ng-toast.ng-toast--top,.ng-toast.ng-toast--top .ng-toast__list{top:0;bottom:auto}.ng-toast.ng-toast--top.ng-toast--center .ng-toast__list{position:static}.ng-toast.ng-toast--bottom,.ng-toast.ng-toast--bottom .ng-toast__list{top:auto;bottom:0}.ng-toast.ng-toast--bottom.ng-toast--center .ng-toast__list{pointer-events:none}.ng-toast.ng-toast--bottom.ng-toast--center .ng-toast__message .alert{pointer-events:auto}.ng-toast.ng-toast--right .ng-toast__list{left:auto;right:0;margin-right:20px}.ng-toast.ng-toast--right .ng-toast__message{text-align:right}.ng-toast.ng-toast--left .ng-toast__list{right:auto;left:0;margin-left:20px}.ng-toast.ng-toast--left .ng-toast__message{text-align:left}.ng-toast .ng-toast__list{display:inline-block;position:absolute;right:0;left:0;margin:0 auto;padding:0;list-style:none}.ng-toast .ng-toast__message{display:block;width:100%;text-align:center}.ng-toast .ng-toast__message .alert{display:inline-block}.ng-toast .ng-toast__message__count{display:inline-block;margin:0 15px 0 5px}
|
||||||
2
src/main/resources/public/css/rzslider.min.css
vendored
Normal file
2
src/main/resources/public/css/rzslider.min.css
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/*! angularjs-slider - v2.8.0 - (c) Rafal Zajac <rzajac@gmail.com>, Valentin Hervieu <valentin@hervieu.me>, Jussi Saarivirta <jusasi@gmail.com>, Angelin Sirbu <angelin.sirbu@gmail.com> - https://github.com/angular-slider/angularjs-slider - 2016-02-08 */
|
||||||
|
rzslider{position:relative;display:inline-block;width:100%;height:4px;margin:35px 0 15px 0;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}rzslider[disabled]{cursor:not-allowed}rzslider[disabled] .rz-pointer{cursor:not-allowed;background-color:#d8e0f3}rzslider span{position:absolute;display:inline-block;white-space:nowrap}rzslider .rz-base{width:100%;height:100%;padding:0}rzslider .rz-bar-wrapper{left:0;z-index:1;width:100%;height:32px;padding-top:16px;margin-top:-16px;box-sizing:border-box}rzslider .rz-bar-wrapper.rz-draggable{cursor:move}rzslider .rz-bar{left:0;z-index:1;width:100%;height:4px;background:#d8e0f3;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}rzslider .rz-bar.rz-selection{z-index:2;background:#0db9f0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}rzslider .rz-pointer{top:-14px;z-index:3;width:32px;height:32px;cursor:pointer;background-color:#0db9f0;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px}rzslider .rz-pointer:after{position:absolute;top:12px;left:12px;width:8px;height:8px;background:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;content:''}rzslider .rz-pointer:hover:after{background-color:#fff}rzslider .rz-pointer.rz-active{z-index:4}rzslider .rz-pointer.rz-active:after{background-color:#451aff}rzslider .rz-bubble{bottom:16px;padding:1px 3px;color:#55637d;cursor:default}rzslider .rz-bubble.rz-selection{top:16px}rzslider .rz-bubble.rz-limit{color:#55637d}rzslider .rz-ticks{position:absolute;top:-3px;left:0;z-index:1;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;height:0;padding:0 11px;margin:0;list-style:none;box-sizing:border-box;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}rzslider .rz-ticks .tick{width:10px;height:10px;text-align:center;cursor:pointer;background:#d8e0f3;border-radius:50%}rzslider .rz-ticks .tick.selected{background:#0db9f0}rzslider .rz-ticks .tick .tick-value{position:absolute;top:-30px;transform:translate(-50%,0)}rzslider.vertical{position:relative;width:4px;height:100%;padding:0;margin:0 20px;vertical-align:baseline}rzslider.vertical .rz-base{width:100%;height:100%;padding:0}rzslider.vertical .rz-bar-wrapper{top:auto;left:0;width:32px;height:100%;padding:0 0 0 16px;margin:0 0 0 -16px}rzslider.vertical .rz-bar{bottom:0;left:auto;width:4px;height:100%}rzslider.vertical .rz-pointer{top:auto;bottom:0;left:-14px!important}rzslider.vertical .rz-bubble{bottom:0;left:16px!important;margin-left:3px}rzslider.vertical .rz-bubble.rz-selection{top:auto;left:16px!important}rzslider.vertical .rz-ticks{top:0;left:-3px;z-index:1;width:0;height:100%;padding:11px 0;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}rzslider.vertical .rz-ticks .tick{vertical-align:middle}rzslider.vertical .rz-ticks .tick .tick-value{top:auto;right:-30px;transform:translate(0,-28%)}
|
||||||
128
src/main/resources/public/css/scrollable-table.css
Normal file
128
src/main/resources/public/css/scrollable-table.css
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
.scrollableContainer {
|
||||||
|
max-height: 436px; /* sets max-height value for all standards-compliant browsers */
|
||||||
|
position: relative;
|
||||||
|
padding-top: 35px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.scrollableContainer .headerSpacer {
|
||||||
|
border: 1px solid #d5d5d5;
|
||||||
|
border-bottom-color: #bbb;
|
||||||
|
position: absolute;
|
||||||
|
height: 36px;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.scrollableContainer th .orderWrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.scrollableContainer th .orderWrapper .order {
|
||||||
|
font-size: 8pt;
|
||||||
|
color: #BDBDBD;
|
||||||
|
}
|
||||||
|
.scrollableContainer th .orderWrapper .active {
|
||||||
|
color: #464646;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollArea {
|
||||||
|
_height: expression( this.scrollHeight > 599 ? "600px" : "auto" ); /* sets max-height for IE6 */
|
||||||
|
max-height: 400px; /* sets max-height value for all standards-compliant browsers */
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #d5d5d5;
|
||||||
|
/* the implementation of this is still quite buggy; specifically, it doesn't like the
|
||||||
|
absolutely positioned headers within
|
||||||
|
-webkit-overflow-scrolling: touch; */
|
||||||
|
}
|
||||||
|
.scrollArea table {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
/*border-collapse: separate;*/
|
||||||
|
}
|
||||||
|
.scrollArea table th {
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
.scrollArea table .th-inner {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollArea table th .box {
|
||||||
|
padding: 0 8px;
|
||||||
|
padding-right: 11px; /* order icon width*/
|
||||||
|
border-left: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to hack fix firefox border issue */
|
||||||
|
@-moz-document url-prefix() {
|
||||||
|
.scrollArea table th .box{
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollArea table .th-inner .ng-scope {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.scrollArea table tr th:first-child th .box {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
.scrollArea table .th-inner.condensed {
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
.scrollArea table tbody tr td:first-child {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
.scrollArea table tbody tr td:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.scrollArea table tbody tr:first-child td {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
.scrollArea table tbody tr:last-child td {
|
||||||
|
border-bottom: 2px solid #ddd;
|
||||||
|
}
|
||||||
|
.scrollArea table tbody tr td {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollableContainer .scaler {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #CFCFCF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollableContainer th .resize-rod {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
cursor: col-resize;
|
||||||
|
width: 4px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-resizing .scrollableContainer {
|
||||||
|
cursor: col-resize;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
@@ -5,13 +5,14 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>HA Bridge</title>
|
<title>HA Bridge</title>
|
||||||
<style>
|
<link href="css/main.css" rel="stylesheet">
|
||||||
body {
|
|
||||||
padding-top: 60px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="css/bootstrap-theme.min.css" rel="stylesheet">
|
||||||
|
<link href="css/ngToast.min.css" rel="stylesheet">
|
||||||
|
<link href="css/rzslider.min.css" rel="stylesheet">
|
||||||
|
<link href="css/ngDialog.min.css" rel="stylesheet">
|
||||||
|
<link href="css/ngDialog-theme-default.min.css" rel="stylesheet">
|
||||||
|
<link href="css/scrollable-table.css" rel="stylesheet">
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script type="text/javascript" src="js/html5shiv.min.js"></script>
|
<script type="text/javascript" src="js/html5shiv.min.js"></script>
|
||||||
@@ -19,14 +20,16 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<toast></toast>
|
||||||
|
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||||
<div class="container">
|
<div class="container" ng-controller="VersionController">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle">
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="#">HA Bridge</a>
|
<a class="navbar-brand" href="#">HA Bridge</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,14 +37,13 @@
|
|||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="active"><a href="#">Home</a></li>
|
<li class="active"><a href="#">Home</a></li>
|
||||||
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
|
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
|
||||||
|
<li><a href="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Help</a></li>
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a id="dropdownMenu1" href="#" class="dropdown-toggle"
|
<a id="dLabel" href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">About <span class="caret"></span></a>
|
||||||
data-toggle="dropdown" role="button" aria-haspopup="true"
|
<ul class="dropdown-menu" aria-labelledby="dLabel">
|
||||||
aria-expanded="false">About <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
|
||||||
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
|
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
|
||||||
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
||||||
<li><a href="#">HA Bridge Version 0.3.2</a></li>
|
<li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -54,11 +56,15 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script src="js/jquery-1.11.3.min.js"></script>
|
<script src="js/jquery-1.11.3.min.js"></script>
|
||||||
<script src="js/angular.min.js"></script>
|
<script src="js/angular.min.js"></script>
|
||||||
<script src="js/angular-route.min.js"></script>
|
<script src="js/angular-route.min.js"></script>
|
||||||
<script src="js/bootstrap.min.js"></script>
|
<script src="js/angular-sanitize.min.js"></script>
|
||||||
|
<script src="js/bootstrap.min.js"></script>
|
||||||
|
<script src="js/ngToast.min.js"></script>
|
||||||
|
<script src="js/rzslider.min.js"></script>
|
||||||
|
<script src="js/ngDialog.min.js"></script>
|
||||||
|
<script src="js/angular-scrollable-table.min.js"></script>
|
||||||
<script src="scripts/app.js"></script>
|
<script src="scripts/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
16
src/main/resources/public/js/angular-sanitize.min.js
vendored
Normal file
16
src/main/resources/public/js/angular-sanitize.min.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
AngularJS v1.4.3
|
||||||
|
(c) 2010-2015 Google, Inc. http://angularjs.org
|
||||||
|
License: MIT
|
||||||
|
*/
|
||||||
|
(function(n,h,p){'use strict';function E(a){var f=[];r(f,h.noop).chars(a);return f.join("")}function g(a,f){var d={},c=a.split(","),b;for(b=0;b<c.length;b++)d[f?h.lowercase(c[b]):c[b]]=!0;return d}function F(a,f){function d(a,b,d,l){b=h.lowercase(b);if(s[b])for(;e.last()&&t[e.last()];)c("",e.last());u[b]&&e.last()==b&&c("",b);(l=v[b]||!!l)||e.push(b);var m={};d.replace(G,function(b,a,f,c,d){m[a]=q(f||c||d||"")});f.start&&f.start(b,m,l)}function c(b,a){var c=0,d;if(a=h.lowercase(a))for(c=e.length-
|
||||||
|
1;0<=c&&e[c]!=a;c--);if(0<=c){for(d=e.length-1;d>=c;d--)f.end&&f.end(e[d]);e.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,e=[],m=a,l;for(e.last=function(){return e[e.length-1]};a;){l="";k=!0;if(e.last()&&w[e.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");f.chars&&f.chars(q(b));return""}),c("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",
|
||||||
|
b)===b&&(f.comment&&f.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(x.test(a)){if(b=a.match(x))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(y))a=a.substring(b[0].length),b[0].replace(y,c),k=!1}else K.test(a)&&((b=a.match(z))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(z,d)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),f.chars&&f.chars(q(l)))}if(a==m)throw L("badparse",a);m=a}c()}function q(a){if(!a)return"";A.innerHTML=
|
||||||
|
a.replace(/</g,"<");return A.textContent}function B(a){return a.replace(/&/g,"&").replace(M,function(a){var d=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(d-55296)+(a-56320)+65536)+";"}).replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"<").replace(/>/g,">")}function r(a,f){var d=!1,c=h.bind(a,a.push);return{start:function(a,k,e){a=h.lowercase(a);!d&&w[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(k,function(d,e){var k=h.lowercase(e),g="img"===a&&"src"===k||
|
||||||
|
"background"===k;!0!==O[k]||!0===D[k]&&!f(d,g)||(c(" "),c(e),c('="'),c(B(d)),c('"'))}),c(e?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||c(B(a))}}}var L=h.$$minErr("$sanitize"),z=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,y=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\//,H=/\x3c!--(.*?)--\x3e/g,x=/<!DOCTYPE([^>]*?)>/i,
|
||||||
|
I=/<!\[CDATA\[(.*?)]]\x3e/g,M=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,N=/([^\#-~| |!])/g,v=g("area,br,col,hr,img,wbr");n=g("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");p=g("rp,rt");var u=h.extend({},p,n),s=h.extend({},n,g("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),t=h.extend({},p,g("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
||||||
|
n=g("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan,use");var w=g("script,style"),C=h.extend({},v,s,t,u,n),D=g("background,cite,href,longdesc,src,usemap,xlink:href");n=g("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width");
|
||||||
|
p=g("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
|
||||||
|
!0);var O=h.extend({},D,p,n),A=document.createElement("pre");h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(f){var d=[];F(f,r(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var f=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,d=/^mailto:/i;return function(c,b){function k(a){a&&g.push(E(a))}function e(a,
|
||||||
|
c){g.push("<a ");h.isDefined(b)&&g.push('target="',b,'" ');g.push('href="',a.replace(/"/g,"""),'">');k(c);g.push("</a>")}if(!c)return c;for(var m,l=c,g=[],n,p;m=l.match(f);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),e(n,m[0].replace(d,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular);
|
||||||
|
//# sourceMappingURL=angular-sanitize.min.js.map
|
||||||
1
src/main/resources/public/js/angular-scrollable-table.min.js
vendored
Normal file
1
src/main/resources/public/js/angular-scrollable-table.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
src/main/resources/public/js/ngDialog.min.js
vendored
Normal file
2
src/main/resources/public/js/ngDialog.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
src/main/resources/public/js/ngToast.min.js
vendored
Normal file
6
src/main/resources/public/js/ngToast.min.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* ngToast v1.5.6 (http://tameraydin.github.io/ngToast)
|
||||||
|
* Copyright 2015 Tamer Aydin (http://tamerayd.in)
|
||||||
|
* Licensed under MIT (http://tameraydin.mit-license.org/)
|
||||||
|
*/
|
||||||
|
!function(a,b,c){"use strict";b.module("ngToast.provider",[]).provider("ngToast",[function(){function a(a){for(var d=Math.floor(1e3*Math.random());c.indexOf(d)>-1;)d=Math.floor(1e3*Math.random());this.id=d,this.count=0,this.animation=e.animation,this.className=e.className,this.additionalClasses=e.additionalClasses,this.dismissOnTimeout=e.dismissOnTimeout,this.timeout=e.timeout,this.dismissButton=e.dismissButton,this.dismissButtonHtml=e.dismissButtonHtml,this.dismissOnClick=e.dismissOnClick,this.compileContent=e.compileContent,b.extend(this,a)}var c=[],d=[],e={animation:!1,className:"success",additionalClasses:null,dismissOnTimeout:!0,timeout:4e3,dismissButton:!1,dismissButtonHtml:"×",dismissOnClick:!0,compileContent:!1,combineDuplications:!1,horizontalPosition:"right",verticalPosition:"top",maxNumber:0};this.configure=function(a){b.extend(e,a)},this.$get=[function(){var b=function(a,b){return b="object"==typeof b?b:{content:b},b.className=a,this.create(b)};return{settings:e,messages:c,dismiss:function(a){if(a){for(var b=c.length-1;b>=0;b--)if(c[b].id===a)return c.splice(b,1),void d.splice(d.indexOf(a),1)}else{for(;c.length>0;)c.pop();d=[]}},create:function(b){if(b="object"==typeof b?b:{content:b},e.combineDuplications)for(var f=d.length-1;f>=0;f--){var g=c[f],h=b.className||"success";if(g.content===b.content&&g.className===h)return void c[f].count++}e.maxNumber>0&&d.length>=e.maxNumber&&this.dismiss(d[0]);var i=new a(b);return"bottom"===e.verticalPosition?c.unshift(i):c.push(i),d.push(i.id),i.id},success:function(a){return b.call(this,"success",a)},info:function(a){return b.call(this,"info",a)},warning:function(a){return b.call(this,"warning",a)},danger:function(a){return b.call(this,"danger",a)}}}]}])}(window,window.angular),function(a,b){"use strict";b.module("ngToast.directives",["ngToast.provider"]).run(["$templateCache",function(a){a.put("ngToast/toast.html",'<div class="ng-toast ng-toast--{{hPos}} ng-toast--{{vPos}} {{animation ? \'ng-toast--animate-\' + animation : \'\'}}"><ul class="ng-toast__list"><toast-message ng-repeat="message in messages" message="message" count="message.count"><span ng-bind-html="message.content"></span></toast-message></ul></div>'),a.put("ngToast/toastMessage.html",'<li class="ng-toast__message {{message.additionalClasses}}"ng-mouseenter="onMouseEnter()"ng-mouseleave="onMouseLeave()"><div class="alert alert-{{message.className}}" ng-class="{\'alert-dismissible\': message.dismissButton}"><button type="button" class="close" ng-if="message.dismissButton" ng-bind-html="message.dismissButtonHtml" ng-click="!message.dismissOnClick && dismiss()"></button><span ng-if="count" class="ng-toast__message__count">{{count + 1}}</span><span ng-if="!message.compileContent" ng-transclude></span></div></li>')}]).directive("toast",["ngToast","$templateCache","$log",function(a,b,c){return{replace:!0,restrict:"EA",templateUrl:"ngToast/toast.html",compile:function(d,e){if(e.template){var f=b.get(e.template);f?d.replaceWith(f):c.warn("ngToast: Provided template could not be loaded. Please be sure that it is populated before the <toast> element is represented.")}return function(b){b.hPos=a.settings.horizontalPosition,b.vPos=a.settings.verticalPosition,b.animation=a.settings.animation,b.messages=a.messages}}}}]).directive("toastMessage",["$timeout","$compile","ngToast",function(a,b,c){return{replace:!0,transclude:!0,restrict:"EA",scope:{message:"=",count:"="},controller:["$scope","ngToast",function(a,b){a.dismiss=function(){b.dismiss(a.message.id)}}],templateUrl:"ngToast/toastMessage.html",link:function(d,e,f,g,h){e.attr("data-message-id",d.message.id);var i,j=d.message.compileContent;if(d.cancelTimeout=function(){a.cancel(i)},d.startTimeout=function(){d.message.dismissOnTimeout&&(i=a(function(){c.dismiss(d.message.id)},d.message.timeout))},d.onMouseEnter=function(){d.cancelTimeout()},d.onMouseLeave=function(){d.startTimeout()},j){var k;h(d,function(a){k=a,e.children().append(k)}),a(function(){b(k.contents())("boolean"==typeof j?d.$parent:j,function(a){k.replaceWith(a)})},0)}d.startTimeout(),d.message.dismissOnClick&&e.bind("click",function(){c.dismiss(d.message.id),d.$apply()})}}}])}(window,window.angular),function(a,b){"use strict";b.module("ngToast",["ngSanitize","ngToast.directives","ngToast.provider"])}(window,window.angular);
|
||||||
2
src/main/resources/public/js/rzslider.min.js
vendored
Normal file
2
src/main/resources/public/js/rzslider.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,103 +1,131 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
|
||||||
<li role="presentation" class="active"><a href="#">Configuration</a></li>
|
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<div class="panel-heading">
|
<li role="presentation" class="active"><a href="#">Bridge
|
||||||
<h1 class="panel-title">Bridge settings</h1>
|
Devices</a></li>
|
||||||
</div>
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
<div class="panel-body">
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<form class="form-horizontal">
|
<div class="panel panel-default">
|
||||||
<div class="form-group">
|
<div class="panel-heading">
|
||||||
<label class="col-xs-12 col-sm-3 control-label" for="bridge-base">Bridge
|
<h2 class="panel-title">Current devices
|
||||||
server</label>
|
({{bridge.devices.length}})</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table watch="bridge.devices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="id">ID</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="deviceType">Type</th>
|
||||||
|
<th sortable-header col="targetDevice">Target</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="device in bridge.devices">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.deviceType}}</td>
|
||||||
|
<td>{{device.targetDevice}}</td>
|
||||||
|
<td>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'dim')">Test Dim</button>
|
||||||
|
<button class="btn btn-info" type="submit"
|
||||||
|
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="editDevice(device)">Edit/Copy</button>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDevice(device)">Delete</button>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">
|
||||||
|
Bridge Device DB Backup <a ng-click="toggleBk()"><span
|
||||||
|
class={{imgBkUrl}} aria-hidden="true"></a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div ng-if="visibleBk" class="animate-if" class="panel-body">
|
||||||
|
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
|
||||||
|
File Name</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input id="bridge-base" class="form-control" type="text"
|
<input id="backup-name" class="form-control" type="text"
|
||||||
ng-model="bridge.base" placeholder="URL to bridge">
|
ng-model="optionalbackupname" placeholder="Optional">
|
||||||
</div>
|
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
|
||||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
|
||||||
ng-click="testUrl(bridge.base)">Go</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<button type="submit" class="btn btn-primary"
|
||||||
<table class="table table-bordered table-striped table-hover">
|
ng-click="backupDeviceDb(optionalbackupname)">Backup
|
||||||
<thead>
|
Device DB</button>
|
||||||
<tr>
|
</div>
|
||||||
<th>Setting</th>
|
</form>
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.config.address</td>
|
|
||||||
<td>{{BridgeSettings.upnpconfigaddress}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>server.port</td>
|
|
||||||
<td>{{BridgeSettings.serverport}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.devices.db</td>
|
|
||||||
<td>{{BridgeSettings.upnpdevicedb}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>upnp.response.port</td>
|
|
||||||
<td>{{BridgeSettings.upnpresponseport}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>vera.address</td>
|
|
||||||
<td>{{BridgeSettings.veraaddress}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-controller="ErrorsController">
|
|
||||||
<div ng-if="bridge.error"
|
|
||||||
class="alert alert-warning alert-dismissible" role="alert">
|
|
||||||
<button type="button" class="close" data-dismiss="alert"
|
|
||||||
aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h2 ng-show='bridge.error != ""'>ERROR</h2>
|
|
||||||
|
|
||||||
<div ng-show='bridge.error != ""'>{{bridge.error}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">Current devices</h2>
|
|
||||||
</div>
|
|
||||||
<table class="table table-bordered table-striped table-hover">
|
<table class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>Filename</th>
|
||||||
<th>Name</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr ng-repeat="device in bridge.devices">
|
<tr ng-repeat="backup in bridge.backups">
|
||||||
<td>{{device.id}}</td>
|
<td>{{backup}}</td>
|
||||||
<td>{{device.name}}</td>
|
|
||||||
<td>{{device.deviceType}}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device.onUrl)">Test ON</button>
|
|
||||||
<button class="btn btn-info" type="submit"
|
|
||||||
ng-click="testUrl(device.offUrl)">Test OFF</button>
|
|
||||||
<button class="btn btn-warning" type="submit"
|
|
||||||
ng-click="editDevice(device)">Edit</button>
|
|
||||||
<button class="btn btn-danger" type="submit"
|
<button class="btn btn-danger" type="submit"
|
||||||
ng-click="deleteDevice(device)">Delete</button>
|
ng-click="restoreBackup(backup)">Restore</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="deleteBackup(backup)">Delete</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/ng-template" id="valueDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Select value</h2>
|
||||||
|
<p>
|
||||||
|
<input type="radio" ng-model="valueType" value="percentage" ng-change="changeScale()"> Percentage
|
||||||
|
<input type="radio" ng-model="valueType" value="raw" ng-change="changeScale()"> Raw
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<rzslider rz-slider-model="slider.value" rz-slider-options="slider.options"></rzslider>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script type="text/ng-template" id="deleteDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device to Delete?</h2>
|
||||||
|
<p>{{device.name}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,52 +1,235 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
</ul>
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/editdevice">Edit
|
||||||
|
Device</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a new device</h2>
|
<h2 class="panel-title">Edit/Copy a device</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<div class="panel-body">
|
||||||
<li class="list-group-item">
|
<p class="text-muted">This screen allows the modification of many
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
fields the bridge uses. Please use care when updating these fields as
|
||||||
<div class="form-group">
|
you may break the settings used by the bridge to call a specific end
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
point device.</p>
|
||||||
</label>
|
<p>When copying, update the name and select the "Add Bridge
|
||||||
|
Device" Button.</p>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-success"
|
||||||
Update Device</button>
|
ng-click="addDevice()">Update Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
|
||||||
URL </label>
|
</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<input type="text" class="form-control" id="device-target"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.targetDevice" placeholder="default">
|
||||||
</div>
|
</div>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<button class="btn btn-primary" ng-click="copyDevice()">Add
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
<div class="row">
|
||||||
for="device-off-url">Off URL </label>
|
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device
|
||||||
|
Type </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<select name="device-type" id="device-type"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.deviceType">
|
||||||
</div>
|
<option value="">---Types if needed---</option>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<!-- not selected / blank option -->
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
<option value="custom">Custom</option>
|
||||||
|
<option value="UDP">UDP</option>
|
||||||
|
<option value="TCP">TCP</option>
|
||||||
|
<option value="exec">Execute Script/Program</option>
|
||||||
|
<option value="switch">Switch</option>
|
||||||
|
<option value="scene">Scene</option>
|
||||||
|
<option value="macro">Macro</option>
|
||||||
|
<option value="group">Group</option>
|
||||||
|
<option value="activity">Activity</option>
|
||||||
|
<option value="button">Button</option>
|
||||||
|
<option value="thermo">Thermo</option>
|
||||||
|
<option value="passthru">Pass Thru</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
<div class="form-group">
|
||||||
</div>
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-map-type">Map Type </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-map-type" id="device-map-type"
|
||||||
|
ng-model="device.mapType">
|
||||||
|
<option value="">---Please select---</option>
|
||||||
|
<!-- not selected / blank option -->
|
||||||
|
<option value="veraDevice">Vera Device</option>
|
||||||
|
<option value="veraScene">Vera Scene</option>
|
||||||
|
<option value="harmonyActivity">Harmony Activity</option>
|
||||||
|
<option value="harmonyButton">Harmony Button</option>
|
||||||
|
<option value="nestHomeAway">Nest Home Status</option>
|
||||||
|
<option value="nestThermoSet">Nest Thermostat</option>
|
||||||
|
<option value="hueDevice">Hue Device</option>
|
||||||
|
<option value="halDevice">HAL Device</option>
|
||||||
|
<option value="halHome">HAL Home Status</option>
|
||||||
|
<option value="halThermoSet">HAL Thermostat</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.mapType" class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map
|
||||||
|
ID </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-map-id"
|
||||||
|
ng-model="device.mapId" placeholder="1111">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||||
|
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-off-url">Off
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-headers">HTTP
|
||||||
|
Headers </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-headers"
|
||||||
|
ng-model="device.headers"
|
||||||
|
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-http-verb">Http Verb </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-http-verb" id="device-http-verb"
|
||||||
|
ng-model="device.httpVerb">
|
||||||
|
<option value="">---Please select---</option>
|
||||||
|
<!-- not selected / blank option -->
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-type">Content Type </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-content-type" id="device-content-type"
|
||||||
|
ng-model="device.contentType">
|
||||||
|
<option value="">---Please select---</option>
|
||||||
|
<!-- not selected / blank option -->
|
||||||
|
<option value="application/atom+xml">application/atom+xml</option>
|
||||||
|
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||||
|
<option value="application/json">application/json</option>
|
||||||
|
<option value="application/octet-stream">application/octet-stream</option>
|
||||||
|
<option value="application/svg+xml">application/svg+xml</option>
|
||||||
|
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||||
|
<option value="application/xml">application/xml</option>
|
||||||
|
<option value="*">*</option>
|
||||||
|
<option value="multipart/form-data">multipart/form-data</option>
|
||||||
|
<option value="text/html">text/html</option>
|
||||||
|
<option value="text/plain">text/plain</option>
|
||||||
|
<option value="text/xml">text/xml</option>
|
||||||
|
<option value="*/*">*/*</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body">Content Body On</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-content-body"
|
||||||
|
ng-model="device.contentBody"
|
||||||
|
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control"
|
||||||
|
id="device-content-body-off" ng-model="device.contentBodyOff"
|
||||||
|
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -1,99 +1,250 @@
|
|||||||
<ul class="nav nav-pills" role="tablist">
|
<ul class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation"><a href="#">Configuration</a></li>
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
</ul>
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/editor">Manual
|
||||||
|
Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div ng-if="bridge.showVera" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
<h2 class="panel-title">Generate a new device/scene/control point</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<div class="panel-body">
|
||||||
<li class="list-group-item">
|
<p class="text-muted">You can generate on/off URLs by filling in
|
||||||
<p class="text-muted">You can generate on/off URLs by filling in
|
the Vera server URL, port, and device ID; or you can fill them out
|
||||||
the Vera server URL, port, and device ID; or you can fill them out
|
manually in the lower section.</p>
|
||||||
manually in the lower section.</p>
|
</div>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
||||||
|
Server URL </label>
|
||||||
|
|
||||||
<form class="form-horizontal">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<div class="form-group">
|
<input type="text" class="form-control" id="vera-base"
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
|
ng-model="vera.base"
|
||||||
Server URL </label>
|
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
||||||
|
Request Port </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-10 col-sm-2">
|
||||||
<input type="text" class="form-control" id="vera-base"
|
<input type="text" class="form-control" id="vera-port"
|
||||||
ng-model="vera.base"
|
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
||||||
placeholder="Vera URL (e.g. http://192.168.1.100)">
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-port">Vera
|
|
||||||
Request Port </label>
|
|
||||||
|
|
||||||
<div class="col-xs-10 col-sm-2">
|
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
||||||
<input type="text" class="form-control" id="vera-port"
|
ID </label>
|
||||||
ng-model="vera.port" placeholder="Vera Port (typically 3480)">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="col-xs-2 col-sm-2 control-label" for="vera-id">Device
|
<div class="col-xs-10 col-sm-2">
|
||||||
ID </label>
|
<input type="text" class="form-control" id="vera-id"
|
||||||
|
ng-model="vera.id" placeholder="ID">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-2 col-sm-2 control-label"
|
||||||
|
for="device-dim-control">Device Dim Control</label>
|
||||||
|
|
||||||
<div class="col-xs-10 col-sm-2">
|
<div class="col-xs-10 col-sm-2">
|
||||||
<input type="text" class="form-control" id="vera-id"
|
<select name="device-dim-control" id="device-dim-control"
|
||||||
ng-model="vera.id" placeholder="ID">
|
ng-model="device_dim_control">
|
||||||
</div>
|
<option value="">none</option>
|
||||||
<button type="submit" ng-click="buildUrlsUsingDevice()"
|
<option value="${intensity..byte}">Pass-thru Value</option>
|
||||||
class="col-xs-4 col-sm-2 btn btn-success">Generate Device
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
URLs</button>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
<button type="submit" ng-click="buildUrlsUsingScene()"
|
</select>
|
||||||
class="col-xs-4 col-sm-2 btn btn-success">Generate Scene
|
</div>
|
||||||
URLs</button>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</form>
|
<button type="submit"
|
||||||
</li>
|
ng-click="buildUrlsUsingDevice(device_dim_control)"
|
||||||
</ul>
|
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
|
||||||
|
Device URLs</button>
|
||||||
|
<button type="submit" ng-click="buildUrlsUsingScene()"
|
||||||
|
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
|
||||||
|
Scene URLs</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a new device</h2>
|
<h2 class="panel-title">Add a new device</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<div class="panel-body">
|
||||||
<li class="list-group-item">
|
<p class="text-muted">This area allows you to create any http or
|
||||||
<form class="form-horizontal" ng-submit="addDevice()">
|
udp call to an endpoint. You can use the default GET or select the
|
||||||
<div class="form-group">
|
http verb type below and configure a payload for either on, dim or
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
off methods. Currently, https is not supported. For Execution of a
|
||||||
</label>
|
script or program, plese fill in the path. All manually entered calls
|
||||||
|
can use Json notation of array with [{"item":"the
|
||||||
|
payload"},{"item":"another payload"}] to
|
||||||
|
execute multiple entries. Adding the value replacements
|
||||||
|
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
|
||||||
|
also work.</p>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-name"
|
<input type="text" class="form-control" id="device-name"
|
||||||
ng-model="device.name" placeholder="Device Name">
|
ng-model="device.name" placeholder="Device Name">
|
||||||
</div>
|
|
||||||
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
|
|
||||||
Add Device</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
URL </label>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device
|
||||||
|
Type </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-on-url"
|
<select name="device-type" id="device-type"
|
||||||
ng-model="device.onUrl" placeholder="URL to turn device on">
|
ng-model="device.deviceType">
|
||||||
</div>
|
<option value="">---Types if needed---</option>
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
<!-- not selected / blank option -->
|
||||||
ng-click="testUrl(device.onUrl)">Test</button>
|
<option value="custom">Custom</option>
|
||||||
|
<option value="UDP">UDP</option>
|
||||||
|
<option value="TCP">TCP</option>
|
||||||
|
<option value="exec">Execute Script/Program</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label class="col-xs-12 col-sm-2 control-label"
|
</div>
|
||||||
for="device-off-url">Off URL </label>
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
<div class="col-xs-8 col-sm-7">
|
<div class="col-xs-8 col-sm-7">
|
||||||
<input type="text" class="form-control" id="device-off-url"
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
ng-model="device.offUrl" placeholder="URL to turn device off">
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
</div>
|
|
||||||
<button class="col-xs-4 col-sm-2 btn btn-success" type="button"
|
|
||||||
ng-click="testUrl(device.offUrl)">Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
</li>
|
Clear Device</button>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||||
|
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-off-url">Off
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-headers">HTTP
|
||||||
|
Headers </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-headers"
|
||||||
|
ng-model="device.headers"
|
||||||
|
placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-http-verb">Http Verb </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-http-verb" id="device-http-verb"
|
||||||
|
ng-model="device.httpVerb">
|
||||||
|
<option value="">---Please select---</option>
|
||||||
|
<!-- not selected / blank option -->
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-type">Content Type </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-content-type" id="device-content-type"
|
||||||
|
ng-model="device.contentType">
|
||||||
|
<option value="">---Please select---</option>
|
||||||
|
<!-- not selected / blank option -->
|
||||||
|
<option value="application/atom+xml">application/atom+xml</option>
|
||||||
|
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
||||||
|
<option value="application/json">application/json</option>
|
||||||
|
<option value="application/octet-stream">application/octet-stream</option>
|
||||||
|
<option value="application/svg+xml">application/svg+xml</option>
|
||||||
|
<option value="application/xhtml+xml">application/xhtml+xml</option>
|
||||||
|
<option value="application/xml">application/xml</option>
|
||||||
|
<option value="*">*</option>
|
||||||
|
<option value="multipart/form-data">multipart/form-data</option>
|
||||||
|
<option value="text/html">text/html</option>
|
||||||
|
<option value="text/plain">text/plain</option>
|
||||||
|
<option value="text/xml">text/xml</option>
|
||||||
|
<option value="*/*">*/*</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body">Content Body On</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-content-body"
|
||||||
|
ng-model="device.contentBody"
|
||||||
|
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="device.httpVerb" class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-content-body-off">Content Body Off</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control"
|
||||||
|
id="device-content-body-off" ng-model="device.contentBodyOff"
|
||||||
|
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix visible-xs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
217
src/main/resources/public/views/haldevice.html
Normal file
217
src/main/resources/public/views/haldevice.html
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHAL" role="presentation"><a href="#/HAL">HAL</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/haldevices">HAL
|
||||||
|
Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">HAL Device List
|
||||||
|
({{bridge.haldevices.length}})</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any HAL Device, use the action buttons
|
||||||
|
to generate the device addition information below automatically. Then
|
||||||
|
you can modify the name to anything you want that will be the keyword
|
||||||
|
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||||
|
setup. The 'Already Configured HAL Devices' list below will show what
|
||||||
|
is already setup for your HAL.</p>
|
||||||
|
<p>
|
||||||
|
Also, use this select menu for which type of dim control you would
|
||||||
|
like to be generated: <select name="device-dim-control"
|
||||||
|
id="device-dim-control" ng-model="device_dim_control">
|
||||||
|
<option value="">none</option>
|
||||||
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
<p>Use the check boxes by the names to use the bulk addition
|
||||||
|
feature. Select your items and dim control type if wanted, then click
|
||||||
|
bulk add below. Your items will be added with on and off or dim and
|
||||||
|
off if selected with the name of the device from the HAL.</p>
|
||||||
|
</div>
|
||||||
|
<scrollable-table watch="bridge.haldevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">
|
||||||
|
<span><input type="checkbox" name="selectAll"
|
||||||
|
value="{{selectAll}}"
|
||||||
|
ng-checked="selectAll"
|
||||||
|
ng-click="toggleSelectAll()"> Name</span></th>
|
||||||
|
<th sortable-header col="category">Category</th>
|
||||||
|
<th sortable-header col="halname">HAL</th>
|
||||||
|
<th>On Button</th>
|
||||||
|
<th>Off Button</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="haldevice in bridge.haldevices | availableHalDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td><input type="checkbox" name="bulk.devices[]"
|
||||||
|
value="{{haldevice.haldevicename}}"
|
||||||
|
ng-checked="bulk.devices.indexOf(haldevice.haldevicename) > -1"
|
||||||
|
ng-click="toggleSelection(haldevice.haldevicename)">
|
||||||
|
{{haldevice.haldevicename}}</td>
|
||||||
|
<td>{{haldevice.haldevicetype}}</td>
|
||||||
|
<td>{{haldevice.halname}}</td>
|
||||||
|
<td>
|
||||||
|
<select name="button-on" id="button-on" ng-model="button_on">
|
||||||
|
<option ng-repeat="aButtonOn in haldevice.buttons.DeviceElements"
|
||||||
|
value="{{aButtonOn}}">{{aButtonOn.DeviceName}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select name="button-off" id="button-off" ng-model="button_off">
|
||||||
|
<option ng-repeat="aButtonOff in haldevice.buttons.DeviceElements"
|
||||||
|
value="{{aButtonOff}}">{{aButtonOff.DeviceName}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button ng-if="haldevice.haldevicetype != 'Home' && haldevice.haldevicetype != 'HVAC' && haldevice.haldevicetype != 'IrData'" class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildDeviceUrls(haldevice, device_dim_control)">Generate
|
||||||
|
Bridge Device</button>
|
||||||
|
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALHomeUrls(haldevice)">Home/Away</button>
|
||||||
|
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildButtonUrls(haldevice, button_on, button_off)">Build
|
||||||
|
A Button</button>
|
||||||
|
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALHeatUrls(haldevice)">Heat</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALCoolUrls(haldevice)">Cool</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALAutoUrls(haldevice)">Auto</button>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALOffUrls(haldevice)">Off</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildHALFanUrls(haldevice)">Fan</button>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
|
||||||
|
({{bulk.devices.length}})</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
Already Configured HAL Devices <a ng-click="toggleButtons()"><span
|
||||||
|
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table ng-if="buttonsVisible" watch="bridge.haldevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="category">Category</th>
|
||||||
|
<th sortable-header col="halname">HAL</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="device in bridge.devices | unavailableHalDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.deviceType}}</td>
|
||||||
|
<td>{{device.targetDevice}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add Bridge Device for a HAL Device</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-dim-url">Dim URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||||
|
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
145
src/main/resources/public/views/harmonyactivity.html
Normal file
145
src/main/resources/public/views/harmonyactivity.html
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation" class="active"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li role="presentation"><a href="#/harmonydevices">Harmony
|
||||||
|
Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Harmony Activity List</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any Harmony Activity, use the action
|
||||||
|
buttons to generate the device addition information below
|
||||||
|
automatically. Then you can modify the name to anything you want that
|
||||||
|
will be the keyword for Alexa. Click the 'Add Bridge Device' to
|
||||||
|
finish that selection setup. The 'Already Configured Activities' list
|
||||||
|
below will show what is already setup for your Harmony Hubs.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<scrollable-table watch="bridge.harmonyactivities">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="hub">Hub</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.id}}</td>
|
||||||
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
||||||
|
Bridge Device</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
Already Configured Activities <a ng-click="toggleButtons()"><span
|
||||||
|
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table ng-if="buttonsVisible"
|
||||||
|
watch="bridge.harmonyactivities">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="hub">Hub</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.label}}</td>
|
||||||
|
<td>{{harmonyactivity.activity.id}}</td>
|
||||||
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add a Bridge Device for a Harmony
|
||||||
|
Activity</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
169
src/main/resources/public/views/harmonydevice.html
Normal file
169
src/main/resources/public/views/harmonydevice.html
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li role="presentation"><a href="#/harmonyactivities">Harmony
|
||||||
|
Activities</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony
|
||||||
|
Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Harmony Device List</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any Harmony Device and Buttons, use the
|
||||||
|
build button to generate the configuration for this bridge device.
|
||||||
|
You can add button presses by selecting yoru devic and buttons and
|
||||||
|
then selecting the Build Button. This will allow multiple button
|
||||||
|
presses to be built for a given device. Then you can modify the name
|
||||||
|
to anything you want that will be the keyword for Alexa. Click the
|
||||||
|
'Add Bridge Device' to finish that selection setup. The 'Already
|
||||||
|
Configured Harmony Buttons' list below will show what is already
|
||||||
|
setup for your Harmony Hubs.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<scrollable-table watch="bridge.harmonydevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="hub">Hub</th>
|
||||||
|
<th>On Button</th>
|
||||||
|
<th>Off Button</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmonydevice in bridge.harmonydevices">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{harmonydevice.device.label}}</td>
|
||||||
|
<td>{{harmonydevice.device.id}}</td>
|
||||||
|
<td>{{harmonydevice.hub}}</td>
|
||||||
|
<td><select name="device-ctrlon" id="device-ctrlon"
|
||||||
|
ng-model="devicectrlon">
|
||||||
|
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup"
|
||||||
|
label="{{ctrlon.name}}">
|
||||||
|
<option ng-repeat="funcon in ctrlon.function"
|
||||||
|
value="{{funcon.action}}">{{funcon.label}}</option>
|
||||||
|
</optgroup>
|
||||||
|
</select></td>
|
||||||
|
<td><select name="device-ctrloff" id="device-ctrloff"
|
||||||
|
ng-model="devicectrloff">
|
||||||
|
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup"
|
||||||
|
label="{{ctrloff.name}}">
|
||||||
|
<option ng-repeat="funcoff in ctrloff.function"
|
||||||
|
value="{{funcoff.action}}">{{funcoff.label}}</option>
|
||||||
|
</optgroup>
|
||||||
|
</select></td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build
|
||||||
|
A Button</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
Already Configured Harmony Buttons <a ng-click="toggleButtons()"><span
|
||||||
|
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table ng-if="buttonsVisible" watch="bridge.harmonydevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Device Id</th>
|
||||||
|
<th sortable-header col="targetDevice">Hub</th>
|
||||||
|
<th>Harmony Device-Button On-Button Off</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.targetDevice}}</td>
|
||||||
|
<td>{{device.mapId}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add a Bridge Device for Harmony Buttons</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
148
src/main/resources/public/views/huedevice.html
Normal file
148
src/main/resources/public/views/huedevice.html
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/huedevices">Hue
|
||||||
|
Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Hue Device List
|
||||||
|
({{bridge.huedevices.length}})</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any Hue Device, use the action buttons
|
||||||
|
to generate the device addition information below automatically. Then
|
||||||
|
you can modify the name to anything you want that will be the keyword
|
||||||
|
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||||
|
setup. The 'Already Configured Hue Devices' list below will show what
|
||||||
|
is already setup for your Hue.</p>
|
||||||
|
<p>Use the check boxes by the names to use the bulk addition
|
||||||
|
feature. Select your items, then click bulk add below. Your items
|
||||||
|
will be added with on and off or dim and off if selected with the
|
||||||
|
name of the device from the Hue.</p>
|
||||||
|
</div>
|
||||||
|
<scrollable-table watch="bridge.huedevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name"><span><input type="checkbox" name="selectAll"
|
||||||
|
value="{{selectAll}}"
|
||||||
|
ng-checked="selectAll"
|
||||||
|
ng-click="toggleSelectAll()"> Name</span></th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="huename">Hue</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="huedevice in bridge.huedevices | availableHueDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td><input type="checkbox" name="bulk.devices[]"
|
||||||
|
value="{{huedevice.device.uniqueid}}"
|
||||||
|
ng-checked="bulk.devices.indexOf(huedevice.device.uniqueid) > -1"
|
||||||
|
ng-click="toggleSelection(huedevice.device.uniqueid)">
|
||||||
|
{{huedevice.device.name}}</td>
|
||||||
|
<td>{{huedevice.device.uniqueid}}</td>
|
||||||
|
<td>{{huedevice.huename}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildDeviceUrls(huedevice)">Generate Bridge
|
||||||
|
Device</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="bulkAddDevices()">Bulk Add
|
||||||
|
({{bulk.devices.length}})</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
Already Configured Hue Devices <a ng-click="toggleButtons()"><span
|
||||||
|
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table ng-if="buttonsVisible" watch="bridge.huedevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="huename">hue</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="huedevice in bridge.huedevices | unavailableHueDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{huedevice.device.name}}</td>
|
||||||
|
<td>{{huedevice.device.uniqueid}}</td>
|
||||||
|
<td>{{huedevice.huename}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(huedevice.device.uniqueid, 'hueDevice')">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add Bridge Device for a Hue Device</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
85
src/main/resources/public/views/logs.html
Normal file
85
src/main/resources/public/views/logs.html
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">Log Messages</h1>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-primary" type="submit" ng-click="updateLogs()">Update
|
||||||
|
Log</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<scrollable-table watch="bridge.logMsgs">
|
||||||
|
<table class="table table-striped table-bordered table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th sortable-header col="time">Time</th>
|
||||||
|
<th sortable-header col="level">Level</th>
|
||||||
|
<th sortable-header col="message">Message</th>
|
||||||
|
<th sortable-header col="component">Component</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="logMessage in bridge.logMsgs">
|
||||||
|
<td>{{logMessage.time}}</td>
|
||||||
|
<td>{{logMessage.level}}</td>
|
||||||
|
<td>{{logMessage.message}}</td>
|
||||||
|
<td>{{logMessage.component}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">
|
||||||
|
Logging Configuration <a ng-click="toggle()"><span
|
||||||
|
class={{imgUrl}} aria-hidden="true"></a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-primary" type="submit"
|
||||||
|
ng-click="updateLoggers()">Update Log Levels</button>
|
||||||
|
Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll"
|
||||||
|
ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false>
|
||||||
|
{{bridge.logShowAll}}
|
||||||
|
</p>
|
||||||
|
<scrollable-table watch="bridge.loggerInfo">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th sortable-header col="logLevel">Log Level</th>
|
||||||
|
<th sortable-header col="loggerName">Component</th>
|
||||||
|
<th>New Log Level</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="logInfo in bridge.loggerInfo">
|
||||||
|
<td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td>
|
||||||
|
<td>{{logInfo.loggerName}}</td>
|
||||||
|
<td><select name="new-log-level" id="new-log-level"
|
||||||
|
ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel">
|
||||||
|
<option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option>
|
||||||
|
</select></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
164
src/main/resources/public/views/nestactions.html
Normal file
164
src/main/resources/public/views/nestactions.html
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Nest Items List</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">For any Nest Item, use the action buttons to
|
||||||
|
generate the device addition information below automatically. Then
|
||||||
|
you can modify the name to anything you want that will be the keyword
|
||||||
|
for Alexa. Click the 'Add Bridge Device' to finish that selection
|
||||||
|
setup. The 'Already Configured Nest Items' list below will show what
|
||||||
|
is already setup for your Nest.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<scrollable-table watch="bridge.nestitems">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="type">Type</th>
|
||||||
|
<th sortable-header col="location">Location</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{nestitem.name}}</td>
|
||||||
|
<td>{{nestitem.type}}</td>
|
||||||
|
<td>{{nestitem.location}}</td>
|
||||||
|
<td>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li ng-if="nestitem.type ==='Home' " class="list-group-item">
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestHomeUrls(nestitem)">Home/Away</button>
|
||||||
|
</li>
|
||||||
|
<li ng-if="nestitem.type ==='Thermostat' " class="list-group-item">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestTempUrls(nestitem)">Temp</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestHeatUrls(nestitem)">Heat</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestCoolUrls(nestitem)">Cool</button>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestRangeUrls(nestitem)">Range</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestOffUrls(nestitem)">Off</button>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildNestFanUrls(nestitem)">Fan</button>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
Already Configured Nest Items <a ng-click="toggleButtons()"><span
|
||||||
|
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<scrollable-table ng-if="buttonsVisible" watch="bridge.nestitems">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Device Id</th>
|
||||||
|
<th>mapId</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr
|
||||||
|
ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{device.name}}</td>
|
||||||
|
<td>{{device.id}}</td>
|
||||||
|
<td>{{device.mapId}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(device.mapId, 'nest')">Delete</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add a Bridge Device for a Nest Item</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
|
||||||
|
ng-click="addDevice()">Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-off-url">Off URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-off-url"
|
||||||
|
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
320
src/main/resources/public/views/system.html
Normal file
320
src/main/resources/public/views/system.html
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/system">Bridge
|
||||||
|
Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a
|
||||||
|
href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a
|
||||||
|
href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a
|
||||||
|
href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li ng-if="bridge.showHal" role="presentation"><a
|
||||||
|
href="#/haldevices">HAL Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">Bridge Settings</h1>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
|
||||||
|
server</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input id="bridge-base" class="form-control" type="text"
|
||||||
|
ng-model="bridge.base" placeholder="URL to bridge">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
|
ng-click="goBridgeUrl(bridge.base)">Test</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form name="form">
|
||||||
|
<p>
|
||||||
|
<button ng-disabled="bridge.isInControl"
|
||||||
|
class="btn btn-success" type="submit" ng-click="saveSettings()">Save</button>
|
||||||
|
<button ng-disabled="bridge.isInControl" class="btn btn-warning"
|
||||||
|
type="submit" ng-click="bridgeReinit()">Bridge
|
||||||
|
Reinitialize</button>
|
||||||
|
<button ng-disabled="bridge.isInControl" class="btn btn-danger"
|
||||||
|
type="submit" ng-click="bridgeStop()">Bridge Stop</button>
|
||||||
|
<button class="btn btn-primary" type="submit" onclick="myRefresh()">Refresh</button>
|
||||||
|
<script>
|
||||||
|
function myRefresh() {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</p>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Setting</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr>
|
||||||
|
<td>Configuration Path and File</td>
|
||||||
|
<td><input id="bridge-settings-configfile"
|
||||||
|
class="form-control" type="text"
|
||||||
|
ng-model="bridge.settings.configfile"
|
||||||
|
placeholder="data/ha-bridge.config"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Device DB Path and File</td>
|
||||||
|
<td><input id="bridge-settings-upnpdevicedb"
|
||||||
|
class="form-control" type="text"
|
||||||
|
ng-model="bridge.settings.upnpdevicedb"
|
||||||
|
placeholder="data/device.db"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UPNP IP Address</td>
|
||||||
|
<td><input id="bridge-settings-upnpconfigaddress"
|
||||||
|
class="form-control" type="text"
|
||||||
|
ng-model="bridge.settings.upnpconfigaddress"
|
||||||
|
placeholder="192.168.1.1"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web Server Port</td>
|
||||||
|
<td><input id="bridge-settings-serverport"
|
||||||
|
class="form-control" type="number"
|
||||||
|
ng-model="bridge.settings.serverport" min="1" max="65535"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UPNP Response Port</td>
|
||||||
|
<td><input id="bridge-settings-upnpresponseport"
|
||||||
|
class="form-control" type="number"
|
||||||
|
ng-model="bridge.settings.upnpresponseport" min="1" max="65535"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Vera Names and IP Addresses</td>
|
||||||
|
<td><table
|
||||||
|
class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="vera in bridge.settings.veraaddress.devices">
|
||||||
|
<td>{{vera.name}}</td>
|
||||||
|
<td>{{vera.ip}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="removeVeratoSettings(vera.name, vera.ip)">Del</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="bridge-settings-next-vera-name"
|
||||||
|
class="form-control" type="text" ng-model="newveraname"
|
||||||
|
placeholder="A Vera"></td>
|
||||||
|
<td><input id="bridge-settings-next-vera-ip"
|
||||||
|
class="form-control" type="text" ng-model="newveraip"
|
||||||
|
placeholder="192.168.1.2"></td>
|
||||||
|
<td><button class="btn btn-success" type="submit"
|
||||||
|
ng-click="addVeratoSettings(newveraname, newveraip)">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Harmony Names and IP Addresses</td>
|
||||||
|
<td><table
|
||||||
|
class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="harmony in bridge.settings.harmonyaddress.devices">
|
||||||
|
<td>{{harmony.name}}</td>
|
||||||
|
<td>{{harmony.ip}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="bridge-settings-next-harmony-name"
|
||||||
|
class="form-control" type="text" ng-model="newharmonyname"
|
||||||
|
placeholder="A Harmony"></td>
|
||||||
|
<td><input id="bridge-settings-next-harmony-ip"
|
||||||
|
class="form-control" type="text" ng-model="newharmonyip"
|
||||||
|
placeholder="192.168.1.3"></td>
|
||||||
|
<td><button class="btn btn-success" type="submit"
|
||||||
|
ng-click="addHarmonytoSettings(newharmonyname, newharmonyip)">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Harmony Username</td>
|
||||||
|
<td><input id="bridge-settings-harmonyuser"
|
||||||
|
class="form-control" type="text"
|
||||||
|
ng-model="bridge.settings.harmonyuser"
|
||||||
|
placeholder="someone@gmail.com"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Harmony Password</td>
|
||||||
|
<td><input id="bridge-settings-harmonypwd"
|
||||||
|
class="form-control" type="password"
|
||||||
|
ng-model="bridge.settings.harmonypwd" placeholder="thepassword"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Hue Names and IP Addresses</td>
|
||||||
|
<td><table
|
||||||
|
class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="hue in bridge.settings.hueaddress.devices">
|
||||||
|
<td>{{hue.name}}</td>
|
||||||
|
<td>{{hue.ip}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="removeHuetoSettings(hue.name, hue.ip)">Del</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="bridge-settings-next-hue-name"
|
||||||
|
class="form-control" type="text" ng-model="newhuename"
|
||||||
|
placeholder="A Hue"></td>
|
||||||
|
<td><input id="bridge-settings-next-hue-ip"
|
||||||
|
class="form-control" type="text" ng-model="newhueip"
|
||||||
|
placeholder="192.168.1.3"></td>
|
||||||
|
<td><button class="btn btn-success" type="submit"
|
||||||
|
ng-click="addHuetoSettings(newhuename, newhueip)">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>HAL Names and IP Addresses</td>
|
||||||
|
<td><table
|
||||||
|
class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="hal in bridge.settings.haladdress.devices">
|
||||||
|
<td>{{hal.name}}</td>
|
||||||
|
<td>{{hal.ip}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="removeHaltoSettings(hal.name, hal.ip)">Del</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="bridge-settings-next-hal-name"
|
||||||
|
class="form-control" type="text" ng-model="newhalname"
|
||||||
|
placeholder="A Hal"></td>
|
||||||
|
<td><input id="bridge-settings-next-hal-ip"
|
||||||
|
class="form-control" type="text" ng-model="newhalip"
|
||||||
|
placeholder="192.168.1.3:82"></td>
|
||||||
|
<td><button class="btn btn-success" type="submit"
|
||||||
|
ng-click="addHaltoSettings(newhalname, newhalip)">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>HAL Token</td>
|
||||||
|
<td><input id="bridge-settings-haltoken" class="form-control"
|
||||||
|
type="password" ng-model="bridge.settings.haltoken"
|
||||||
|
placeholder="thetoken"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nest Username</td>
|
||||||
|
<td><input id="bridge-settings-nestuser" class="form-control"
|
||||||
|
type="text" ng-model="bridge.settings.nestuser"
|
||||||
|
placeholder="someone@gmail.com"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nest Password</td>
|
||||||
|
<td><input id="bridge-settings-nestpwd" class="form-control"
|
||||||
|
type="password" ng-model="bridge.settings.nestpwd"
|
||||||
|
placeholder="thepassword"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nest Temp Farenheit</td>
|
||||||
|
<td><input type="checkbox"
|
||||||
|
ng-model="bridge.settings.farenheit" ng-true-value=true
|
||||||
|
ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Button Press/Call Item Loop Sleep Interval (ms)</td>
|
||||||
|
<td><input id="bridge-settings-buttonsleep"
|
||||||
|
class="form-control" type="number" name="input"
|
||||||
|
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Log Messages to Buffer</td>
|
||||||
|
<td><input id="bridge-settings-numberoflogmessages"
|
||||||
|
class="form-control" type="number"
|
||||||
|
ng-model="bridge.settings.numberoflogmessages" min="100"
|
||||||
|
max="65535"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UPNP Strict Handling</td>
|
||||||
|
<td><input type="checkbox"
|
||||||
|
ng-model="bridge.settings.upnpstrict" ng-true-value=true
|
||||||
|
ng-false-value=false> {{bridge.settings.upnpstrict}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Trace UPNP Calls</td>
|
||||||
|
<td><input type="checkbox"
|
||||||
|
ng-model="bridge.settings.traceupnp" ng-true-value=true
|
||||||
|
ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">
|
||||||
|
Bridge Settings Backup <a ng-click="toggle()"><span
|
||||||
|
class={{imgUrl}} aria-hidden="true"></a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div ng-if="visible" class="animate-if" class="panel-body">
|
||||||
|
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
|
||||||
|
Settings File Name</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input id="backup-name" class="form-control" type="text"
|
||||||
|
ng-model="optionalbackupname" placeholder="Optional">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary"
|
||||||
|
ng-click="backupSettings(optionalbackupname)">Backup
|
||||||
|
Settings</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Filename</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="backup in bridge.configs">
|
||||||
|
<td>{{backup}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="restoreSettings(backup)">Restore</button>
|
||||||
|
<button class="btn btn-warning" type="submit"
|
||||||
|
ng-click="deleteSettingsBackup(backup)">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user