Compare commits

...

8 Commits

Author SHA1 Message Date
crush157
7f72b0311a Add option to set hue uid to 9 octets 2021-03-24 14:31:11 -04:00
BWS Systems
b3f2c25721 Merge pull request #1266 from bwssytems/dev_branch_5.3.x
Dev branch 5.3.x to create v5.4.0

#1044 Alexa app, error "Device doesn't support requested value" bug question
#1118 Device status update in Alexa App is not working correctly for ha-bridge devices bug duplicate question
#1126 Can't get XY ColorData into URL enhancement question
#1127 Can't get separate hue, saturation and brightness enhancement question
#1128 Wrong color calucation in HS mode bug question
#1131 Changing color temperatur is not working correctly bug question
#1132 Conversion from CIE to RGB incorrect bug question
#1139 Device ID creation fails bug question
#1150 Home Assistant gets null exception during initialization bug question
#1170 Alexa not sending the correct color codes duplicate
#1171 Please add option: If bright request present with on, only send dim enhancement
#1184 Alexa will not discover HABridge question
#1191 When "Use UPNP Address Interface Only" is selected, echo cannot find ha-bridge bug
#1210 [Enahnacement] Have link button timeout be configurable enhancement
#1215 Alexa unable to discover recently added devices to ha-bridge duplicate question
#1227 Feature request: ${intensity.previous} value passing control enhancement
#1239 HA-Bridge has suddenly given up itself - Exception in thread "main" java.lang.NullPointerException bug question
#1243 Alexa device discovery now broke question
#1253 HABridge hue ColorDecode 0 0 0 bug question
#1256 Homeassistant devices not appearing bug question
2020-12-14 12:20:52 -06:00
bwssystems
98008428a7 Fixed HomeAssistant issues and this is teh release for 5.4.0 2020-12-14 12:17:44 -06:00
bwssystems
675e74df7b Add switch for dim when color request is present and other items 2020-12-08 17:03:24 -06:00
bwssystems
fb7aabb780 Fix all color handling and dim with no on request 2020-12-07 18:07:42 -06:00
bwssystems
969ed352f7 Update handling of upnp and updated how unique ids are generated 2020-12-01 19:32:42 -06:00
bwssystems
c98513c365 remove .project file 2020-11-19 12:16:08 -06:00
bwssystems
add9617a07 Fix command line config path issue
When the command line config path is used and the ocnfig file has no entry for configfile a null pointer exception occurrs
2020-11-19 12:09:13 -06:00
25 changed files with 997 additions and 330 deletions

3
.gitignore vendored
View File

@@ -23,4 +23,5 @@ sftp-config\.json
# dependencies # dependencies
/node_modules /node_modules
package-lock.json package-lock.json
.project

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ha-bridge</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

103
README.md
View File

@@ -35,7 +35,7 @@ A Custom implementation path looks like this:
**NOTE: This software does not control Philips Hue devices directly. A physical Philips Hue Hub is required for that, by which the ha-bridge can then proxy all of your real Hue bridges behind this bridge.** **NOTE: This software does not control Philips Hue devices directly. A physical Philips Hue Hub is required for that, by which the ha-bridge can then proxy all of your real Hue bridges behind this bridge.**
**ISSUE: Google Home does NOT support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work. If you have an older Google Home application, this may still work. YMMV.** **ISSUE: Google Home does NOT support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work.**
**FAQ: Please look here for the current FAQs! https://github.com/bwssytems/ha-bridge/wiki/HA-Bridge-FAQs** **FAQ: Please look here for the current FAQs! https://github.com/bwssytems/ha-bridge/wiki/HA-Bridge-FAQs**
@@ -57,20 +57,20 @@ Then locate the jar and start the server with:
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below. ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
``` ```
java -jar ha-bridge-5.3.1RC2.jar java -jar ha-bridge-5.4.1.jar
``` ```
## Manual installation of ha-bridge and setup of systemd service ## Manual installation of ha-bridge and setup of systemd service
Next gen Linux systems (this includes the Raspberry Pi), use systemd to run and manage services. Next gen Linux systems (this includes the Raspberry Pi), use systemd to run and manage services.
Here is a link on how to use systemd: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units Here is a link on how to use systemd: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
Create the directory and make sure that ha-bridge-5.3.1RC2.jar is in your /home/pi/ha-bridge directory. Create the directory and make sure that ha-bridge-5.4.1.jar is in your /home/pi/ha-bridge directory.
``` ```
pi@raspberrypi:~ $ mkdir ha-bridge pi@raspberrypi:~ $ mkdir ha-bridge
pi@raspberrypi:~ $ cd ha-bridge pi@raspberrypi:~ $ cd ha-bridge
pi@raspberrypi:~/ha-bridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.3.1RC2/ha-bridge-5.3.1RC2.jar pi@raspberrypi:~/ha-bridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.4.1/ha-bridge-5.4.1.jar
``` ```
Create the ha-bridge.service unit file: Create the ha-bridge.service unit file:
@@ -89,7 +89,7 @@ After=network.target
Type=simple Type=simple
WorkingDirectory=/home/pi/ha-bridge WorkingDirectory=/home/pi/ha-bridge
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/ha-bridge/data/habridge.config /home/pi/ha-bridge/ha-bridge-5.3.1RC2.jar ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/ha-bridge/data/habridge.config /home/pi/ha-bridge/ha-bridge-5.4.1.jar
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -375,6 +375,10 @@ This setting is in bridge-id, uuid, etc. in ha-bridge hue config replies. Leave
This setting is the time used in between button presses when there is multiple buttons in a button device. It also controls the time between multiple items in a custom device call. This is defaulted to 100ms and the number represents milliseconds (1000 milliseconds = 1 second). This setting is the time used in between button presses when there is multiple buttons in a button device. It also controls the time between multiple items in a custom device call. This is defaulted to 100ms and the number represents milliseconds (1000 milliseconds = 1 second).
#### Log Messages to Buffer #### Log Messages to Buffer
This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process. This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process.
#### UPNP Original (simple version) ####
Use very simplistic UPNP handling that was used in versions previous to 4.0. (Not Recommended)
#### UPNP Advanced (use multiple responses and notifies) ####
Turns on advanced UPP that hue bridge version 1 used at the latest release, not very stable. (Not Recommended)
#### Trace UPNP Calls #### Trace UPNP Calls
Turn on tracing for upnp discovery messages to the log. The default is false. Turn on tracing for upnp discovery messages to the log. The default is false.
#### Trace State Changes #### Trace State Changes
@@ -516,6 +520,59 @@ e.g.
[{"item":{"clientId":"TestClient","topic":"Yep","message":"This is the time ${time.format(yyyy-MM-ddTHH:mm:ssXXX)}"},"type":"mqttDevice"}] [{"item":{"clientId":"TestClient","topic":"Yep","message":"This is the time ${time.format(yyyy-MM-ddTHH:mm:ssXXX)}"},"type":"mqttDevice"}]
``` ```
Listing of all intensity replacement values that can be used.
Replacement target text | Description
------------------------|------------
${intensity.percent} | Insert the whole number percentage value e.g. 45
${intensity.decimal_percent} | Insert the decimal percentage value e.g. 0.45
${intensity.byte} | Insert the byte value
${intensity.math(X)} | Insert the math function identified by X
${intensity.math(X).hex} | Insert the hex value of the math function identified by X
${intensity.percent.hex} | Insert the hex value of the integer percentage value
${intensity.byte.hex} | Insert the hex value of the byte value
${intensity.previous_percent} | Insert the previous integer percentage value
${intensity.previous_decimal_percent}Insert the previous decimal percentage value
${intensity.previous_byte} | Insert the previous byte value
Listing of all color replacement values that can be used.
Replacement target text | Description
------------------------| -----------
${color.r} | Insert the integer value of Red e.g. 123
${color.g} | Insert the integer value of Green e.g. 241
${color.b} | Insert the integer value of Blue e.g. 255
${color.rx} | Insert the hex value of Red e.g. 7BX
${color.gx} | Insert the hex value of Green e.g. F1X
${color.bx} | Insert the hex value of Blue e.g. FFX
${color.rgbx} | Insert the hex value of all rgb e.g. 7BF1FFX
${color.hsb} | Insert the hsb value e.g. 186.3636,100.0,74.1176
${color.h} | Insert the decimal value of hue e.g. 186.3636
${color.s} | Insert the decimal value of saturation e.g. 100.0
${colorbri} | Insert the integer value of the intensity
${color.milight:([01234])} | Insert the converted value for milight
Listing of all ha-bridge device data replacement values that can be used.
Replacement target text | Description
------------------------|------------
${device.id} | Insert the ID of the device
${device.uniqueid} | Insert the unique ID of the device
${device.name} | Insert the name of the device
${device.mapId} | Insert the map ID of the deivice
${device.mapType} | Insert the map type of the device
${device.deviceType} | Insert the device type of the device
${device.targetDevice} | Insert the target device of the device
${device.requesterAddress} | Insert the requester address of the device being addressed
${device.description} | Insert the description of the device
${device.comments} | Insert the comments of the device
Listing of all time data replacement values that can be used.
Replacement target text | Description
------------------------|------------
${time.format([Java SimpleDateFormat style string]) | Insert the current time described by java SimpleDateFormat string descriptor
${time.millis} | Insert the current time in milliseconds that the system returns
Also, you may want to use the REST APIs listed below to configure your devices. Also, you may want to use the REST APIs listed below to configure your devices.
## Ask Alexa ## Ask Alexa
@@ -537,41 +594,7 @@ DIM Commands| Alexa, set `<Device Name>` to `<Position>`
To see what Alexa thinks you said, you can check in the home page for your Alexa. To see what Alexa thinks you said, you can check in the home page for your Alexa.
To view or remove devices that Alexa knows about, you can use the mobile app `Menu / Settings / Connected Home` or go to http://echo.amazon.com/#cards. To view or remove devices that Alexa knows about, you can use the mobile app click on the devices icon or go to http://echo.amazon.com/#cards.
## Google Assistant
Google Home is supported as of v3.2.0 and forward, but only if the bridge is running on port 80.
**ISSUE: Google Home does NOT support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work. If you have an older Google Home application, this may still work. YMMV.**
Use the Google Home app on a phone to add new "home control" devices by going into `Settings / Home Control / +`
as described [here](https://support.google.com/googlehome/answer/7124115?hl=en&ref_topic=7125624#homecontrol).
Click on `Philips Hue` under the `Add new` section. If ha-bridge is on the same network as the
phone as well as the Home device, then the app should quickly pass through the pairing step and
populate with all of the devices. If instead it takes you to a Philips Hue login page, this means
that the bridge was not properly discovered.
Then you can say "OK Google, Turn on the office light" or whatever name you have given your configured devices.
The Google Assistant can also group lights into rooms as described in the main [help article](https://support.google.com/googlehome/answer/7072090?hl=en&ref_topic=7029100).
Here is the table of items to use to tell Google what you want to do. Note that either "OK Google"
or "Hey Google" can be used as a trigger.
To do this: | Say "Hey Google", then...
------------|--------------------------
To turn on/off a light | "Turn on <light name>"
Dim a light | "Dim the <light name>"
Brighten a light | "Brighten the <light name>"
Set a light brightness to a certain percentage | "Set <light name> to 50%"
Dim/Brighten lights by a certain percentage | "Dim/Brighten <light name> by 50%"
Turn on/off all lights in room | "Turn on/off lights in <room name>"
Turn on/off all lights | "Turn on/off all of the lights"
To see what Home thinks you said, you can ask "Hey Google, What did I say?" or check the history in the app.
New or removed devices are picked up automatically as soon as they are added/removed from ha-bridge.
No re-discovery step is necessary.
## Configuration REST API Usage ## Configuration REST API Usage
This section will describe the REST API available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this: This section will describe the REST API available for configuration. The REST body examples are all formatted for easy reading, the actual body usage should be like this:

273
java8_pom.xml Normal file
View File

@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>5.4.0</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
<description>Emulates a Philips Hue bridge to allow the Amazon Echo to hook up to other HA systems, i.e. Vera or Harmony Hub or Nest, using lightweight frameworks</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>Eclipse Paho Repo</id>
<url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>harmony-java-client</artifactId>
<version>master-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>nest-controller</artifactId>
<version>1.0.14</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>net.java.dev.eval</groupId>
<artifactId>eval</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>lifx-sdk-java</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>com.github.mob41</groupId>
<artifactId>broadlink-java-api</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>org.jmdns</groupId>
<artifactId>jmdns</artifactId>
<version>3.5.5</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>version.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M2</version>
<executions>
<execution>
<id>enforce-maven</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>3.3</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/*.txt</exclude>
<exclude>META-INF/maven/**</exclude>
<exclude>about_files/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
</filter>
<filter>
<artifact>org.slf4j:slf4j-api</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>xpp3:xpp3</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>org.igniterealtime.smack:*</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>com.github.bwssytems:harmony-java-client</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>org.eclipse.paho:org.eclipse.paho.client.mqttv3</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.bwssystems.HABridge.HABridge</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>5.3.1RC1</version> <version>5.4.1RC1-java11</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>
@@ -172,7 +172,7 @@
<configuration> <configuration>
<rules> <rules>
<requireMavenVersion> <requireMavenVersion>
<!-- Change this to Version 3.3 for Java 1.8 and Raspberry PI compilation --> <!-- Change this to Version 3.3 for Java 1.8 and Raspberry PI compilation, Java 11 is 3.6 -->
<version>3.6</version> <version>3.6</version>
</requireMavenVersion> </requireMavenVersion>
</rules> </rules>
@@ -184,7 +184,7 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<!-- Comment this release line out for Java 1.8 and Raspberry PI compilation --> <!-- Comment this release line out for Java 1.8 and Raspberry PI compilation -->
<release>11</release> <release>11</release>
<!-- Uncomment the next two lines for Java 1.8 and Raspberry PI compilation --> <!-- Uncomment the next two lines for Java 1.8 and Raspberry PI compilation -->
<!-- <source>1.8</source> --> <!-- <source>1.8</source> -->

View File

@@ -200,7 +200,10 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setNumberoflogmessages(Integer.valueOf(Configuration.NUMBER_OF_LOG_MESSAGES)); theBridgeSettings.setNumberoflogmessages(Integer.valueOf(Configuration.NUMBER_OF_LOG_MESSAGES));
if(theBridgeSettings.getButtonsleep() == null || theBridgeSettings.getButtonsleep() < 0) if(theBridgeSettings.getButtonsleep() == null || theBridgeSettings.getButtonsleep() < 0)
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP)); theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
if(theBridgeSettings.getLinkbuttontimeout() < 30)
theBridgeSettings.setLinkbuttontimeout(Configuration.LINK_BUTTON_TIMEOUT);
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera()); theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
theBridgeSettings.setFibaroconfigured(theBridgeSettings.isValidFibaro()); theBridgeSettings.setFibaroconfigured(theBridgeSettings.isValidFibaro());
@@ -250,10 +253,10 @@ public class BridgeSettings extends BackupHandler {
return; return;
try { try {
theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class); theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
} catch (Exception e) {
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
theBridgeSettings = new BridgeSettingsDescriptor();
theBridgeSettings.setConfigfile(aPath.toString()); theBridgeSettings.setConfigfile(aPath.toString());
} catch (Exception e) {
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed. Using default settings.");
theBridgeSettings = new BridgeSettingsDescriptor();
} }
} }

View File

@@ -132,6 +132,16 @@ public class BridgeSettingsDescriptor {
@SerializedName("haaddressessecured") @SerializedName("haaddressessecured")
@Expose @Expose
private boolean haaddressessecured; private boolean haaddressessecured;
@SerializedName("upnpadvanced")
@Expose
private boolean upnpadvanced;
@SerializedName("linkbuttontimeout")
@Expose
private Integer linkbuttontimeout;
@SerializedName("uidnineoctets")
@Expose
private boolean uidnineoctets;
// @SerializedName("activeloggers") // @SerializedName("activeloggers")
// @Expose // @Expose
// private List<NameValue> activeloggers; // private List<NameValue> activeloggers;
@@ -192,6 +202,10 @@ public class BridgeSettingsDescriptor {
this.upnporiginal = false; this.upnporiginal = false;
this.seedid = 100; this.seedid = 100;
this.haaddressessecured = false; this.haaddressessecured = false;
this.configfile = Configuration.CONFIG_FILE;
this.upnpadvanced = false;
this.linkbuttontimeout = Configuration.LINK_BUTTON_TIMEOUT;
this.uidnineoctets = false;
} }
public String getUpnpConfigAddress() { public String getUpnpConfigAddress() {
@@ -847,4 +861,28 @@ public class BridgeSettingsDescriptor {
public void setHaaddressessecured(boolean haaddressessecured) { public void setHaaddressessecured(boolean haaddressessecured) {
this.haaddressessecured = haaddressessecured; this.haaddressessecured = haaddressessecured;
} }
public boolean isUpnpadvanced() {
return upnpadvanced;
}
public void setUpnpadvanced(boolean upnpadvanced) {
this.upnpadvanced = upnpadvanced;
}
public Integer getLinkbuttontimeout() {
return linkbuttontimeout;
}
public void setLinkbuttontimeout(Integer linkbuttontimeout) {
this.linkbuttontimeout = linkbuttontimeout;
}
public boolean isUidnineoctets() {
return uidnineoctets;
}
public void setUidnineoctets(boolean uidnineoctets) {
this.uidnineoctets = uidnineoctets;
}
} }

View File

@@ -17,4 +17,5 @@ public class Configuration {
public static final int UPNP_SEND_DELAY = 650; public static final int UPNP_SEND_DELAY = 650;
public static final int BROADLINK_DISCOVER_PORT = 40000; public static final int BROADLINK_DISCOVER_PORT = 40000;
public static final int BROADLINK_DISCONVER_TIMEOUT = 5000; public static final int BROADLINK_DISCONVER_TIMEOUT = 5000;
public static final int LINK_BUTTON_TIMEOUT = 45;
} }

View File

@@ -276,12 +276,12 @@ public class SystemControl {
if(!request.body().isEmpty()) { if(!request.body().isEmpty()) {
linkParams = new Gson().fromJson(request.body(), LinkParams.class); linkParams = new Gson().fromJson(request.body(), LinkParams.class);
if(linkParams.getSeconds() <= 0) if(linkParams.getSeconds() <= 0)
linkParams.setSeconds(1); linkParams.setSeconds(3);
} }
else { else {
linkParams = new LinkParams(); linkParams = new LinkParams();
linkParams.setSilent(false); linkParams.setSilent(false);
linkParams.setSeconds(30); linkParams.setSeconds(bridgeSettings.getBridgeSettingsDescriptor().getLinkbuttontimeout());
} }
if(!linkParams.isSilent()) if(!linkParams.isSilent())
log.info("Link button pressed...."); log.info("Link button pressed....");

View File

@@ -2,7 +2,7 @@ package com.bwssystems.HABridge.api.hue;
public class HueConstants { public class HueConstants {
public final static String HUB_VERSION = "9999999999"; public final static String HUB_VERSION = "9999999999";
public final static String API_VERSION = "1.19.0"; public final static String API_VERSION = "1.17.0";
public final static String MODEL_ID = "BSB002"; public final static String MODEL_ID = "BSB002";
public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-"; public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-";
} }

View File

@@ -92,7 +92,13 @@ public class DeviceDescriptor{
@SerializedName("startupActions") @SerializedName("startupActions")
@Expose @Expose
private String startupActions; private String startupActions;
@SerializedName("dimNoOn")
@Expose
private boolean dimNoOn;
@SerializedName("dimOnColor")
@Expose
private boolean dimOnColor;
public String getName() { public String getName() {
return name; return name;
} }
@@ -355,4 +361,20 @@ public class DeviceDescriptor{
public void setStartupActions(String startupActions) { public void setStartupActions(String startupActions) {
this.startupActions = startupActions; this.startupActions = startupActions;
} }
public boolean isDimNoOn() {
return dimNoOn;
}
public void setDimNoOn(boolean dimNoOn) {
this.dimNoOn = dimNoOn;
}
public boolean isDimOnColor() {
return dimOnColor;
}
public void setDimOnColor(boolean dimOnColor) {
this.dimOnColor = dimOnColor;
}
} }

View File

@@ -18,7 +18,7 @@ import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.api.CallItem; import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.api.hue.DeviceState; import com.bwssystems.HABridge.api.hue.DeviceState;
import com.bwssystems.HABridge.dao.DeviceDescriptor; // import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.plugins.hue.HueHome; import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.BackupHandler; import com.bwssystems.HABridge.util.BackupHandler;
import com.bwssystems.HABridge.util.JsonTransformer; import com.bwssystems.HABridge.util.JsonTransformer;
@@ -30,6 +30,8 @@ import com.google.gson.JsonSyntaxException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/* /*
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later * This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
@@ -41,9 +43,10 @@ public class DeviceRepository extends BackupHandler {
private Gson gson; private Gson gson;
private Integer nextId; private Integer nextId;
private Integer seedId; private Integer seedId;
private boolean uidnineoctets;
private Logger log = LoggerFactory.getLogger(DeviceRepository.class); private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
public DeviceRepository(String deviceDb, Integer seedid) { public DeviceRepository(String deviceDb, Integer seedid, boolean uidnineoctets_setting) {
super(); super();
gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
repositoryPath = null; repositoryPath = null;
@@ -51,6 +54,7 @@ public class DeviceRepository extends BackupHandler {
setupParams(repositoryPath, ".bk", "device.db-"); setupParams(repositoryPath, ".bk", "device.db-");
nextId = seedid; nextId = seedid;
seedId = seedid; seedId = seedid;
uidnineoctets = uidnineoctets_setting;
_loadRepository(repositoryPath); _loadRepository(repositoryPath);
} }
@@ -188,7 +192,7 @@ public class DeviceRepository extends BackupHandler {
nextId++; nextId++;
} }
if (descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) { if (descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
descriptors[i].setUniqueid("00:11:22:33:44:55:66:" + hueUniqueId(Integer.valueOf(descriptors[i].getId()))); descriptors[i].setUniqueid(hueUniqueId(Integer.valueOf(descriptors[i].getId())));
} }
put(descriptors[i].getId(), descriptors[i]); put(descriptors[i].getId(), descriptors[i]);
theNames = theNames + " " + descriptors[i].getName() + ", "; theNames = theNames + " " + descriptors[i].getName() + ", ";
@@ -206,11 +210,10 @@ public class DeviceRepository extends BackupHandler {
DeviceDescriptor theDevice; DeviceDescriptor theDevice;
boolean findNext = true; boolean findNext = true;
nextId = seedId; nextId = seedId;
while(deviceIterator.hasNext()) { while (deviceIterator.hasNext()) {
theDevice = deviceIterator.next(); theDevice = deviceIterator.next();
if(theDevice.isLockDeviceId()) { if (theDevice.isLockDeviceId()) {
lockedIds.add(theDevice.getId()); lockedIds.add(theDevice.getId());
} }
} }
@@ -220,15 +223,15 @@ public class DeviceRepository extends BackupHandler {
theDevice = deviceIterator.next(); theDevice = deviceIterator.next();
if (!theDevice.isLockDeviceId()) { if (!theDevice.isLockDeviceId()) {
findNext = true; findNext = true;
while(findNext) { while (findNext) {
if(lockedIds.contains(String.valueOf(nextId))) { if (lockedIds.contains(String.valueOf(nextId))) {
nextId++; nextId++;
} else { } else {
findNext = false; findNext = false;
} }
} }
theDevice.setId(String.valueOf(nextId)); theDevice.setId(String.valueOf(nextId));
theDevice.setUniqueid("00:11:22:33:44:55:66:" + hueUniqueId(nextId)); theDevice.setUniqueid(hueUniqueId(nextId));
nextId++; nextId++;
} }
newdevices.put(theDevice.getId(), theDevice); newdevices.put(theDevice.getId(), theDevice);
@@ -297,27 +300,64 @@ public class DeviceRepository extends BackupHandler {
} }
private String hueUniqueId(Integer anId) { private String hueUniqueId(Integer anId) {
String theUniqueId; String theUniqueId = null;
Integer newValue; Integer newValue;
String hexValueLeft; String hexValueLeft;
String hexValueRight; String hexValueRight;
newValue = anId % 256; MessageDigest md = null;
if (newValue <= 0)
newValue = 1;
else if (newValue > 255)
newValue = 255;
hexValueLeft = HexLibrary.byteToHex(newValue.byteValue());
newValue = anId / 256;
newValue = newValue % 256;
if (newValue < 0)
newValue = 0;
else if (newValue > 255)
newValue = 255;
hexValueRight = HexLibrary.byteToHex(newValue.byteValue());
theUniqueId = String.format("%s-%s", hexValueLeft, hexValueRight).toUpperCase(); try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
log.warn("Cannot get MD5 utility to hash unique ids.");
}
if (md != null) {
md.update(anId.toString().getBytes());
byte[] digest = md.digest();
if (uidnineoctets) {
theUniqueId = String.format("00:%s:%s:%s:%s:%s:%s:%s-%s",
HexLibrary.encodeHexString(digest).substring(0, 2),
HexLibrary.encodeHexString(digest).substring(2, 4),
HexLibrary.encodeHexString(digest).substring(4, 6),
HexLibrary.encodeHexString(digest).substring(6, 8),
HexLibrary.encodeHexString(digest).substring(8, 10),
HexLibrary.encodeHexString(digest).substring(10, 12),
HexLibrary.encodeHexString(digest).substring(12, 14),
HexLibrary.encodeHexString(digest).substring(14, 16));
} else {
theUniqueId = String.format("%s:%s:%s:%s:%s:%s:%s-%s",
HexLibrary.encodeHexString(digest).substring(0, 2),
HexLibrary.encodeHexString(digest).substring(2, 4),
HexLibrary.encodeHexString(digest).substring(4, 6),
HexLibrary.encodeHexString(digest).substring(6, 8),
HexLibrary.encodeHexString(digest).substring(8, 10),
HexLibrary.encodeHexString(digest).substring(10, 12),
HexLibrary.encodeHexString(digest).substring(12, 14),
HexLibrary.encodeHexString(digest).substring(14, 16));
}
}
if (theUniqueId == null) {
newValue = anId % 256;
if (newValue <= 0)
newValue = 1;
else if (newValue > 255)
newValue = 255;
hexValueLeft = HexLibrary.byteToHex(newValue.byteValue());
newValue = anId / 256;
newValue = newValue % 256;
if (newValue < 0)
newValue = 0;
else if (newValue > 255)
newValue = 255;
hexValueRight = HexLibrary.byteToHex(newValue.byteValue());
theUniqueId = String.format("11:22:33:44:55:66:%s-%s", hexValueLeft, hexValueRight).toUpperCase();
}
return theUniqueId; return theUniqueId;
} }
} }

View File

@@ -48,7 +48,7 @@ public class DeviceResource {
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) { public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
bridgeSettings = theSettings; bridgeSettings = theSettings;
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb(), bridgeSettings.getBridgeSettingsDescriptor().getSeedid()); this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb(), bridgeSettings.getBridgeSettingsDescriptor().getSeedid(), bridgeSettings.getBridgeSettingsDescriptor().isUidnineoctets());
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb()); this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
homeManager = aHomeManager; homeManager = aHomeManager;
aGsonHandler = new GsonBuilder().create(); aGsonHandler = new GsonBuilder().create();

View File

@@ -21,6 +21,9 @@ public class BrightnessDecode {
private static final String INTENSITY_MATH_CLOSE_HEX = ").hex}"; private static final String INTENSITY_MATH_CLOSE_HEX = ").hex}";
private static final String INTENSITY_PERCENT_HEX = "${intensity.percent.hex}"; private static final String INTENSITY_PERCENT_HEX = "${intensity.percent.hex}";
private static final String INTENSITY_BYTE_HEX = "${intensity.byte.hex}"; private static final String INTENSITY_BYTE_HEX = "${intensity.byte.hex}";
private static final String INTENSITY_PREVIOUS_PERCENT = "${intensity.previous_percent}";
private static final String INTENSITY_PREVIOUS_DECIMAL_PERCENT = "${intensity.previous_decimal_percent}";
private static final String INTENSITY_PREVIOUS_BYTE = "${intensity.previous_byte}";
public static int calculateIntensity(int setIntensity, Integer targetBri, Integer targetBriInc) { public static int calculateIntensity(int setIntensity, Integer targetBri, Integer targetBriInc) {
if (targetBri != null) { if (targetBri != null) {
@@ -45,7 +48,7 @@ public class BrightnessDecode {
* intensity.math(X*1) : where X is the value from the interface call and * intensity.math(X*1) : where X is the value from the interface call and
* can use net.java.dev.eval math * can use net.java.dev.eval math
*/ */
public static String replaceIntensityValue(String request, int intensity, boolean isHex) { private static String replaceIntensityValue(String request, int previous_intensity, int intensity, boolean isHex) {
if (request == null) { if (request == null) {
return null; return null;
} }
@@ -54,6 +57,8 @@ public class BrightnessDecode {
String replaceTarget = null; String replaceTarget = null;
int percentBrightness = 0; int percentBrightness = 0;
float decimalBrightness = (float) 1.0; float decimalBrightness = (float) 1.0;
int previousPercentBrightness = 0;
float previousDecimalBrightness = (float) 1.0;
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>(); Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = null; String mathDescriptor = null;
@@ -68,6 +73,17 @@ public class BrightnessDecode {
percentBrightness = 1; percentBrightness = 1;
} }
if(previous_intensity > 0) {
previousDecimalBrightness = (float) (previous_intensity / 255.0);
if(previous_intensity > 0 && previous_intensity < 5)
previousPercentBrightness = 1;
else
previousPercentBrightness = (int) Math.round(previous_intensity / 255.0 * 100);
} else {
previousDecimalBrightness = (float) 1.0;
previousPercentBrightness = 1;
}
while(notDone) { while(notDone) {
notDone = false; notDone = false;
if (request.contains(INTENSITY_BYTE)) { if (request.contains(INTENSITY_BYTE)) {
@@ -78,6 +94,14 @@ public class BrightnessDecode {
} }
replaceTarget = INTENSITY_BYTE; replaceTarget = INTENSITY_BYTE;
notDone = true; notDone = true;
} else if (request.contains(INTENSITY_PREVIOUS_BYTE)) {
if (isHex) {
replaceValue = convertToHex(previous_intensity);
} else {
replaceValue = String.valueOf(previous_intensity);
}
replaceTarget = INTENSITY_PREVIOUS_BYTE;
notDone = true;
} else if (request.contains(INTENSITY_BYTE_HEX)) { } else if (request.contains(INTENSITY_BYTE_HEX)) {
replaceValue = convertToHex(intensity); replaceValue = convertToHex(intensity);
replaceTarget = INTENSITY_BYTE_HEX; replaceTarget = INTENSITY_BYTE_HEX;
@@ -90,6 +114,14 @@ public class BrightnessDecode {
} }
replaceTarget = INTENSITY_PERCENT; replaceTarget = INTENSITY_PERCENT;
notDone = true; notDone = true;
} else if (request.contains(INTENSITY_PREVIOUS_PERCENT)) {
if (isHex) {
replaceValue = convertToHex(previousPercentBrightness);
} else {
replaceValue = String.valueOf(previousPercentBrightness);
}
replaceTarget = INTENSITY_PREVIOUS_PERCENT;
notDone = true;
} else if (request.contains(INTENSITY_PERCENT_HEX)) { } else if (request.contains(INTENSITY_PERCENT_HEX)) {
replaceValue = convertToHex(percentBrightness); replaceValue = convertToHex(percentBrightness);
replaceTarget = INTENSITY_PERCENT_HEX; replaceTarget = INTENSITY_PERCENT_HEX;
@@ -98,6 +130,10 @@ public class BrightnessDecode {
replaceValue = String.format(Locale.ROOT, "%1.2f", decimalBrightness); replaceValue = String.format(Locale.ROOT, "%1.2f", decimalBrightness);
replaceTarget = INTENSITY_DECIMAL_PERCENT; replaceTarget = INTENSITY_DECIMAL_PERCENT;
notDone = true; notDone = true;
} else if (request.contains(INTENSITY_PREVIOUS_DECIMAL_PERCENT)) {
replaceValue = String.format(Locale.ROOT, "%1.2f", previousDecimalBrightness);
replaceTarget = INTENSITY_PREVIOUS_DECIMAL_PERCENT;
notDone = true;
} else if (request.contains(INTENSITY_MATH_CLOSE)) { } else if (request.contains(INTENSITY_MATH_CLOSE)) {
mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(), mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
request.indexOf(INTENSITY_MATH_CLOSE)); request.indexOf(INTENSITY_MATH_CLOSE));
@@ -135,7 +171,7 @@ public class BrightnessDecode {
// Helper Method // Helper Method
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) { public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex); return replaceIntensityValue(request, theIntensity, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
} }
// Apache Commons Conversion utils likes little endian too much // Apache Commons Conversion utils likes little endian too much

View File

@@ -18,6 +18,8 @@ package com.bwssystems.HABridge.hue;
* XYZ -> CIE-LAB -> XYZ * XYZ -> CIE-LAB -> XYZ
* @author Diego Catalano * @author Diego Catalano
*/ */
public class ColorConverter { public class ColorConverter {
/** /**
@@ -26,6 +28,7 @@ public class ColorConverter {
private ColorConverter() {} private ColorConverter() {}
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV}; public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
private final static double EPSILON = 0.00001;
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser // XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
@@ -259,7 +262,7 @@ public class ColorConverter {
* @param blue Blue coefficient. * @param blue Blue coefficient.
* @return Normalized RGChromaticity. Range[0..1]. * @return Normalized RGChromaticity. Range[0..1].
*/ */
public static double[] RGChromaticity(int red, int green, int blue){ public static float[] RGChromaticity(int red, int green, int blue){
double[] color = new double[5]; double[] color = new double[5];
double sum = red + green + blue; double sum = red + green + blue;
@@ -276,24 +279,7 @@ public class ColorConverter {
double rS = color[0] - 0.333; double rS = color[0] - 0.333;
double gS = color[1] - 0.333; double gS = color[1] - 0.333;
//saturation //saturationBRGBtoHSV(int red, int green, int blue){
color[3] = Math.sqrt(rS * rS + gS * gS);
//hue
color[4] = Math.atan(rS / gS);
return color;
}
/**
* RGB -> HSV.
* Adds (hue + 360) % 360 for represent hue in the range [0..359].
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return HSV color space.
*/
public static float[] RGBtoHSV(int red, int green, int blue){
float[] hsv = new float[3]; float[] hsv = new float[3];
float r = red / 255f; float r = red / 255f;
float g = green / 255f; float g = green / 255f;
@@ -630,69 +616,69 @@ public class ColorConverter {
public static int[] HunterLABtoRGB(float l, float a, float b){ public static int[] HunterLABtoRGB(float l, float a, float b){
float[] xyz = HunterLABtoXYZ(l, a, b); float[] xyz = HunterLABtoXYZ(l, a, b);
return XYZtoRGB(xyz[0], xyz[1], xyz[2]); return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
} }
/** /**
* RGB -> HLS. * RGB -> HSL.
* @param red Red coefficient. Values in the range [0..255]. * @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255]. * @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255]. * @param blue Blue coefficient. Values in the range [0..255].
* @return HLS color space. * @return HSL color space.
*/ */
public static float[] RGBtoHLS(int red, int green, int blue){ public static float[] RGBtoHSL(int red, int green, int blue){
float[] hsl = new float[3]; float[] hsl = new float[3];
float r = red / 255f; double r = red;
float g = green / 255f; double g = green;
float b = blue / 255f; double b = blue;
float max = Math.max(r,Math.max(r,b)); double max = Math.max(r,Math.max(g,b));
float min = Math.min(r,Math.min(r,b)); double min = Math.min(r,Math.min(g,b));
float delta = max - min; // double delta = max - min;
//HSK //HSK
float h = 0; Double h = 0d;
float s = 0; Double s = 0d;
float l = (max + min) / 2; Double l = 0d;
if ( delta == 0 ){ //saturation
// gray color double cnt = (max + min) / 2d;
h = 0; if (cnt <= 127d) {
s = 0.0f; s = ((max - min) / (max + min));
}
else
{
// get saturation value
s = ( l <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) );
// get hue value
float hue;
if ( r == max )
{
hue = ( ( g - b ) / 6 ) / delta;
} }
else if ( g == max ) else {
{ s = ((max - min) / (510d - max - min));
hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta;
}
else
{
hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta;
} }
// correct hue if needed //lightness
if ( hue < 0 ) l = ((max + min) / 2d) / 255d;
hue += 1;
if ( hue > 1 )
hue -= 1;
h = (int) ( hue * 360 ); //hue
} if (Math.abs(max - min) <= EPSILON) {
h = 0d;
s = 0d;
}
else {
double diff = max - min;
if (Math.abs(max - r) <= EPSILON) {
h = 60d * (g - b) / diff;
}
else if (Math.abs(max - g) <= EPSILON) {
h = 60d * (b - r) / diff + 120d;
}
else {
h = 60d * (r - g) / diff + 240d;
}
if (h < 0d) {
h += 360d;
}
}
hsl[0] = h; hsl[0] = h.floatValue();
hsl[1] = s; hsl[1] = s.floatValue();
hsl[2] = l; hsl[2] = l.floatValue();
return hsl; return hsl;
} }
@@ -931,14 +917,19 @@ public class ColorConverter {
*/ */
public static float[] XYtoXYZ(XYColorSpace xy){ public static float[] XYtoXYZ(XYColorSpace xy){
float[] xyz = new float[3]; float[] xyz = new float[3];
/* Old Way
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0]; xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
xyz[1] = xy.getBrightnessAdjusted(); xyz[1] = xy.getBrightnessAdjusted();
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]); xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
*/
// New Way
xyz[0] = xy.getXy()[0] * (xy.getBrightnessAdjusted() / xy.getXy()[1]) ;
xyz[1] = xy.getBrightnessAdjusted();
xyz[2] = (float) ((1.0 - xy.getXy()[0] - xy.getXy()[1]) * (xy.getBrightnessAdjusted() / xy.getXy()[1]));
return xyz; return xyz;
} }
public static int[] normalizeRGB(int[] rgb) { public static int[] normalizeRGB(int[] rgb) {
int[] newRGB = new int[3]; int[] newRGB = new int[3];

View File

@@ -4,12 +4,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.awt.Color; // import java.awt.Color;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.hue.ColorData; // import com.bwssystems.HABridge.hue.ColorData;
public class ColorDecode { public class ColorDecode {
private static final Logger log = LoggerFactory.getLogger(ColorDecode.class); private static final Logger log = LoggerFactory.getLogger(ColorDecode.class);
@@ -27,75 +27,83 @@ public class ColorDecode {
private static final String COLOR_BRI = "${colorbri}"; private static final String COLOR_BRI = "${colorbri}";
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}"); private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
/* This is supersceded by the next iteration function below this original one
public static List<Integer> convertHSBtoRGBOrig(HueSatBri hsb) {
List<Integer> rgb; List<Integer> rgb;
Float hue = (Float)(hsb.getHue()*1.0f); Float hue = (Float)(hsb.getHue()*1.0f);
Float saturation = (Float)(hsb.getSat()*1.0f); Float saturation = (Float)(hsb.getSat()*1.0f);
Float brightness = (Float)(hsb.getBri()*1.0f); Float brightness = (Float)(hsb.getBri()*1.0f);
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness); log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
//Convert Hue into degrees for HSB //Convert Hue into degrees for HSB
hue = hue / 182.04f; // hue = hue / 182.04f;
hue = (hue / 65535.0f) * 360.0f;
//Bri and Sat must be values from 0-1 (~percentage) //Bri and Sat must be values from 0-1 (~percentage)
brightness = brightness / 255.0f; // ightness = brightness / 255.0f;
saturation = saturation / 255.0f; // saturation = saturation / 255.0f;
brightness = brightness / 254.0f;
saturation = saturation / 254.0f;
Float r = 0f; Float r = 0f;
Float g = 0f; Float g = 0f;
Float b = 0f; Float b = 0f;
if (saturation == 0) if(brightness > 0.0f) {
{ if (saturation == 0)
r = g = b = brightness; {
r = g = b = brightness;
}
else
{
// the color wheel consists of 6 sectors.
Float sectorPos = hue / 60.0f;
int sectorNumber = (int)(Math.floor(sectorPos));
// get the fractional part of the sector
Float fractionalSector = sectorPos - sectorNumber;
// calculate values for the three axes of the color.
Float p = brightness * (1.0f - saturation);
Float q = brightness * (1.0f - (saturation * fractionalSector));
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
// assign the fractional colors to r, g, and b based on the sector the angle is in.
switch (sectorNumber)
{
case 0:
r = brightness;
g = t;
b = p;
break;
case 1:
r = q;
g = brightness;
b = p;
break;
case 2:
r = p;
g = brightness;
b = t;
break;
case 3:
r = p;
g = q;
b = brightness;
break;
case 4:
r = t;
g = p;
b = brightness;
break;
case 5:
r = brightness;
g = p;
b = q;
break;
}
}
} }
else
{
// the color wheel consists of 6 sectors.
Float sectorPos = hue / 60.0f;
int sectorNumber = (int)(Math.floor(sectorPos));
// get the fractional part of the sector
Float fractionalSector = sectorPos - sectorNumber;
// calculate values for the three axes of the color.
Float p = brightness * (1.0f - saturation);
Float q = brightness * (1.0f - (saturation * fractionalSector));
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
// assign the fractional colors to r, g, and b based on the sector the angle is in.
switch (sectorNumber)
{
case 0:
r = brightness;
g = t;
b = p;
break;
case 1:
r = q;
g = brightness;
b = p;
break;
case 2:
r = p;
g = brightness;
b = t;
break;
case 3:
r = p;
g = q;
b = brightness;
break;
case 4:
r = t;
g = p;
b = brightness;
break;
case 5:
r = brightness;
g = p;
b = q;
break;
}
}
//Check if any value is out of byte range //Check if any value is out of byte range
if (r < 0f) if (r < 0f)
{ {
@@ -114,10 +122,106 @@ public class ColorDecode {
rgb.add((int)Math.round(r*255)); rgb.add((int)Math.round(r*255));
rgb.add((int)Math.round(g*255)); rgb.add((int)Math.round(g*255));
rgb.add((int)Math.round(b*255)); rgb.add((int)Math.round(b*255));
log.debug("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " log.info("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2)); + rgb.get(2));
int theRGB = Color.HSBtoRGB(hue, saturation, brightness);
Color decodedRGB = new Color(theRGB);
log.info("Color change with HSB using java Color: " + hsb + ". Resulting RGB Values: " + decodedRGB.getRed() + " " + decodedRGB.getGreen() + " "
+ decodedRGB.getBlue());
return rgb; return rgb;
} }
*/
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
List<Integer> rgb;
Float hue = (Float)(hsb.getHue()*1.0f);
Float saturation = (Float)(hsb.getSat()*1.0f);
Float brightness = (Float)(hsb.getBri()*1.0f);
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
//Convert Hue into degrees for HSB
// hue = hue / 182.04f;
hue = (hue / 65535.0f);
//Bri and Sat must be values from 0-1 (~percentage)
// ightness = brightness / 255.0f;
// saturation = saturation / 255.0f;
brightness = brightness / 254.0f;
saturation = saturation / 254.0f;
Float r = 0f;
Float g = 0f;
Float b = 0f;
Float temp2 = 0f;
Float temp1 = 0f;
if(brightness > 0.0f) {
if (saturation == 0)
{
r = g = b = brightness;
}
else
{
temp2 = (brightness < 0.5f) ? brightness * (1.0f + saturation) : brightness + saturation - (brightness * saturation);
temp1 = 2.0f * brightness - temp2;
r = GetColorComponent(temp1, temp2, hue + 1.0f/3.0f);
g = GetColorComponent(temp1, temp2, hue);
b = GetColorComponent(temp1, temp2, hue - 1.0f/3.0f);
}
}
//Check if any value is out of byte range
if (r < 0f)
{
r = 0f;
}
if (g < 0f)
{
g = 0f;
}
if (b < 0f)
{
b = 0f;
}
rgb = new ArrayList<Integer>();
rgb.add((int)Math.round(r*255));
rgb.add((int)Math.round(g*255));
rgb.add((int)Math.round(b*255));
log.debug("Color change with HSB New: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2));
return rgb;
}
private static Float GetColorComponent(Float temp1, Float temp2, Float temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1.0f/6.0f)
{
return temp1 + (temp2 - temp1) * 6.0f * temp3;
}
if (temp3 < 0.5f)
{
return temp2;
}
if (temp3 < 2.0f/3.0f)
{
return temp1 + ((temp2 - temp1) * ((2.0f/3.0f) - temp3) * 6.0f);
}
return temp1;
}
private static Float MoveIntoRange(Float temp3)
{
if (temp3 < 0.0f) return temp3 + 1f;
if (temp3 > 1.0f) return temp3 - 1f;
return temp3;
}
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) { public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
List<Integer> rgb; List<Integer> rgb;
@@ -133,7 +237,7 @@ public class ColorDecode {
rgb.add(rgbInt[0]); rgb.add(rgbInt[0]);
rgb.add(rgbInt[1]); rgb.add(rgbInt[1]);
rgb.add(rgbInt[2]); rgb.add(rgbInt[2]);
log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " " + brightness + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
+ " " + rgb.get(2)); + " " + rgb.get(2));
return rgb; return rgb;
} }
@@ -179,10 +283,10 @@ public class ColorDecode {
private static double assureBounds(double value) { private static double assureBounds(double value) {
if (value < 0.0) { if (value < 0.0) {
value = 0; value = 0.0;
} }
if (value > 255.0) { if (value > 255.0) {
value = 255; value = 255.0;
} }
return value; return value;
} }
@@ -252,8 +356,9 @@ public class ColorDecode {
List<Double> xyData = (List<Double>) colorData.getData(); List<Double> xyData = (List<Double>) colorData.getData();
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1))); request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
} else { } else {
List<Double> xyData = (List<Double>) colorData.getData(); float[] xyz = ColorConverter.RGBtoXYZ(rgb.get(0), rgb.get(1), rgb.get(2));
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1))); XYColorSpace theXYcolor = ColorConverter.XYZtoXY(xyz[0], xyz[1], xyz[2]);
request = request.replace(COLOR_XY, String.format("%f,%f",theXYcolor.getXy()[0], theXYcolor.getXy()[1]));
} }
notDone = true; notDone = true;
} }
@@ -263,9 +368,9 @@ public class ColorDecode {
HueSatBri hslData = (HueSatBri) colorData.getData(); HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_H, String.format("%d", hslData.getHue())); request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
} else { } else {
float[] hsb = new float[3]; float[] hsb;
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb); hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float hue = hsb[0] * (float) 360.0; float hue = hsb[0];
request = request.replace(COLOR_H, String.format("%f", hue)); request = request.replace(COLOR_H, String.format("%f", hue));
} }
notDone = true; notDone = true;
@@ -276,8 +381,8 @@ public class ColorDecode {
HueSatBri hslData = (HueSatBri) colorData.getData(); HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_S, String.format("%d", hslData.getSat())); request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
} else { } else {
float[] hsb = new float[3]; float[] hsb;
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb); hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float sat = hsb[1] * (float) 100.0; float sat = hsb[1] * (float) 100.0;
request = request.replace(COLOR_S, String.format("%f", sat)); request = request.replace(COLOR_S, String.format("%f", sat));
} }
@@ -289,7 +394,7 @@ public class ColorDecode {
HueSatBri hslData = (HueSatBri) colorData.getData(); HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri())); request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
} else { } else {
request = request.replace(COLOR_BRI, String.format("%f", setIntensity)); request = request.replace(COLOR_BRI, String.format("%d", setIntensity));
} }
notDone = true; notDone = true;
} }
@@ -301,8 +406,8 @@ public class ColorDecode {
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri())); String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
} else { } else {
float[] hsb = new float[3]; float[] hsb = new float[3];
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb); hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float hue = hsb[0] * (float) 360.0; float hue = hsb[0];
float sat = hsb[1] * (float) 100.0; float sat = hsb[1] * (float) 100.0;
float bright = hsb[2] * (float) 100.0; float bright = hsb[2] * (float) 100.0;
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright)); request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));

View File

@@ -1221,12 +1221,44 @@ public class HueMulator {
isOnRequest = true; isOnRequest = true;
} }
if(device.isOnFirstDim()) {
if(isDimRequest && !device.getDeviceState().isOn()) {
isOnRequest = true;
theStateChanges.setOn(true);
// isDimRequest = false;
// isColorRequest = false;
} else if (isDimRequest && device.getDeviceState().isOn()) {
if (device.getDeviceState().getBri() == theStateChanges.getBri()) {
isOnRequest = true;
theStateChanges.setOn(true);
// isDimRequest = false;
// isColorRequest = false;
} else {
isOnRequest = false;
// isDimRequest = true;
// isColorRequest = false;
}
}
} else if (device.isOnWhenDimPresent()) {
if (isDimRequest) {
isOnRequest = true;
theStateChanges.setOn(true);
}
} else if (device.isDimNoOn()) {
if (isDimRequest && isOnRequest) {
isOnRequest = false;
}
}
if(isColorRequest && isDimRequest && !device.isDimOnColor()) {
isDimRequest = false;
}
/* Old code supperceded by the above block
if (!device.isOnFirstDim() && device.isOnWhenDimPresent() && isDimRequest && !isOnRequest) { if (!device.isOnFirstDim() && device.isOnWhenDimPresent() && isDimRequest && !isOnRequest) {
isOnRequest = true; isOnRequest = true;
theStateChanges.setOn(true); theStateChanges.setOn(true);
} else if (!device.isOnFirstDim() && !device.isOnWhenDimPresent() && isDimRequest) { } else
// isOnRequest = false;
}
if (device.isOnFirstDim() && isDimRequest && !device.getDeviceState().isOn()) { if (device.isOnFirstDim() && isDimRequest && !device.getDeviceState().isOn()) {
isOnRequest = true; isOnRequest = true;
@@ -1245,6 +1277,7 @@ public class HueMulator {
isColorRequest = false; isColorRequest = false;
} }
} }
*/
if (isOnRequest) { if (isOnRequest) {
if (bridgeSettings.isTracestate()) if (bridgeSettings.isTracestate())

View File

@@ -139,8 +139,7 @@ public class HassHome implements Home {
hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class); hassCommand = aGsonHandler.fromJson(anItem.getItem(), HassCommand.class);
else else
hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class); hassCommand = aGsonHandler.fromJson(anItem.getItem().getAsString().replaceAll("^\"|\"$", ""), HassCommand.class);
hassCommand.setBri(BrightnessDecode.replaceIntensityValue(hassCommand.getBri(), hassCommand.setBri(BrightnessDecode.calculateReplaceIntensityValue(hassCommand.getBri(), intensity, targetBri, targetBriInc, false));
BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false));
HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName()); HomeAssistant homeAssistant = getHomeAssistant(hassCommand.getHassName());
if (homeAssistant == null) { if (homeAssistant == null) {
log.warn("Should not get here, no HomeAssistants available"); log.warn("Should not get here, no HomeAssistants available");

View File

@@ -102,6 +102,10 @@ public class HomeAssistant {
if (theAuthType == null) { if (theAuthType == null) {
try { try {
theAuthType = new Gson().fromJson(hassAddress.getExtensions(), HassAuth.class); theAuthType = new Gson().fromJson(hassAddress.getExtensions(), HassAuth.class);
if(theAuthType == null) {
theAuthType = new HassAuth();
theAuthType.setLegacyauth(false);
}
} catch (Exception e) { } catch (Exception e) {
log.warn("Could not read hass auth - continuing with defaults."); log.warn("Could not read hass auth - continuing with defaults.");
theAuthType = new HassAuth(); theAuthType = new HassAuth();
@@ -114,7 +118,7 @@ public class HomeAssistant {
private NameValue[] getAuthHeader() { private NameValue[] getAuthHeader() {
if (headers == null) { if (headers == null) {
if (hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) { if (hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
headers = new NameValue[1]; headers = new NameValue[2];
headers[0] = new NameValue(); headers[0] = new NameValue();
if (isLegacyAuth()) { if (isLegacyAuth()) {
headers[0].setName("x-ha-access"); headers[0].setName("x-ha-access");
@@ -123,6 +127,9 @@ public class HomeAssistant {
headers[0].setName("Authorization"); headers[0].setName("Authorization");
headers[0].setValue("Bearer " + hassAddress.getPassword()); headers[0].setValue("Bearer " + hassAddress.getPassword());
} }
headers[1] = new NameValue();
headers[1].setName("Accept-Encoding");
headers[1].setValue("gzip");
} }
} else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) { } else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) {
headers = null; headers = null;

View File

@@ -30,6 +30,7 @@ public class UpnpListener {
private String upnpConfigIP; private String upnpConfigIP;
// private boolean strict; // private boolean strict;
private boolean upnpOriginal; private boolean upnpOriginal;
private boolean upnpAdvanced;
private boolean traceupnp; private boolean traceupnp;
private boolean useUpnpIface; private boolean useUpnpIface;
private BridgeControlDescriptor bridgeControl; private BridgeControlDescriptor bridgeControl;
@@ -38,31 +39,37 @@ public class UpnpListener {
private String httpType; private String httpType;
private HuePublicConfig aHueConfig; private HuePublicConfig aHueConfig;
private Integer theUpnpSendDelay; private Integer theUpnpSendDelay;
/* This is the minimum response needed, all others are for the advanced setting */
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n"
+ HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
/* These next 2 templates are for the advanced upnp option */
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: uuid:" + HueConstants.UUID_PREFIX + HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: uuid:" + HueConstants.UUID_PREFIX
+ "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" + HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:"
+ "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
/* These notify templates are for the advanced upnp option */
private String notifyTemplate1 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String notifyTemplate1 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + "NT: uuid:" + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + "NT: uuid:"
+ HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
+ "NT: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; + "NT: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
+ "NT: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + "NT: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
@@ -75,6 +82,7 @@ public class UpnpListener {
upnpConfigIP = theSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress(); upnpConfigIP = theSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress();
// strict = theSettings.isUpnpStrict(); // strict = theSettings.isUpnpStrict();
upnpOriginal = theSettings.getBridgeSettingsDescriptor().isUpnporiginal(); upnpOriginal = theSettings.getBridgeSettingsDescriptor().isUpnporiginal();
upnpAdvanced = theSettings.getBridgeSettingsDescriptor().isUpnpadvanced();
traceupnp = theSettings.getBridgeSettingsDescriptor().isTraceupnp(); traceupnp = theSettings.getBridgeSettingsDescriptor().isTraceupnp();
useUpnpIface = theSettings.getBridgeSettingsDescriptor().isUseupnpiface(); useUpnpIface = theSettings.getBridgeSettingsDescriptor().isUseupnpiface();
theUpnpSendDelay = theSettings.getBridgeSettingsDescriptor().getUpnpsenddelay(); theUpnpSendDelay = theSettings.getBridgeSettingsDescriptor().getUpnpsenddelay();
@@ -192,10 +200,13 @@ public class UpnpListener {
log.info("UPNP Discovery Listener running and ready...."); log.info("UPNP Discovery Listener running and ready....");
boolean loopControl = true; boolean loopControl = true;
boolean error = false; boolean error = false;
try {
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT); if(upnpAdvanced) {
} catch (SocketException e1) { try {
log.warn("Could not sent soTimeout on multi-cast socket"); upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
} catch (SocketException e1) {
log.warn("Could not sent soTimeout on multi-cast socket");
}
} }
// Instant current, previous; // Instant current, previous;
// previous = Instant.now(); // previous = Instant.now();
@@ -326,37 +337,39 @@ public class UpnpListener {
+ " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); + " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
try { if(upnpAdvanced) {
Thread.sleep(theUpnpSendDelay); try {
} catch (InterruptedException e) { Thread.sleep(theUpnpSendDelay);
// noop } catch (InterruptedException e) {
} // noop
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, }
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId, discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
bridgeSNUUID, bridgeSNUUID); Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
if (traceupnp) { bridgeSNUUID, bridgeSNUUID);
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":" if (traceupnp) {
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort); log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
} + httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort }
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); + " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
try { try {
Thread.sleep(theUpnpSendDelay); Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// noop // noop
}
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
} }
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
} }
private void sendUDPResponse(byte[] udpMessage, InetAddress requester, int sourcePort) throws IOException { private void sendUDPResponse(byte[] udpMessage, InetAddress requester, int sourcePort) throws IOException {

View File

@@ -55,10 +55,12 @@ public class UpnpSettingsResource {
+ "<depth>24</depth>\n" + "<depth>24</depth>\n"
+ "<url>hue_logo_3.png</url>\n" + "<url>hue_logo_3.png</url>\n"
+ "</icon>\n" + "</icon>\n"
+ "</iconList>\n" + "</iconList>\n";
+ "</device>\n"
+ "</root>\n";
private String hueTemplate_end = "</device>\n"
+ "</root>\n";
/* not utilizing this section any more
private String hueTemplate_mid_orig = "<serviceList>\n" private String hueTemplate_mid_orig = "<serviceList>\n"
+ "<service>\n" + "<service>\n"
+ "<serviceType>(null)</serviceType>\n" + "<serviceType>(null)</serviceType>\n"
@@ -68,7 +70,7 @@ public class UpnpSettingsResource {
+ "<SCPDURL>(null)</SCPDURL>\n" + "<SCPDURL>(null)</SCPDURL>\n"
+ "</service>\n" + "</service>\n"
+ "</serviceList>\n"; + "</serviceList>\n";
*/
public UpnpSettingsResource(BridgeSettings theBridgeSettings) { public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
super(); super();
@@ -92,16 +94,24 @@ public class UpnpSettingsResource {
String hueTemplate = null; String hueTemplate = null;
if(theSettings.isUpnporiginal()) { if(theSettings.isUpnporiginal()) {
httpLocationAddr = theSettings.getUpnpConfigAddress(); httpLocationAddr = theSettings.getUpnpConfigAddress();
hueTemplate = hueTemplate_pre + hueTemplate_mid_orig + hueTemplate_post; hueTemplate = hueTemplate_pre + hueTemplate_end;
} else { } else if(!theSettings.isUpnpadvanced()) {
if(theSettings.isUseupnpiface()) { if(theSettings.isUseupnpiface()) {
httpLocationAddr = theSettings.getUpnpConfigAddress(); httpLocationAddr = theSettings.getUpnpConfigAddress();
} else { } else {
log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port()); log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port());
httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress(); httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress();
} }
hueTemplate = hueTemplate_pre + hueTemplate_post; hueTemplate = hueTemplate_pre + hueTemplate_end;
} else {
if(theSettings.isUseupnpiface()) {
httpLocationAddr = theSettings.getUpnpConfigAddress();
} else {
log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port());
httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress();
}
hueTemplate = hueTemplate_pre + hueTemplate_post + hueTemplate_end;
} }
String bridgeIdMac = HuePublicConfig.createConfig("temp", httpLocationAddr, HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac(); String bridgeIdMac = HuePublicConfig.createConfig("temp", httpLocationAddr, HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac();

View File

@@ -479,7 +479,7 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
this.pushLinkButton = function () { this.pushLinkButton = function () {
return $http.put(this.state.systemsbase + "/presslinkbutton").then( return $http.put(this.state.systemsbase + "/presslinkbutton").then(
function (response) { function (response) {
self.displayTimer("Link your device", 30000); self.displayTimer("Link your device", self.state.settings.linkbuttontimeout * 1000);
}, },
function (error) { function (error) {
if (error.status === 401) if (error.status === 401)
@@ -1547,26 +1547,42 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
}; };
this.toXY = function (red, green, blue) { this.toXY = function (red, green, blue) {
//Gamma corrective var r = red / 255;
red = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92); var g = green / 255;
green = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92); var b = blue / 255;
blue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92);
//R
if ( r > 0.04045)
r = Math.pow(( ( r + 0.055 ) / 1.055 ), 2.4);
else
r /= 12.92;
//G
if ( g > 0.04045)
g = Math.pow(( ( g + 0.055 ) / 1.055 ), 2.4);
else
g /= 12.92;
//B
if ( b > 0.04045)
b = Math.pow(( ( b + 0.055 ) / 1.055 ), 2.4);
else
b /= 12.92;
r *= 100;
g *= 100;
b *= 100;
var x = 0.412453 * r + 0.35758 * g + 0.180423 * b;
var y = 0.212671 * r + 0.71516 * g + 0.072169 * b;
var z = 0.019334 * r + 0.119193 * g + 0.950227 * b;
var newX = x / (x + y + z);
var newY = y / (x + y + z);
var interBright = (y / 100) * 254;
var newBright = Math.round(interBright);
//Apply wide gamut conversion D65 return [newX.toPrecision(6), newY.toPrecision(6), newBright];
var X = red * 0.664511 + green * 0.154324 + blue * 0.162028;
var Y = red * 0.283881 + green * 0.668433 + blue * 0.047685;
var Z = red * 0.000088 + green * 0.072310 + blue * 0.986039;
var fx = X / (X + Y + Z);
var fy = Y / (X + Y + Z);
if (isNaN(fx)) {
fx = 0.0;
}
if (isNaN(fy)) {
fy = 0.0;
}
return [fx.toPrecision(4), fy.toPrecision(4)];
}; };
this.testUrl = function (device, type, value, valueType) { this.testUrl = function (device, type, value, valueType) {
@@ -1592,7 +1608,7 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
if (valueType === "color" && value) { if (valueType === "color" && value) {
if (addComma) if (addComma)
testBody = testBody + ","; testBody = testBody + ",";
testBody = testBody + "\"xy\": [" + value[0] + "," + value[1] + "]"; testBody = testBody + "\"xy\": [" + value[0] + "," + value[1] + "],\"bri\":" + value[2];
} }
testBody = testBody + "}"; testBody = testBody + "}";
if (testBody === "{}") { if (testBody === "{}") {

View File

@@ -114,6 +114,18 @@
ng-model="device.onFirstDim" ng-true-value=true ng-model="device.onFirstDim" ng-true-value=true
ng-false-value=false> {{device.onFirstDim}}</td> ng-false-value=false> {{device.onFirstDim}}</td>
</tr> </tr>
<tr>
<td><label>Dim only when On present (If dim is present and the on request is present, the on request will not be sent. This is overriden by the above settings.)</label></td>
<td><input type="checkbox"
ng-model="device.dimNoOn" ng-true-value=true
ng-false-value=false> {{device.dimNoOn}}</td>
</tr>
<tr>
<td><label>Send dim when color request present and dim present</label></td>
<td><input type="checkbox"
ng-model="device.dimOnColor" ng-true-value=true
ng-false-value=false> {{device.dimOnColor}}</td>
</tr>
<tr> <tr>
<td><label>Filter Address (comma separated list)</label></td> <td><label>Filter Address (comma separated list)</label></td>
<td><input type="text" class="form-control" id="device-requester-addr" <td><input type="text" class="form-control" id="device-requester-addr"

View File

@@ -824,6 +824,16 @@
<td><input type="checkbox" ng-model="bridge.settings.upnporiginal" ng-true-value=true <td><input type="checkbox" ng-model="bridge.settings.upnporiginal" ng-true-value=true
ng-false-value=false> {{bridge.settings.upnporiginal}}</td> ng-false-value=false> {{bridge.settings.upnporiginal}}</td>
</tr> </tr>
<tr>
<td>UPNP Advanced (use multiple responses and notifies)</td>
<td><input type="checkbox" ng-model="bridge.settings.upnpadvanced" ng-true-value=true
ng-false-value=false> {{bridge.settings.upnpadvanced}}</td>
</tr>
<tr>
<td>Unique ID to use 9 Octets (Renumber after saving this setting)</td>
<td><input type="checkbox" ng-model="bridge.settings.uidnineoctets" ng-true-value=true
ng-false-value=false> {{bridge.settings.uidnineoctets}}</td>
</tr>
<tr> <tr>
<td>Trace UPNP Calls</td> <td>Trace UPNP Calls</td>
<td><input type="checkbox" ng-model="bridge.settings.traceupnp" ng-true-value=true <td><input type="checkbox" ng-model="bridge.settings.traceupnp" ng-true-value=true
@@ -839,6 +849,11 @@
<td><input id="bridge-settings-upnpsenddelay" class="form-control" type="number" <td><input id="bridge-settings-upnpsenddelay" class="form-control" type="number"
ng-model="bridge.settings.upnpsenddelay" min="100" max="15000"></td> ng-model="bridge.settings.upnpsenddelay" min="100" max="15000"></td>
</tr> </tr>
<tr>
<td>Link Button Timeout (seconds)</td>
<td><input id="bridge-settings-linkbuttontimeout" class="form-control" type="number"
ng-model="bridge.settings.linkbuttontimeout" min="30"></td>
</tr>
<tr> <tr>
<td>ID Seed (start numbering from this value)</td> <td>ID Seed (start numbering from this value)</td>
<td><input id="bridge-settings-seedid" class="form-control" type="number" <td><input id="bridge-settings-seedid" class="form-control" type="number"

View File

@@ -1,5 +1,6 @@
package com.bwssystems.color.test; package com.bwssystems.color.test;
import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -17,10 +18,10 @@ public class ConvertCIEColorTestCase {
@Test @Test
public void testColorConverterXYtoRGB() { public void testColorConverterXYtoRGB() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.671254"), Double.parseDouble("0.303273"))); ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.20821628789344535"), Double.parseDouble("0.22503526273269103")));
XYColorSpace xyColor = new XYColorSpace(); XYColorSpace xyColor = new XYColorSpace();
xyColor.setBrightness(50); xyColor.setBrightness(56);
float[] xyFloat = new float[2]; float[] xyFloat = new float[2];
xyFloat[0] = xy.get(0).floatValue(); xyFloat[0] = xy.get(0).floatValue();
xyFloat[1] = xy.get(1).floatValue(); xyFloat[1] = xy.get(1).floatValue();
@@ -32,12 +33,29 @@ public class ConvertCIEColorTestCase {
rgbDecode.add(1, rgb[1]); rgbDecode.add(1, rgb[1]);
rgbDecode.add(2, rgb[2]); rgbDecode.add(2, rgb[2]);
List<Integer> assertDecode = new ArrayList<Integer>(); List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 255); assertDecode.add(0, 60);
assertDecode.add(1, 0); assertDecode.add(1, 134);
assertDecode.add(2, 5); assertDecode.add(2, 196);
Assert.assertEquals(rgbDecode, assertDecode); Assert.assertEquals(rgbDecode, assertDecode);
} }
@Test
public void testColorConverterRGBtoXY() {
int red = 60;
int green = 134;
int blue = 196;
float[] xyz = ColorConverter.RGBtoXYZ(red, green, blue);
XYColorSpace theColorSpace = ColorConverter.XYZtoXY(xyz[0], xyz[1], xyz[2]);
List<Float> xyDecode = new ArrayList<Float>();
xyDecode.add(0, theColorSpace.getXy()[0]);
xyDecode.add(1, theColorSpace.getXy()[1]);
List<Float> assertDecode = new ArrayList<Float>();
assertDecode.add(0, 0.20821705f);
assertDecode.add(1, 0.22506176f);
Assert.assertEquals(xyDecode, assertDecode);
}
@Test @Test
public void testColorConversionXYtoRGB1() { public void testColorConversionXYtoRGB1() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.671254"), Double.parseDouble("0.303273"))); ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.671254"), Double.parseDouble("0.303273")));
@@ -70,6 +88,22 @@ public class ConvertCIEColorTestCase {
Assert.assertEquals(rgbIntVal, 15270119); Assert.assertEquals(rgbIntVal, 15270119);
} }
@Test
public void testColorConversionXYtoRGB3() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.20821628789344535"), Double.parseDouble("0.22503526273269103")));
List<Integer> colorDecode = ColorDecode.convertCIEtoRGB(xy, 56);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 60);
assertDecode.add(1, 134);
assertDecode.add(2, 196);
Assert.assertEquals(colorDecode, assertDecode);
// ColorData colorData = new ColorData(ColorData.ColorMode.XY, xy);
// int rgbIntVal = ColorDecode.getIntRGB(colorData, 56);
// Assert.assertEquals(rgbIntVal, 15270119);
}
@Test @Test
public void testColorConversionHSBtoRGB1() { public void testColorConversionHSBtoRGB1() {
HueSatBri hsb = new HueSatBri(); HueSatBri hsb = new HueSatBri();
@@ -79,12 +113,30 @@ public class ConvertCIEColorTestCase {
List<Integer> colorDecode = ColorDecode.convertHSBtoRGB(hsb); List<Integer> colorDecode = ColorDecode.convertHSBtoRGB(hsb);
List<Integer> assertDecode = new ArrayList<Integer>(); List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 60); assertDecode.add(0, 61);
assertDecode.add(1, 97); assertDecode.add(1, 134);
assertDecode.add(2, 128); assertDecode.add(2, 196);
Assert.assertEquals(colorDecode, assertDecode); Assert.assertEquals(colorDecode, assertDecode);
} }
@Test
public void testColorConverterRGBtoHSB() {
int red = 61;
int green = 134;
int blue = 196;
float[] hsl = ColorConverter.RGBtoHSL(red, green, blue);
List<Integer> hsbDecode = new ArrayList<Integer>();
hsbDecode.add(0, (int) (hsl[0] / 360f * 65535f));
hsbDecode.add(1, (int) (hsl[1] * 254f));
hsbDecode.add(2, (int) (hsl[2] * 254f));
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 37783);
assertDecode.add(1, 135);
assertDecode.add(2, 127);
Assert.assertEquals(hsbDecode, assertDecode);
}
@Test @Test
public void testColorConversionCTtoRGB() { public void testColorConversionCTtoRGB() {
Integer ct = 500; Integer ct = 500;