Compare commits

...

23 Commits

Author SHA1 Message Date
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
BWS Systems
f9e9f16756 Update Readme for RC2 2020-11-09 14:20:53 -05:00
BWS Systems
f15cc0d53a Merge pull request #1238 from bwssytems/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1
2020-11-09 13:08:53 -05:00
BWS Systems
0f791c1e71 Merge pull request #1249 from marcopollacci/dev_branch_5.3.x
Dev branch 5.3.x merge changes
2020-11-09 13:07:29 -05:00
Marco Pollacci
9887042f4d Update DeviceRepository.java 2020-11-06 10:26:00 +01:00
Marco Pollacci
c840f2bc4d Update DeviceResponse.java 2020-11-06 10:07:40 +01:00
dependabot[bot]
9a355b7906 Bump junit from 4.12 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 06:42:38 +00:00
BWS Systems
0d568d8d68 Changed version to 5.3.1RC1 2020-03-26 15:31:55 -04:00
BWS Systems
f5e100667e Needed to not fix the multicast socket to a specific ip address
This is when upnp use interface only
2020-03-26 15:25:10 -04:00
BWS Systems
c376253488 Fix getting outbound route from inbound address 2020-03-26 13:34:27 -04:00
BWS Systems
a3fd2ca722 finished color decode fixes and tests, updated deviceId counting, fixing min bright value 2019-10-02 15:21:35 -05:00
BWS Systems
fe4df16e10 Continue test cases 2019-10-01 14:42:20 -05:00
BWS Systems
9399af7ec7 Merge pull request #1138 from jimirocks/proxy
Fix nginx example
2019-09-30 08:29:21 -05:00
Jiří Mikulášek
be72f7e62c Fix nginx example 2019-09-28 00:52:06 +02:00
BWS Systems
768eebfc78 Updated color conversions and tests 2019-09-26 14:12:41 -05:00
BWS Systems
79ce23b80a Continue color validation 2019-09-25 16:38:30 -05:00
BWS Systems
bddc7c1c31 Updated handling for use upnp iface and start color upgrades 2019-09-24 16:07:36 -05:00
BWS Systems
51c6ffc48a Auto stash before rebase of "origin/dev_branch_5.3.x" 2019-09-24 08:40:16 -05:00
BWS Systems
ee4afc00c0 Merge pull request #1121 from gaudryc/master
Fix the bad practice "Comparison of String objects using == or !=".
2019-08-19 08:08:19 -05:00
gaudryc
8b48f23741 Fix the bad practice "Comparison of String objects using == or !=". 2019-08-18 22:33:27 +02:00
23 changed files with 1759 additions and 427 deletions

4
.gitignore vendored
View File

@@ -12,6 +12,7 @@ data
/.settings/
/start.bat
/.classpath
/.project
sftp-config\.json
/bin/
@@ -22,4 +23,5 @@ sftp-config\.json
# dependencies
/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>

View File

@@ -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.
```
java -jar ha-bridge-5.3.0.jar
java -jar ha-bridge-5.3.1RC3.jar
```
## 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.
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.0.jar is in your /home/pi/ha-bridge directory.
Create the directory and make sure that ha-bridge-5.3.1RC3.jar is in your /home/pi/ha-bridge directory.
```
pi@raspberrypi:~ $ mkdir ha-bridge
pi@raspberrypi:~ $ cd ha-bridge
pi@raspberrypi:~/ha-bridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.3.0/ha-bridge-5.3.0.jar
pi@raspberrypi:~/ha-bridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.3.1RC3/ha-bridge-5.3.1RC3.jar
```
Create the ha-bridge.service unit file:
@@ -89,7 +89,7 @@ After=network.target
Type=simple
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.0.jar
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/ha-bridge/data/habridge.config /home/pi/ha-bridge/ha-bridge-5.3.1RC3.jar
[Install]
WantedBy=multi-user.target
@@ -222,7 +222,7 @@ proxy.server = (
```
### nginx Example
```
location /api/ {
location /api {
proxy_pass http://127.0.0.1:8080/api;
}
```

12
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>5.3.0</version>
<version>5.3.1RC4-java11</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
@@ -111,12 +111,12 @@
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -172,7 +172,7 @@
<configuration>
<rules>
<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>
</requireMavenVersion>
</rules>
@@ -184,7 +184,7 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<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>
<!-- Uncomment the next two lines for Java 1.8 and Raspberry PI compilation -->
<!-- <source>1.8</source> -->
@@ -196,7 +196,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<skipTests>true</skipTests>
<skipTests>false</skipTests>
</configuration>
</plugin>
<plugin>

View File

@@ -250,10 +250,10 @@ public class BridgeSettings extends BackupHandler {
return;
try {
theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
} catch (Exception e) {
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
theBridgeSettings = new BridgeSettingsDescriptor();
theBridgeSettings.setConfigfile(aPath.toString());
} catch (Exception e) {
log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed. Using default settings.");
theBridgeSettings = new BridgeSettingsDescriptor();
}
}

View File

@@ -132,6 +132,9 @@ public class BridgeSettingsDescriptor {
@SerializedName("haaddressessecured")
@Expose
private boolean haaddressessecured;
@SerializedName("upnpadvanced")
@Expose
private boolean upnpadvanced;
// @SerializedName("activeloggers")
// @Expose
// private List<NameValue> activeloggers;
@@ -192,6 +195,8 @@ public class BridgeSettingsDescriptor {
this.upnporiginal = false;
this.seedid = 100;
this.haaddressessecured = false;
this.configfile = Configuration.CONFIG_FILE;
this.upnpadvanced = false;
}
public String getUpnpConfigAddress() {
@@ -847,4 +852,12 @@ public class BridgeSettingsDescriptor {
public void setHaaddressessecured(boolean haaddressessecured) {
this.haaddressessecured = haaddressessecured;
}
public boolean isUpnpadvanced() {
return upnpadvanced;
}
public void setUpnpadvanced(boolean upnpadvanced) {
this.upnpadvanced = upnpadvanced;
}
}

View File

@@ -17,6 +17,7 @@ public class DeviceResponse {
private String swversion;
private String swconfigid;
private String productid;
private String productname;
public DeviceState getState() {
return state;
@@ -90,6 +91,14 @@ public class DeviceResponse {
this.productid = productid;
}
public String getProductName() {
return productname;
}
public void setProductName(String productname) {
this.productname = productname;
}
public String getLuminaireuniqueid() {
return luminaireuniqueid;
@@ -109,10 +118,11 @@ public class DeviceResponse {
if (device.isColorDevice()) {
response.setType("Extended color light");
response.setModelid("LCT010");
response.setSwversion("1.15.2_r19181");
response.setSwconfigid("F921C859");
response.setProductid("Philips-LCT010-1-A19ECLv4");
response.setModelid("LCT015");
response.setSwversion("1.46.13_r26312");
response.setSwconfigid("52E3234B");
response.setProductid("Philips-LCT015-1-A19ECLv5");
response.setProductName("Hue color lamp");
} else {
response.setType("Dimmable light");
response.setModelid("LWB007");
@@ -129,13 +139,14 @@ public class DeviceResponse {
response.setState(group.getAction());
response.setName(group.getName());
response.setUniqueid("00:17:88:5E:D3:FF-" + String.format("%02X", Integer.parseInt(group.getId())));
response.setUniqueid("00:11:22:33:44:55:66:77-" + String.format("%02X", Integer.parseInt(group.getId())));
response.setManufacturername("Philips");
response.setType("Extended color light");
response.setModelid("LCT010");
response.setSwversion("1.15.2_r19181");
response.setSwconfigid("F921C859");
response.setProductid("Philips-LCT010-1-A19ECLv4");
response.setModelid("LCT015");
response.setSwversion("1.46.13_r26312");
response.setSwconfigid("52E3234B");
response.setProductid("Philips-LCT015-1-A19ECLv5");
response.setProductName("Hue color lamp");
response.setLuminaireuniqueid(null);

View File

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

View File

@@ -92,7 +92,10 @@ public class DeviceDescriptor{
@SerializedName("startupActions")
@Expose
private String startupActions;
@SerializedName("dimNoOn")
@Expose
private boolean dimNoOn;
public String getName() {
return name;
}
@@ -355,4 +358,12 @@ public class DeviceDescriptor{
public void setStartupActions(String startupActions) {
this.startupActions = startupActions;
}
public boolean isDimNoOn() {
return dimNoOn;
}
public void setDimNoOn(boolean dimNoOn) {
this.dimNoOn = dimNoOn;
}
}

View File

@@ -30,6 +30,8 @@ import com.google.gson.JsonSyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.Arrays;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/*
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
@@ -75,6 +77,8 @@ public class DeviceRepository extends BackupHandler {
nextId = Integer.decode(list[i].getId());
}
}
nextId = nextId + 1;
}
}
@@ -186,7 +190,7 @@ public class DeviceRepository extends BackupHandler {
nextId++;
}
if (descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hueUniqueId(Integer.valueOf(descriptors[i].getId())));
descriptors[i].setUniqueid(hueUniqueId(Integer.valueOf(descriptors[i].getId())));
}
put(descriptors[i].getId(), descriptors[i]);
theNames = theNames + " " + descriptors[i].getName() + ", ";
@@ -204,11 +208,10 @@ public class DeviceRepository extends BackupHandler {
DeviceDescriptor theDevice;
boolean findNext = true;
nextId = seedId;
while(deviceIterator.hasNext()) {
while (deviceIterator.hasNext()) {
theDevice = deviceIterator.next();
if(theDevice.isLockDeviceId()) {
if (theDevice.isLockDeviceId()) {
lockedIds.add(theDevice.getId());
}
}
@@ -218,15 +221,15 @@ public class DeviceRepository extends BackupHandler {
theDevice = deviceIterator.next();
if (!theDevice.isLockDeviceId()) {
findNext = true;
while(findNext) {
if(lockedIds.contains(String.valueOf(nextId))) {
while (findNext) {
if (lockedIds.contains(String.valueOf(nextId))) {
nextId++;
} else {
findNext = false;
}
}
theDevice.setId(String.valueOf(nextId));
theDevice.setUniqueid("00:17:88:5E:D3:" + hueUniqueId(nextId));
theDevice.setUniqueid(hueUniqueId(nextId));
nextId++;
}
newdevices.put(theDevice.getId(), theDevice);
@@ -295,27 +298,51 @@ public class DeviceRepository extends BackupHandler {
}
private String hueUniqueId(Integer anId) {
String theUniqueId;
String theUniqueId = null;
Integer newValue;
String hexValueLeft;
String hexValueRight;
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());
MessageDigest md = null;
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();
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;
}
}
}

View File

@@ -26,7 +26,7 @@ public class BrightnessDecode {
if (targetBri != null) {
setIntensity = targetBri;
} else if (targetBriInc != null) {
if ((setIntensity + targetBriInc) <= 0)
if ((setIntensity + targetBriInc) <= 1)
setIntensity = targetBriInc;
else if ((setIntensity + targetBriInc) > 254)
setIntensity = targetBriInc;
@@ -53,7 +53,7 @@ public class BrightnessDecode {
String replaceValue = null;
String replaceTarget = null;
int percentBrightness = 0;
float decimalBrightness = (float) 0.0;
float decimalBrightness = (float) 1.0;
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
String mathDescriptor = null;
@@ -64,8 +64,8 @@ public class BrightnessDecode {
else
percentBrightness = (int) Math.round(intensity / 255.0 * 100);
} else {
decimalBrightness = (float) 0.0;
percentBrightness = 0;
decimalBrightness = (float) 1.0;
percentBrightness = 1;
}
while(notDone) {

View File

@@ -0,0 +1,954 @@
package com.bwssystems.HABridge.hue;
/**
* Convert between different color spaces supported.
* RGB -> CMYK -> RGB
* RGB -> YIQ -> RGB
* RGB -> YCbCr -> RGB
* RGB -> YUV -> RGB
* RGB -> RGChromaticity
* RGB -> HSV -> RGB
* RGB -> YCC -> RGB
* RGB -> YCoCg -> RGB
* RGB -> XYZ -> RGB
* RGB -> HunterLAB -> RGB
* RGB -> HLS -> RGB
* RGB -> CIE-LAB -> RGB
* XYZ -> HunterLAB -> XYZ
* XYZ -> CIE-LAB -> XYZ
* @author Diego Catalano
*/
public class ColorConverter {
/**
* Don't let anyone instantiate this class.
*/
private ColorConverter() {}
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
private final static double EPSILON = 0.00001;
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
//2o Observer (CIE 1931)
// X2, Y2, Z2
public static float[] CIE2_A = {109.850f, 100f, 35.585f}; //Incandescent
public static float[] CIE2_C = {98.074f, 100f, 118.232f};
public static float[] CIE2_D50 = {96.422f, 100f, 82.521f};
public static float[] CIE2_D55 = {95.682f, 100f, 92.149f};
public static float[] CIE2_D65 = {95.047f, 100f, 108.883f}; //Daylight
public static float[] CIE2_D75 = {94.972f, 100f, 122.638f};
public static float[] CIE2_F2 = {99.187f, 100f, 67.395f}; //Fluorescent
public static float[] CIE2_F7 = {95.044f, 100f, 108.755f};
public static float[] CIE2_F11 = {100.966f, 100f, 64.370f};
//10o Observer (CIE 1964)
// X2, Y2, Z2
public static float[] CIE10_A = {111.144f, 100f, 35.200f}; //Incandescent
public static float[] CIE10_C = {97.285f, 100f, 116.145f};
public static float[] CIE10_D50 = {96.720f, 100f, 81.427f};
public static float[] CIE10_D55 = {95.799f, 100f, 90.926f};
public static float[] CIE10_D65 = {94.811f, 100f, 107.304f}; //Daylight
public static float[] CIE10_D75 = {94.416f, 100f, 120.641f};
public static float[] CIE10_F2 = {103.280f, 100f, 69.026f}; //Fluorescent
public static float[] CIE10_F7 = {95.792f, 100f, 107.687f};
public static float[] CIE10_F11 = {103.866f, 100f, 65.627f};
/**
* RFB -> CMYK
* @param red Values in the range [0..255].
* @param green Values in the range [0..255].
* @param blue Values in the range [0..255].
* @return CMYK color space. Normalized.
*/
public static float[] RGBtoCMYK(int red, int green, int blue){
float[] cmyk = new float[4];
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
float k = 1.0f - Math.max(r, Math.max(g, b));
float c = (1f-r-k) / (1f-k);
float m = (1f-g-k) / (1f-k);
float y = (1f-b-k) / (1f-k);
cmyk[0] = c;
cmyk[1] = m;
cmyk[2] = y;
cmyk[3] = k;
return cmyk;
}
/**
* CMYK -> RGB
* @param c Cyan.
* @param m Magenta.
* @param y Yellow.
* @param k Black.
* @return RGB color space.
*/
public static int[] CMYKtoRGB(float c, float m, float y, float k){
int[] rgb = new int[3];
rgb[0] = (int)(255 * (1-c) * (1-k));
rgb[1] = (int)(255 * (1-m) * (1-k));
rgb[2] = (int)(255 * (1-y) * (1-k));
return rgb;
}
/**
* RGB -> YUV.
* Y in the range [0..1].
* U in the range [-0.5..0.5].
* V in the range [-0.5..0.5].
* @param red Values in the range [0..255].
* @param green Values in the range [0..255].
* @param blue Values in the range [0..255].
* @return YUV color space.
*/
public static float[] RGBtoYUV(int red, int green, int blue){
float r = (float)red / 255;
float g = (float)green / 255;
float b = (float)blue / 255;
float[] yuv = new float[3];
float y,u,v;
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
u = (float)(-0.14713 * r - 0.28886 * g + 0.436 * b);
v = (float)(0.615 * r - 0.51499 * g - 0.10001 * b);
yuv[0] = y;
yuv[1] = u;
yuv[2] = v;
return yuv;
}
/**
* YUV -> RGB.
* @param y Luma. In the range [0..1].
* @param u Chrominance. In the range [-0.5..0.5].
* @param v Chrominance. In the range [-0.5..0.5].
* @return RGB color space.
*/
public static int[] YUVtoRGB(float y, float u, float v){
int[] rgb = new int[3];
float r,g,b;
r = (float)((y + 0.000 * u + 1.140 * v) * 255);
g = (float)((y - 0.396 * u - 0.581 * v) * 255);
b = (float)((y + 2.029 * u + 0.000 * v) * 255);
rgb[0] = (int)r;
rgb[1] = (int)g;
rgb[2] = (int)b;
return rgb;
}
/**
* RGB -> YIQ.
* @param red Values in the range [0..255].
* @param green Values in the range [0..255].
* @param blue Values in the range [0..255].
* @return YIQ color space.
*/
public static float[] RGBtoYIQ(int red, int green, int blue){
float[] yiq = new float[3];
float y,i,q;
float r = (float)red / 255;
float g = (float)green / 255;
float b = (float)blue / 255;
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
i = (float)(0.596 * r - 0.275 * g - 0.322 * b);
q = (float)(0.212 * r - 0.523 * g + 0.311 * b);
yiq[0] = y;
yiq[1] = i;
yiq[2] = q;
return yiq;
}
/**
* YIQ -> RGB.
* @param y Luma. Values in the range [0..1].
* @param i In-phase. Values in the range [-0.5..0.5].
* @param q Quadrature. Values in the range [-0.5..0.5].
* @return RGB color space.
*/
public static int[] YIQtoRGB(double y, double i, double q){
int[] rgb = new int[3];
int r,g,b;
r = (int)((y + 0.956 * i + 0.621 * q) * 255);
g = (int)((y - 0.272 * i - 0.647 * q) * 255);
b = (int)((y - 1.105 * i + 1.702 * q) * 255);
r = Math.max(0,Math.min(255,r));
g = Math.max(0,Math.min(255,g));
b = Math.max(0,Math.min(255,b));
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
return rgb;
}
public static float[] RGBtoYCbCr(int red, int green, int blue, YCbCrColorSpace colorSpace){
float r = (float)red / 255;
float g = (float)green / 255;
float b = (float)blue / 255;
float[] YCbCr = new float[3];
float y,cb,cr;
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
cb = (float)(-0.169 * r - 0.331 * g + 0.500 * b);
cr = (float)(0.500 * r - 0.419 * g - 0.081 * b);
}
else{
y = (float)(0.2215 * r + 0.7154 * g + 0.0721 * b);
cb = (float)(-0.1145 * r - 0.3855 * g + 0.5000 * b);
cr = (float)(0.5016 * r - 0.4556 * g - 0.0459 * b);
}
YCbCr[0] = (float)y;
YCbCr[1] = (float)cb;
YCbCr[2] = (float)cr;
return YCbCr;
}
public static int[] YCbCrtoRGB(float y, float cb, float cr, YCbCrColorSpace colorSpace){
int[] rgb = new int[3];
float r,g,b;
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
r = (float)(y + 0.000 * cb + 1.403 * cr) * 255;
g = (float)(y - 0.344 * cb - 0.714 * cr) * 255;
b = (float)(y + 1.773 * cb + 0.000 * cr) * 255;
}
else{
r = (float)(y + 0.000 * cb + 1.5701 * cr) * 255;
g = (float)(y - 0.1870 * cb - 0.4664 * cr) * 255;
b = (float)(y + 1.8556 * cb + 0.000 * cr) * 255;
}
rgb[0] = (int)r;
rgb[1] = (int)g;
rgb[2] = (int)b;
return rgb;
}
/**
* Rg-Chromaticity space is already known to remove ambiguities due to illumination or surface pose.
* @see Neural Information Processing - Chi Sing Leung. p. 668
* @param red Red coefficient.
* @param green Green coefficient.
* @param blue Blue coefficient.
* @return Normalized RGChromaticity. Range[0..1].
*/
public static float[] RGChromaticity(int red, int green, int blue){
double[] color = new double[5];
double sum = red + green + blue;
//red
color[0] = red / sum;
//green
color[1] = green / sum;
//blue
color[2] = 1 - color[0] - color[1];
double rS = color[0] - 0.333;
double gS = color[1] - 0.333;
//saturationBRGBtoHSV(int red, int green, int blue){
float[] hsv = new float[3];
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
float max = Math.max(r, Math.max(g, b));
float min = Math.min(r, Math.min(g, b));
float delta = max - min;
// Hue
if (max == min){
hsv[0] = 0;
}
else if (max == r){
hsv[0] = ((g - b) / delta) * 60f;
}
else if (max == g){
hsv[0] = ((b - r) / delta + 2f) * 60f;
}
else if (max == b){
hsv[0] = ((r - g) / delta + 4f) * 60f;
}
// Saturation
if (delta == 0)
hsv[1] = 0;
else
hsv[1] = delta / max;
//Value
hsv[2] = max;
return hsv;
}
/**
* HSV -> RGB.
* @param hue Hue.
* @param saturation Saturation. In the range[0..1].
* @param value Value. In the range[0..1].
* @return RGB color space. In the range[0..255].
*/
public static int[] HSVtoRGB(float hue, float saturation, float value){
int[] rgb = new int[3];
float hi = (float)Math.floor(hue / 60.0) % 6;
float f = (float)((hue / 60.0) - Math.floor(hue / 60.0));
float p = (float)(value * (1.0 - saturation));
float q = (float)(value * (1.0 - (f * saturation)));
float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));
if (hi == 0){
rgb[0] = (int)(value * 255);
rgb[1] = (int)(t * 255);
rgb[2] = (int)(p * 255);
}
else if (hi == 1){
rgb[0] = (int)(q * 255);
rgb[1] = (int)(value * 255);
rgb[2] = (int)(p * 255);
}
else if (hi == 2){
rgb[0] = (int)(p * 255);
rgb[1] = (int)(value * 255);
rgb[2] = (int)(t * 255);
}
else if (hi == 3){
rgb[0] = (int)(p * 255);
rgb[1] = (int)(value * 255);
rgb[2] = (int)(q * 255);
}
else if (hi == 4){
rgb[0] = (int)(t * 255);
rgb[1] = (int)(value * 255);
rgb[2] = (int)(p * 255);
}
else if (hi == 5){
rgb[0] = (int)(value * 255);
rgb[1] = (int)(p * 255);
rgb[2] = (int)(q * 255);
}
return rgb;
}
/**
* RGB -> YCC.
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return YCC color space. In the range [0..1].
*/
public static float[] RGBtoYCC(int red, int green, int blue){
float[] ycc = new float[3];
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
float y = 0.213f * r + 0.419f * g + 0.081f * b;
float c1 = -0.131f * r - 0.256f * g + 0.387f * b + 0.612f;
float c2 = 0.373f * r - 0.312f * r - 0.061f * b + 0.537f;
ycc[0] = y;
ycc[1] = c1;
ycc[2] = c2;
return ycc;
}
/**
* YCC -> RGB.
* @param y Y coefficient.
* @param c1 C coefficient.
* @param c2 C coefficient.
* @return RGB color space.
*/
public static int[] YCCtoRGB(float y, float c1, float c2){
int[] rgb = new int[3];
float r = 0.981f * y + 1.315f * (c2 - 0.537f);
float g = 0.981f * y - 0.311f * (c1 - 0.612f)- 0.669f * (c2 - 0.537f);
float b = 0.981f * y + 1.601f * (c1 - 0.612f);
rgb[0] = (int)(r * 255f);
rgb[1] = (int)(g * 255f);
rgb[2] = (int)(b * 255f);
return rgb;
}
/**
* RGB -> YCoCg.
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return YCoCg color space.
*/
public static float[] RGBtoYCoCg(int red, int green, int blue){
float[] yCoCg = new float[3];
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
float y = r / 4f + g / 2f + b / 4f;
float co = r / 2f - b / 2f;
float cg = -r / 4f + g / 2f - b / 4f;
yCoCg[0] = y;
yCoCg[1] = co;
yCoCg[2] = cg;
return yCoCg;
}
/**
* YCoCg -> RGB.
* @param y Pseudo luminance, or intensity.
* @param co Orange chrominance.
* @param cg Green chrominance.
* @return RGB color space.
*/
public static int[] YCoCgtoRGB(float y, float co, float cg){
int[] rgb = new int[3];
float r = y + co - cg;
float g = y + cg;
float b = y - co - cg;
rgb[0] = (int)(r * 255f);
rgb[1] = (int)(g * 255f);
rgb[2] = (int)(b * 255f);
return rgb;
}
/**
* RGB -> XYZ
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return XYZ color space.
*/
public static float[] RGBtoXYZ(int red, int green, int blue){
float[] xyz = new float[3];
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
//R
if ( r > 0.04045)
r = (float)Math.pow(( ( r + 0.055f ) / 1.055f ), 2.4f);
else
r /= 12.92f;
//G
if ( g > 0.04045)
g = (float)Math.pow(( ( g + 0.055f ) / 1.055f ), 2.4f);
else
g /= 12.92f;
//B
if ( b > 0.04045)
b = (float)Math.pow(( ( b + 0.055f ) / 1.055f ), 2.4f);
else
b /= 12.92f;
r *= 100;
g *= 100;
b *= 100;
float x = 0.412453f * r + 0.35758f * g + 0.180423f * b;
float y = 0.212671f * r + 0.71516f * g + 0.072169f * b;
float z = 0.019334f * r + 0.119193f * g + 0.950227f * b;
xyz[0] = x;
xyz[1] = y;
xyz[2] = z;
return xyz;
}
/**
* XYZ -> RGB
* @param x X coefficient.
* @param y Y coefficient.
* @param z Z coefficient.
* @return RGB color space.
*/
public static int[] XYZtoRGB(float x, float y, float z){
int[] rgb = new int[3];
x /= 100;
y /= 100;
z /= 100;
float r = 3.240479f * x - 1.53715f * y - 0.498535f * z;
float g = -0.969256f * x + 1.875991f * y + 0.041556f * z;
float b = 0.055648f * x - 0.204043f * y + 1.057311f * z;
if ( r > 0.0031308 )
r = 1.055f * ( (float)Math.pow(r, 0.4166f) ) - 0.055f;
else
r = 12.92f * r;
if ( g > 0.0031308 )
g = 1.055f * ( (float)Math.pow(g, 0.4166f) ) - 0.055f;
else
g = 12.92f * g;
if ( b > 0.0031308 )
b = 1.055f * ( (float)Math.pow(b, 0.4166f) ) - 0.055f;
else
b = 12.92f * b;
rgb[0] = (int)(r * 255);
rgb[1] = (int)(g * 255);
rgb[2] = (int)(b * 255);
return rgb;
}
/**
* XYZ -> HunterLAB
* @param x X coefficient.
* @param y Y coefficient.
* @param z Z coefficient.
* @return HunterLab coefficient.
*/
public static float[] XYZtoHunterLAB(float x, float y, float z){
float[] hunter = new float[3];
float sqrt = (float)Math.sqrt(y);
float l = 10 * sqrt;
float a = 17.5f * (((1.02f * x) - y) / sqrt);
float b = 7f * ((y - (0.847f * z)) / sqrt);
hunter[0] = l;
hunter[1] = a;
hunter[2] = b;
return hunter;
}
/**
* HunterLAB -> XYZ
* @param l L coefficient.
* @param a A coefficient.
* @param b B coefficient.
* @return XYZ color space.
*/
public static float[] HunterLABtoXYZ(float l, float a, float b){
float[] xyz = new float[3];
float tempY = l / 10f;
float tempX = a / 17.5f * l / 10f;
float tempZ = b / 7f * l / 10f;
float y = tempY * tempY;
float x = (tempX + y) / 1.02f;
float z = -(tempZ - y) / 0.847f;
xyz[0] = x;
xyz[1] = y;
xyz[2] = z;
return xyz;
}
/**
* RGB -> HunterLAB.
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return HunterLAB color space.
*/
public static float[] RGBtoHunterLAB(int red, int green, int blue){
float[] xyz = RGBtoXYZ(red, green, blue);
return XYZtoHunterLAB(xyz[0], xyz[1], xyz[2]);
}
/**
* HunterLAB -> RGB.
* @param l L coefficient.
* @param a A coefficient.
* @param b B coefficient.
* @return RGB color space.
*/
public static int[] HunterLABtoRGB(float l, float a, float b){
float[] xyz = HunterLABtoXYZ(l, a, b);
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
}
/**
* RGB -> HSL.
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @return HSL color space.
*/
public static float[] RGBtoHSL(int red, int green, int blue){
float[] hsl = new float[3];
double r = red;
double g = green;
double b = blue;
double max = Math.max(r,Math.max(g,b));
double min = Math.min(r,Math.min(g,b));
// double delta = max - min;
//HSK
Double h = 0d;
Double s = 0d;
Double l = 0d;
//saturation
double cnt = (max + min) / 2d;
if (cnt <= 127d) {
s = ((max - min) / (max + min));
}
else {
s = ((max - min) / (510d - max - min));
}
//lightness
l = ((max + min) / 2d) / 255d;
//hue
if (Math.abs(max - min) <= EPSILON) {
h = 0d;
s = 0d;
}
else {
double diff = max - min;
if (Math.abs(max - r) <= EPSILON) {
h = 60d * (g - b) / diff;
}
else if (Math.abs(max - g) <= EPSILON) {
h = 60d * (b - r) / diff + 120d;
}
else {
h = 60d * (r - g) / diff + 240d;
}
if (h < 0d) {
h += 360d;
}
}
hsl[0] = h.floatValue();
hsl[1] = s.floatValue();
hsl[2] = l.floatValue();
return hsl;
}
/**
* HLS -> RGB.
* @param hue Hue.
* @param saturation Saturation.
* @param luminance Luminance.
* @return RGB color space.
*/
public static int[] HSLtoRGB(float hue, float saturation, float luminance){
int[] rgb = new int[3];
float r = 0, g = 0, b = 0;
if ( saturation == 0 )
{
// gray values
r = g = b = (int) ( luminance * 255 );
}
else
{
float v1, v2;
float h = (float) hue / 360;
v2 = ( luminance < 0.5 ) ?
( luminance * ( 1 + saturation ) ) :
( ( luminance + saturation ) - ( luminance * saturation ) );
v1 = 2 * luminance - v2;
r = (int) ( 255 * Hue_2_RGB( v1, v2, h + ( 1.0f / 3 ) ) );
g = (int) ( 255 * Hue_2_RGB( v1, v2, h ) );
b = (int) ( 255 * Hue_2_RGB( v1, v2, h - ( 1.0f / 3 ) ) );
}
rgb[0] = (int)r;
rgb[1] = (int)g;
rgb[2] = (int)b;
return rgb;
}
private static float Hue_2_RGB( float v1, float v2, float vH ){
if ( vH < 0 )
vH += 1;
if ( vH > 1 )
vH -= 1;
if ( ( 6 * vH ) < 1 )
return ( v1 + ( v2 - v1 ) * 6 * vH );
if ( ( 2 * vH ) < 1 )
return v2;
if ( ( 3 * vH ) < 2 )
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
return v1;
}
/**
* RGB -> CIE-LAB.
* @param red Red coefficient. Values in the range [0..255].
* @param green Green coefficient. Values in the range [0..255].
* @param blue Blue coefficient. Values in the range [0..255].
* @param tristimulus XYZ Tristimulus.
* @return CIE-LAB color space.
*/
public static float[] RGBtoLAB(int red, int green, int blue, float[] tristimulus){
float[] xyz = RGBtoXYZ(red, green, blue);
float[] lab = XYZtoLAB(xyz[0], xyz[1], xyz[2], tristimulus);
return lab;
}
/**
* CIE-LAB -> RGB.
* @param l L coefficient.
* @param a A coefficient.
* @param b B coefficient.
* @param tristimulus XYZ Tristimulus.
* @return RGB color space.
*/
public static int[] LABtoRGB(float l, float a, float b, float[] tristimulus){
float[] xyz = LABtoXYZ(l, a, b, tristimulus);
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
}
/**
* XYZ -> CIE-LAB.
* @param x X coefficient.
* @param y Y coefficient.
* @param z Z coefficient.
* @param tristimulus XYZ Tristimulus.
* @return CIE-LAB color space.
*/
public static float[] XYZtoLAB(float x, float y, float z, float[] tristimulus){
float[] lab = new float[3];
x /= tristimulus[0];
y /= tristimulus[1];
z /= tristimulus[2];
if (x > 0.008856)
x = (float)Math.pow(x,0.33f);
else
x = (7.787f * x) + ( 0.1379310344827586f );
if (y > 0.008856)
y = (float)Math.pow(y,0.33f);
else
y = (7.787f * y) + ( 0.1379310344827586f );
if (z > 0.008856)
z = (float)Math.pow(z,0.33f);
else
z = (7.787f * z) + ( 0.1379310344827586f );
lab[0] = ( 116 * y ) - 16;
lab[1] = 500 * ( x - y );
lab[2] = 200 * ( y - z );
return lab;
}
/**
* CIE-LAB -> XYZ.
* @param l L coefficient.
* @param a A coefficient.
* @param b B coefficient.
* @param tristimulus XYZ Tristimulus.
* @return XYZ color space.
*/
public static float[] LABtoXYZ(float l, float a, float b, float[] tristimulus){
float[] xyz = new float[3];
float y = ( l + 16f ) / 116f;
float x = a / 500f + y;
float z = y - b / 200f;
//Y
if ( Math.pow(y,3) > 0.008856 )
y = (float)Math.pow(y,3);
else
y = (float)(( y - 16 / 116 ) / 7.787);
//X
if ( Math.pow(x,3) > 0.008856 )
x = (float)Math.pow(x,3);
else
x = (float)(( x - 16 / 116 ) / 7.787);
// Z
if ( Math.pow(z,3) > 0.008856 )
z = (float)Math.pow(z,3);
else
z = (float)(( z - 16 / 116 ) / 7.787);
xyz[0] = x * tristimulus[0];
xyz[1] = y * tristimulus[1];
xyz[2] = z * tristimulus[2];
return xyz;
}
/**
* RGB -> C1C2C3.
* @param r Red coefficient. Values in the range [0..255].
* @param g Green coefficient. Values in the range [0..255].
* @param b Blue coefficient. Values in the range [0..255].
* @return C1C2C3 color space.
*/
public static float[] RGBtoC1C2C3(int r, int g, int b){
float[] c = new float[3];
c[0] = (float)Math.atan(r / Math.max(g, b));
c[1] = (float)Math.atan(g / Math.max(r, b));
c[2] = (float)Math.atan(b / Math.max(r, g));
return c;
}
/**
* RGB -> O1O2.
* @param r Red coefficient. Values in the range [0..255].
* @param g Green coefficient. Values in the range [0..255].
* @param b Blue coefficient. Values in the range [0..255].
* @return O1O2 color space.
*/
public static float[] RGBtoO1O2(int r, int g, int b){
float[] o = new float[2];
o[0] = (r - g) / 2f;
o[1] = (r + g) / 4f - (b / 2f);
return o;
}
/**
* RGB -> Grayscale.
* @param r Red coefficient. Values in the range [0..255].
* @param g Green coefficient. Values in the range [0..255].
* @param b Blue coefficient. Values in the range [0..255].
* @return Grayscale color space.
*/
public static float RGBtoGrayscale(int r, int g, int b){
return r*0.2125f + g*0.7154f + b*0.0721f;
}
/**
* XYZ -> Philips Hue XY
* @param x X coefficient.
* @param y Y coefficient.
* @param z Z coefficient.
* @return Hue xy array
*/
public static XYColorSpace XYZtoXY(float x, float y, float z){
float[] xy = new float[2];
xy[0] = x / (x + y + z);
xy[1] = y / (x + y + z);
XYColorSpace xyColor = new XYColorSpace();
xyColor.setBrightness((int)Math.round(y * 254.0f));
xyColor.setXy(xy);
return xyColor;
}
/**
* Philips Hue XY -> XYZ
* @param x X coefficient.
* @param y Y coefficient.
* @return XYZ array
*/
public static float[] XYtoXYZ(XYColorSpace xy){
float[] xyz = new float[3];
/* Old Way
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
xyz[1] = xy.getBrightnessAdjusted();
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
*/
// New Way
xyz[0] = xy.getXy()[0] * (xy.getBrightnessAdjusted() / xy.getXy()[1]) ;
xyz[1] = xy.getBrightnessAdjusted();
xyz[2] = (float) ((1.0 - xy.getXy()[0] - xy.getXy()[1]) * (xy.getBrightnessAdjusted() / xy.getXy()[1]));
return xyz;
}
public static int[] normalizeRGB(int[] rgb) {
int[] newRGB = new int[3];
newRGB[0] = assureBounds(rgb[0]);
newRGB[1] = assureBounds(rgb[1]);
newRGB[2] = assureBounds(rgb[2]);
return newRGB;
}
private static int assureBounds(int value) {
if (value < 0.0) {
value = 0;
}
if (value > 255.0) {
value = 255;
}
return value;
}
}

View File

@@ -4,12 +4,12 @@ import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.Color;
// import java.awt.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.hue.ColorData;
// import com.bwssystems.HABridge.hue.ColorData;
public class ColorDecode {
private static final Logger log = LoggerFactory.getLogger(ColorDecode.class);
@@ -20,170 +20,224 @@ public class ColorDecode {
private static final String COLOR_GX = "${color.gx}";
private static final String COLOR_BX = "${color.bx}";
private static final String COLOR_RGBX = "${color.rgbx}";
private static final String COLOR_HSL = "${color.hsl}";
private static final String COLOR_HSB = "${color.hsb}";
private static final String COLOR_H = "${color.h}";
private static final String COLOR_S = "${color.s}";
private static final String COLOR_XY = "${color.xy}";
private static final String COLOR_BRI = "${colorbri}";
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
public static List<Integer> convertHSLtoRGB(HueSatBri hsl) {
/* This is supersceded by the next iteration function below this original one
public static List<Integer> convertHSBtoRGBOrig(HueSatBri hsb) {
List<Integer> rgb;
float decimalBrightness = (float) 0.0;
float var_1 = (float) 0.0;
float var_2 = (float) 0.0;
float h = (float) 0.0;
float h2 = (float) 0.0;
float s = (float) 0.0;
double r = 0.0;
double g = 0.0;
double b = 0.0;
Float hue = (Float)(hsb.getHue()*1.0f);
Float saturation = (Float)(hsb.getSat()*1.0f);
Float brightness = (Float)(hsb.getBri()*1.0f);
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
//Convert Hue into degrees for HSB
// hue = hue / 182.04f;
hue = (hue / 65535.0f) * 360.0f;
//Bri and Sat must be values from 0-1 (~percentage)
// ightness = brightness / 255.0f;
// saturation = saturation / 255.0f;
if(hsl.getBri() > 0)
decimalBrightness = (float) (hsl.getBri() / 255.0);
brightness = brightness / 254.0f;
saturation = saturation / 254.0f;
if(hsl.getHue() > 0) {
h = ((float)hsl.getHue() / (float)65535.0);
h2 = h + (float)0.5;
if(h2 > 1.0) {
h2 = h2 - (float)1.0;
Float r = 0f;
Float g = 0f;
Float b = 0f;
if(brightness > 0.0f) {
if (saturation == 0)
{
r = g = b = brightness;
}
else
{
// the color wheel consists of 6 sectors.
Float sectorPos = hue / 60.0f;
int sectorNumber = (int)(Math.floor(sectorPos));
// get the fractional part of the sector
Float fractionalSector = sectorPos - sectorNumber;
// 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;
}
}
}
if(hsl.getSat() > 0) {
s = (float)(hsl.getSat() / 254.0);
//Check if any value is out of byte range
if (r < 0f)
{
r = 0f;
}
if (s == 0)
{
r = decimalBrightness * (float)255;
g = decimalBrightness * (float)255;
b = decimalBrightness * (float)255;
}
else
{
if (decimalBrightness < 0.5)
{
var_2 = decimalBrightness * (1 + s);
}
else
{
var_2 = (decimalBrightness + s) - (s * decimalBrightness);
};
var_1 = 2 * decimalBrightness - var_2;
float onethird = (float)0.33333;
float h2Plus = (h2 + onethird);
float h2Minus = (h2 - onethird);
log.debug("calculate HSL vars - var1: " + var_1 + ", var_2: " + var_2 + ", h2: " + h2 + ", h2 + 1/3: " + h2Plus + ", h2 - 1/3: " + h2Minus);
r = 255 * hue_2_rgb(var_1, var_2, h2Plus);
g = 255 * hue_2_rgb(var_1, var_2, h2);
b = 255 * hue_2_rgb(var_1, var_2, h2Minus);
};
if (g < 0f)
{
g = 0f;
}
if (b < 0f)
{
b = 0f;
}
rgb = new ArrayList<Integer>();
rgb.add((int) Math.round(r));
rgb.add((int) Math.round(g));
rgb.add((int) Math.round(b));
log.debug("Color change with HSL: " + hsl + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
rgb.add((int)Math.round(r*255));
rgb.add((int)Math.round(g*255));
rgb.add((int)Math.round(b*255));
log.info("Color change with HSB: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2));
int theRGB = Color.HSBtoRGB(hue, saturation, brightness);
Color decodedRGB = new Color(theRGB);
log.info("Color change with HSB using java Color: " + hsb + ". Resulting RGB Values: " + decodedRGB.getRed() + " " + decodedRGB.getGreen() + " "
+ decodedRGB.getBlue());
return rgb;
}
*/
public static List<Integer> convertHSBtoRGB(HueSatBri hsb) {
List<Integer> rgb;
Float hue = (Float)(hsb.getHue()*1.0f);
Float saturation = (Float)(hsb.getSat()*1.0f);
Float brightness = (Float)(hsb.getBri()*1.0f);
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
//Convert Hue into degrees for HSB
// hue = hue / 182.04f;
hue = (hue / 65535.0f);
//Bri and Sat must be values from 0-1 (~percentage)
// ightness = brightness / 255.0f;
// saturation = saturation / 255.0f;
brightness = brightness / 254.0f;
saturation = saturation / 254.0f;
Float r = 0f;
Float g = 0f;
Float b = 0f;
Float temp2 = 0f;
Float temp1 = 0f;
if(brightness > 0.0f) {
if (saturation == 0)
{
r = g = b = brightness;
}
else
{
temp2 = (brightness < 0.5f) ? brightness * (1.0f + saturation) : brightness + saturation - (brightness * saturation);
temp1 = 2.0f * brightness - temp2;
r = GetColorComponent(temp1, temp2, hue + 1.0f/3.0f);
g = GetColorComponent(temp1, temp2, hue);
b = GetColorComponent(temp1, temp2, hue - 1.0f/3.0f);
}
}
//Check if any value is out of byte range
if (r < 0f)
{
r = 0f;
}
if (g < 0f)
{
g = 0f;
}
if (b < 0f)
{
b = 0f;
}
rgb = new ArrayList<Integer>();
rgb.add((int)Math.round(r*255));
rgb.add((int)Math.round(g*255));
rgb.add((int)Math.round(b*255));
log.debug("Color change with HSB New: " + hsb + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2));
return rgb;
}
public static float hue_2_rgb(float v1, float v2, float vh) {
log.debug("hue_2_rgb vh: " + vh);
if (vh < 0.0)
private static Float GetColorComponent(Float temp1, Float temp2, Float temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1.0f/6.0f)
{
vh = vh + (float)1;
};
return temp1 + (temp2 - temp1) * 6.0f * temp3;
}
if (vh > 1.0)
if (temp3 < 0.5f)
{
vh = vh - (float)1;
};
return temp2;
}
if (((float)6.0 * vh) < 1.0)
if (temp3 < 2.0f/3.0f)
{
return (v1 + (v2 - v1) * (float)6.0 * vh);
};
return temp1 + ((temp2 - temp1) * ((2.0f/3.0f) - temp3) * 6.0f);
}
if (((float)2.0 * vh) < 1.0)
{
return (v2);
};
return temp1;
}
if ((3.0 * vh) < 2.0)
{
return (v1 + (v2 - v1) * (((float)2.0 / (float)3.0 - vh) * (float)6.0));
};
return (v1);
private static Float MoveIntoRange(Float temp3)
{
if (temp3 < 0.0f) return temp3 + 1f;
if (temp3 > 1.0f) return temp3 - 1f;
return temp3;
}
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
List<Integer> rgb;
double x = xy.get(0); // the given x value
double y = xy.get(1); // the given y value
double z = 1.0 - x - y;
double Y = (double) brightness / (double) 254.00; // The given brightness value
double X = (Y / y) * x;
double Z = (Y / y) * z;
double r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
double g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
double b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;
if (r > b && r > g && r > 1.0) {
g = g / r;
b = b / r;
r = 1.0;
} else if (g > b && g > r && g > 1.0) {
r = r / g;
b = b / g;
g = 1.0;
} else if (b > r && b > g && b > 1.0) {
r = r / b;
g = g / b;
b = 1.0;
}
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
if (r > b && r > g) {
// red is biggest
if (r > 1.0) {
g = g / r;
b = b / r;
r = 1.0;
}
} else if (g > b && g > r) {
// green is biggest
if (g > 1.0) {
r = r / g;
b = b / g;
g = 1.0;
}
} else if (b > r && b > g) {
// blue is biggest
if (b > 1.0) {
r = r / b;
g = g / b;
b = 1.0;
}
}
if (r < 0.0)
r = 0;
if (g < 0.0)
g = 0;
if (b < 0.0)
b = 0;
XYColorSpace xyColor = new XYColorSpace();
xyColor.setBrightness(brightness);
float[] xyFloat = new float[2];
xyFloat[0] = xy.get(0).floatValue();
xyFloat[1] = xy.get(1).floatValue();
xyColor.setXy(xyFloat);
float[] xyz = ColorConverter.XYtoXYZ(xyColor);
int[] rgbInt = ColorConverter.normalizeRGB(ColorConverter.XYZtoRGB(xyz[0], xyz[1], xyz[2]));
rgb = new ArrayList<Integer>();
rgb.add((int) Math.round(r * 255));
rgb.add((int) Math.round(g * 255));
rgb.add((int) Math.round(b * 255));
log.debug("Color change with XY: " + x + " " + y + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
rgb.add(rgbInt[0]);
rgb.add(rgbInt[1]);
rgb.add(rgbInt[2]);
log.debug("Color change with XY: " + xy.get(0) + " " + xy.get(1) + " " + brightness + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
+ " " + rgb.get(2));
return rgb;
}
@@ -229,10 +283,10 @@ public class ColorDecode {
private static double assureBounds(double value) {
if (value < 0.0) {
value = 0;
value = 0.0;
}
if (value > 255.0) {
value = 255;
value = 255.0;
}
return value;
}
@@ -253,7 +307,7 @@ public class ColorDecode {
} else if (colorMode == ColorData.ColorMode.CT) {
rgb = convertCTtoRGB((Integer) colorData.getData());
} else if (colorMode == ColorData.ColorMode.HS) {
rgb = convertHSLtoRGB((HueSatBri) colorData.getData());
rgb = convertHSBtoRGB((HueSatBri) colorData.getData());
}
while (notDone) {
@@ -297,13 +351,67 @@ public class ColorDecode {
notDone = true;
}
if (request.contains(COLOR_HSL)) {
float[] hsb = new float[3];
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
float hue = hsb[0] * (float) 360.0;
float sat = hsb[1] * (float) 100.0;
float bright = hsb[2] * (float) 100.0;
request = request.replace(COLOR_HSL, String.format("%f,%f,%f", hue, sat, bright));
if (request.contains(COLOR_XY)) {
if (colorMode == ColorData.ColorMode.XY) {
List<Double> xyData = (List<Double>) colorData.getData();
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
} else {
float[] xyz = ColorConverter.RGBtoXYZ(rgb.get(0), rgb.get(1), rgb.get(2));
XYColorSpace theXYcolor = ColorConverter.XYZtoXY(xyz[0], xyz[1], xyz[2]);
request = request.replace(COLOR_XY, String.format("%f,%f",theXYcolor.getXy()[0], theXYcolor.getXy()[1]));
}
notDone = true;
}
if (request.contains(COLOR_H)) {
if (colorMode == ColorData.ColorMode.HS) {
HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
} else {
float[] hsb;
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float hue = hsb[0];
request = request.replace(COLOR_H, String.format("%f", hue));
}
notDone = true;
}
if (request.contains(COLOR_S)) {
if (colorMode == ColorData.ColorMode.HS) {
HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
} else {
float[] hsb;
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float sat = hsb[1] * (float) 100.0;
request = request.replace(COLOR_S, String.format("%f", sat));
}
notDone = true;
}
if (request.contains(COLOR_BRI)) {
if (colorMode == ColorData.ColorMode.HS) {
HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
} else {
request = request.replace(COLOR_BRI, String.format("%d", setIntensity));
}
notDone = true;
}
if (request.contains(COLOR_HSB)) {
if (colorMode == ColorData.ColorMode.HS) {
HueSatBri hslData = (HueSatBri) colorData.getData();
request = request.replace(COLOR_HSB,
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
} else {
float[] hsb = new float[3];
hsb = ColorConverter.RGBtoHSL(rgb.get(0), rgb.get(1), rgb.get(2));
float hue = hsb[0];
float sat = hsb[1] * (float) 100.0;
float bright = hsb[2] * (float) 100.0;
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));
}
notDone = true;
}

View File

@@ -473,9 +473,9 @@ public class HueMulator {
if (deviceState != null) {
deviceState.setOn(stateChanges.isOn());
if (!deviceState.isOn() && deviceState.getBri() == 254)
deviceState.setBri(0);
deviceState.setBri(1);
if (!deviceState.isOn() && offState)
deviceState.setBri(0);
deviceState.setBri(1);
}
notFirstChange = true;
}
@@ -609,7 +609,7 @@ public class HueMulator {
notFirstChange = true;
}
if ((deviceState != null) && deviceState.isOn() && deviceState.getBri() <= 0)
if ((deviceState != null) && deviceState.isOn() && deviceState.getBri() <= 1)
deviceState.setBri(254);
// if((deviceState != null) && !deviceState.isOn() && (targetBri != null ||
@@ -1221,12 +1221,41 @@ public class HueMulator {
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;
}
}
/* Old code supperceded by the above block
if (!device.isOnFirstDim() && device.isOnWhenDimPresent() && isDimRequest && !isOnRequest) {
isOnRequest = true;
theStateChanges.setOn(true);
} else if (!device.isOnFirstDim() && !device.isOnWhenDimPresent() && isDimRequest) {
// isOnRequest = false;
}
} else
if (device.isOnFirstDim() && isDimRequest && !device.getDeviceState().isOn()) {
isOnRequest = true;
@@ -1245,6 +1274,7 @@ public class HueMulator {
isColorRequest = false;
}
}
*/
if (isOnRequest) {
if (bridgeSettings.isTracestate())
@@ -1416,8 +1446,8 @@ public class HueMulator {
int bri = 0;
if (targetBriInc != null) {
bri = state.getBri() - targetBriInc;
if (bri < 0)
bri = 0;
if (bri < 1)
bri = 1;
} else if (targetBri != null) {
bri = targetBri;
} else {
@@ -1440,8 +1470,8 @@ public class HueMulator {
int bri = 0;
if (targetBriInc != null) {
bri = state.getBri() - targetBriInc;
if (bri < 0)
bri = 0;
if (bri < 1)
bri = 1;
} else if (targetBri != null) {
bri = targetBri;
} else {

View File

@@ -0,0 +1,26 @@
package com.bwssystems.HABridge.hue;
public class XYColorSpace {
float[] xy;
int brightness;
public float[] getXy() {
return xy;
}
public void setXy(float[] xy) {
this.xy = xy;
}
public int getBrightness() {
return brightness;
}
public float getBrightnessAdjusted() {
return ((float) brightness / 254.0f) * 100f;
}
public void setBrightness(int brightness) {
this.brightness = brightness;
}
}

View File

@@ -41,10 +41,10 @@ public class MozIotCommandDetail {
public String getBody() {
String theBody = "";
if(level != null && level != "") {
if(level != null && !"".equals(level)) {
theBody = "{\"level\":" + level + "}";
}
else if(color != null && color != "") {
else if(color != null && !"".equals(color)) {
theBody = "{\"color\":\"" + color + "\"}";
} else {
theBody = "{\"on\":" + on + "}";

View File

@@ -9,6 +9,7 @@ import com.bwssystems.HABridge.Configuration;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.HABridge.util.UDPDatagramSender;
import com.bwssystems.HABridge.util.AddressUtil;
import java.io.IOException;
import java.net.*;
@@ -29,6 +30,7 @@ public class UpnpListener {
private String upnpConfigIP;
// private boolean strict;
private boolean upnpOriginal;
private boolean upnpAdvanced;
private boolean traceupnp;
private boolean useUpnpIface;
private BridgeControlDescriptor bridgeControl;
@@ -37,63 +39,39 @@ public class UpnpListener {
private String httpType;
private HuePublicConfig aHueConfig;
private Integer theUpnpSendDelay;
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: %s://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: upnp:rootdevice\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: %s://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: %s://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String 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/" + HueConstants.API_VERSION + "\r\n" +
"NTS: ssdp:alive\r\n" +
"hue-bridgeid: %s\r\n" +
"NT: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
/* This is the minimum response needed, all others are for the advanced setting */
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n"
+ "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
/* These next 2 templates are for the advanced upnp option */
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: uuid:" + HueConstants.UUID_PREFIX
+ "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "EXT:\r\n" + "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "hue-bridgeid: %s\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:"
+ HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
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/" + HueConstants.API_VERSION + "\r\n" +
"NTS: ssdp:alive\r\n" +
"hue-bridgeid: %s\r\n" +
"NT: upnp:rootdevice\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"LOCATION: %s://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
"NTS: ssdp:alive\r\n" +
"hue-bridgeid: %s\r\n" +
"NT: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
/* These notify templates are for the advanced upnp option */
private String notifyTemplate1 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + "NT: uuid:"
+ HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
+ "NT: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n"
+ "LOCATION: %s://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/"
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n"
+ "NT: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
public UpnpListener(BridgeSettings theSettings, BridgeControlDescriptor theControl,
UDPDatagramSender aUdpDatagramSender) throws IOException {
@@ -104,6 +82,7 @@ public class UpnpListener {
upnpConfigIP = theSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress();
// strict = theSettings.isUpnpStrict();
upnpOriginal = theSettings.getBridgeSettingsDescriptor().isUpnporiginal();
upnpAdvanced = theSettings.getBridgeSettingsDescriptor().isUpnpadvanced();
traceupnp = theSettings.getBridgeSettingsDescriptor().isTraceupnp();
useUpnpIface = theSettings.getBridgeSettingsDescriptor().isUseupnpiface();
theUpnpSendDelay = theSettings.getBridgeSettingsDescriptor().getUpnpsenddelay();
@@ -112,17 +91,18 @@ public class UpnpListener {
theSettings.getBridgeSettingsDescriptor().getHubmac());
bridgeId = aHueConfig.getBridgeid();
bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
if(theSettings.getBridgeSecurity().isUseHttps()) {
if (theSettings.getBridgeSecurity().isUseHttps()) {
httpType = "https";
} else {
httpType = "http";
}
try {
if (useUpnpIface)
upnpMulticastSocket = new MulticastSocket(
new InetSocketAddress(upnpConfigIP, Configuration.UPNP_DISCOVERY_PORT));
else
// This commented out code does not work... leave for review
// if (useUpnpIface)
// upnpMulticastSocket = new MulticastSocket(
// new InetSocketAddress(upnpConfigIP, Configuration.UPNP_DISCOVERY_PORT));
// else
upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
} catch (IOException e) {
log.error("Upnp Discovery Port is in use, or restricted by admin (try running with sudo or admin privs): "
@@ -165,7 +145,7 @@ public class UpnpListener {
if (traceupnp)
log.info("Traceupnp: Interface: " + name + " valid usable IP address: " + addr);
IPsPerNic++;
} else if (addr.getHostAddress().equals(upnpConfigIP)) {
} else if (useUpnpIface && (addr.getHostAddress().equals(upnpConfigIP) || name.equals("lo"))) {
if (traceupnp)
log.info("Traceupnp: Interface: " + name + " matches upnp config address of IP address: "
+ addr);
@@ -203,7 +183,8 @@ public class UpnpListener {
final HashMap<String, String> values = new HashMap<String, String>();
values.put("modelid", HueConstants.MODEL_ID);
values.put("bridgeid", bridgeId);
ServiceInfo serviceInfo = ServiceInfo.create("_hue._tcp.local.", "Philips Hue - " + bridgeId.substring(bridgeId.length() - 6), httpServerPort, 0, 0, values);
ServiceInfo serviceInfo = ServiceInfo.create("_hue._tcp.local.",
"Philips Hue - " + bridgeId.substring(bridgeId.length() - 6), httpServerPort, 0, 0, values);
jmdns.registerService(serviceInfo);
} catch (IOException e) {
@@ -219,13 +200,16 @@ public class UpnpListener {
log.info("UPNP Discovery Listener running and ready....");
boolean loopControl = true;
boolean error = false;
try {
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
} catch (SocketException e1) {
log.warn("Could not sent soTimeout on multi-cast socket");
if(upnpAdvanced) {
try {
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
} catch (SocketException e1) {
log.warn("Could not sent soTimeout on multi-cast socket");
}
}
// Instant current, previous;
// previous = Instant.now();
// Instant current, previous;
// previous = Instant.now();
while (loopControl) { // trigger shutdown here
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
@@ -234,26 +218,23 @@ public class UpnpListener {
if (isSSDPDiscovery(packet)) {
try {
sendUpnpResponse(packet);
} catch (IOException e) {
} catch (Exception e) {
log.warn("UpnpListener encountered an error sending upnp response packet. IP: "
+ packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
log.debug("UpnpListener send upnp exception: ", e);
}
}
/*
current = Instant.now();
if (ChronoUnit.MILLIS.between(previous, current) > Configuration.UPNP_NOTIFY_TIMEOUT) {
try {
sendUpnpNotify(socketAddress.getAddress());
} catch (IOException e) {
log.warn("UpnpListener encountered an error sending upnp notify packets. IP: "
+ packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
log.debug("UpnpListener send upnp notify exception: ", e);
}
previous = Instant.now();
}
*/
/*
* current = Instant.now(); if (ChronoUnit.MILLIS.between(previous, current) >
* Configuration.UPNP_NOTIFY_TIMEOUT) { try {
* sendUpnpNotify(socketAddress.getAddress()); } catch (IOException e) { log.
* warn("UpnpListener encountered an error sending upnp notify packets. IP: " +
* packet.getAddress().getHostAddress() + " with message: " + e.getMessage());
* log.debug("UpnpListener send upnp notify exception: ", e); } previous =
* Instant.now();
*
* }
*/
} catch (SocketTimeoutException e) {
try {
sendUpnpNotify(socketAddress.getAddress());
@@ -276,7 +257,7 @@ public class UpnpListener {
}
}
upnpMulticastSocket.close();
if(jmdns != null) {
if (jmdns != null) {
// Unregister all services
jmdns.unregisterAllServices();
}
@@ -297,11 +278,11 @@ public class UpnpListener {
protected boolean isSSDPDiscovery(DatagramPacket packet) {
// Only respond to discover request for strict upnp form
String packetString = new String(packet.getData(), 0, packet.getLength());
// log.info("Packet string <<<" + packetString + ">>>");
if (packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1")
&& packetString.contains("\"ssdp:discover\"")) {
if ((packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") ||
packetString.contains("ST: upnp:rootdevice") ||
packetString.contains("ST: ssdp:all"))) {
if ((packetString.contains("ST: urn:schemas-upnp-org:device:basic:1")
|| packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all"))) {
if (traceupnp) {
log.info("Traceupnp: SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":"
+ packet.getPort());
@@ -327,41 +308,49 @@ public class UpnpListener {
}
protected void sendUpnpResponse(DatagramPacket aPacket) throws IOException {
SocketAddress requesterAddress = aPacket.getSocketAddress();
// SocketAddress requesterAddress = aPacket.getSocketAddress();
InetAddress requester = aPacket.getAddress();
int sourcePort = aPacket.getPort();
String discoveryResponse = null;
// refactored suggestion by https://github.com/pvint
String httpLocationAddress = getOutboundAddress(requesterAddress).getHostAddress();
String httpLocationAddress = null;
if (useUpnpIface) {
httpLocationAddress = upnpConfigIP;
} else {
// refactored suggestion by https://github.com/pvint
httpLocationAddress = AddressUtil.getOutboundAddress(requester.getHostAddress(), sourcePort).getHostAddress();
}
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 1 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 1 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
+ " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
if(upnpAdvanced) {
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID,
bridgeSNUUID);
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
bridgeSNUUID, bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester + ":" + sourcePort);
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -370,20 +359,22 @@ public class UpnpListener {
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate3,Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID);
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 + ":" + sourcePort);
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
}
log.debug("sendUpnpResponse to address: " + requester + ":" + 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 {
log.debug("Sending response string: <<<" + new String(udpMessage) + ">>>");
if(upnpOriginal) {
if (upnpOriginal) {
theUDPDatagramSender.sendUDPResponse(udpMessage, requester, sourcePort);
} else {
if (upnpMulticastSocket == null)
@@ -402,7 +393,8 @@ public class UpnpListener {
}
notifyData = String.format(notifyTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID,
bridgeSNUUID);
if (traceupnp) {
log.info("Traceupnp: sendUpnpNotify notifyTemplate1");
}
@@ -422,7 +414,7 @@ public class UpnpListener {
}
log.debug("sendUpnpNotify notifyTemplate2 is <<<{}>>>", notifyData);
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
@@ -437,21 +429,4 @@ public class UpnpListener {
log.debug("sendUpnpNotify notifyTemplate3 is <<<{}>>>", notifyData);
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
}
// added by https://github.com/pvint
// Ruthlessly stolen from
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
// Try to get a source IP that makes sense for the requestor to contact for use
// in the LOCATION header in replies
private InetAddress getOutboundAddress(SocketAddress remoteAddress) throws SocketException {
DatagramSocket sock = new DatagramSocket();
// connect is needed to bind the socket and retrieve the local address
// later (it would return 0.0.0.0 otherwise)
sock.connect(remoteAddress);
final InetAddress localAddress = sock.getLocalAddress();
sock.disconnect();
sock.close();
sock = null;
return localAddress;
}
}

View File

@@ -7,14 +7,10 @@ import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.HABridge.util.ParseRoute;
import com.bwssystems.HABridge.util.AddressUtil;
import static spark.Spark.get;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
/**
*
*/
@@ -59,10 +55,12 @@ public class UpnpSettingsResource {
+ "<depth>24</depth>\n"
+ "<url>hue_logo_3.png</url>\n"
+ "</icon>\n"
+ "</iconList>\n"
+ "</device>\n"
+ "</root>\n";
+ "</iconList>\n";
private String hueTemplate_end = "</device>\n"
+ "</root>\n";
/* not utilizing this section any more
private String hueTemplate_mid_orig = "<serviceList>\n"
+ "<service>\n"
+ "<serviceType>(null)</serviceType>\n"
@@ -72,7 +70,7 @@ public class UpnpSettingsResource {
+ "<SCPDURL>(null)</SCPDURL>\n"
+ "</service>\n"
+ "</serviceList>\n";
*/
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
super();
@@ -96,10 +94,24 @@ public class UpnpSettingsResource {
String hueTemplate = null;
if(theSettings.isUpnporiginal()) {
httpLocationAddr = theSettings.getUpnpConfigAddress();
hueTemplate = hueTemplate_pre + hueTemplate_mid_orig + hueTemplate_post;
hueTemplate = hueTemplate_pre + hueTemplate_end;
} else if(!theSettings.isUpnpadvanced()) {
if(theSettings.isUseupnpiface()) {
httpLocationAddr = theSettings.getUpnpConfigAddress();
} else {
log.debug("Get Outbound address for ip:" + request.ip() + " and port:" + request.port());
httpLocationAddr = AddressUtil.getOutboundAddress(request.ip(), request.port()).getHostAddress();
}
hueTemplate = hueTemplate_pre + hueTemplate_end;
} else {
httpLocationAddr = getOutboundAddress(request.ip(), request.port()).getHostAddress();
hueTemplate = hueTemplate_pre + hueTemplate_post;
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();
@@ -136,28 +148,4 @@ public class UpnpSettingsResource {
return "";
} );
}
// added by https://github.com/pvint
// Ruthlessly stolen from https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
// Try to get a source IP that makes sense for the requester to contact for use in the LOCATION header in replies
private InetAddress getOutboundAddress(String remoteAddress, int remotePort) {
InetAddress localAddress = null;
try {
DatagramSocket sock = new DatagramSocket();
// connect is needed to bind the socket and retrieve the local address
// later (it would return 0.0.0.0 otherwise)
sock.connect(new InetSocketAddress(remoteAddress, remotePort));
localAddress = sock.getLocalAddress();
sock.disconnect();
sock.close();
sock = null;
} catch(Exception e) {
ParseRoute theRoute = ParseRoute.getInstance();
try {
localAddress = InetAddress.getByName(theRoute.getLocalIPAddress());
} catch(Exception e1) {}
log.warn("Error <" + e.getMessage() + "> on determining interface to reply for <" + remoteAddress + ">. Using default route IP Address of " + localAddress.getHostAddress());
}
log.debug("getOutbountAddress returning IP Address of " + localAddress.getHostAddress());
return localAddress;
}
}

View File

@@ -0,0 +1,62 @@
package com.bwssystems.HABridge.util;
import java.net.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AddressUtil {
final static Logger log = LoggerFactory.getLogger(AddressUtil.class);
// added by https://github.com/pvint
// Ruthlessly stolen from
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
// Try to get a source IP that makes sense for the requester to contact for use
// in the LOCATION header in replies
public static InetAddress getOutboundAddress(String remoteAddress, int remotePort) {
InetAddress localAddress = null;
log.debug("Entering getOutboundAddress with args.");
try {
localAddress = getOutboundAddress(new InetSocketAddress(remoteAddress, remotePort));
} catch (Exception e) {
log.debug("getOutboundAddress(SocketAddress) Threw an Exception: " + e.getMessage());
ParseRoute theRoute = ParseRoute.getInstance();
try {
localAddress = InetAddress.getByName(theRoute.getLocalIPAddress());
log.warn("Error <" + e.getMessage() + "> on determining interface to reply for <" + remoteAddress
+ ">. Using default route IP Address of " + localAddress.getHostAddress());
} catch (Exception e1) {
log.error("Cannot find address for parsed local ip address: " + e.getMessage());
}
}
if(localAddress != null)
log.debug("localAddress is IP Address of " + localAddress.getHostAddress());
else
log.debug("localAddress returning NULL");
return localAddress;
}
// added by https://github.com/pvint
// Ruthlessly stolen from
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
// Try to get a source IP that makes sense for the requestor to contact for use
// in the LOCATION header in replies
public static InetAddress getOutboundAddress(SocketAddress remoteAddress) throws SocketException {
DatagramSocket sock = new DatagramSocket();
// connect is needed to bind the socket and retrieve the local address
// later (it would return 0.0.0.0 otherwise)
log.debug("Entering getOutboundAddress with socket arg.");
sock.connect(remoteAddress);
log.debug("getOutboundAddress(SocketAddress) getLocalAddress.");
final InetAddress localAddress = sock.getLocalAddress();
sock.disconnect();
sock.close();
sock = null;
if(localAddress != null)
log.debug("getOutbountAddress(SocketAddress) returning IP Address of " + localAddress.getHostAddress());
else
log.debug("getOutboundAddress(SocketAddress) returning NULL");
return localAddress;
}
}

View File

@@ -1547,26 +1547,42 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
};
this.toXY = function (red, green, blue) {
//Gamma corrective
red = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);
green = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);
blue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92);
var r = red / 255;
var g = green / 255;
var b = blue / 255;
//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
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)];
return [newX.toPrecision(6), newY.toPrecision(6), newBright];
};
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 (addComma)
testBody = testBody + ",";
testBody = testBody + "\"xy\": [" + value[0] + "," + value[1] + "]";
testBody = testBody + "\"xy\": [" + value[0] + "," + value[1] + "],\"bri\":" + value[2];
}
testBody = testBody + "}";
if (testBody === "{}") {

View File

@@ -114,6 +114,12 @@
ng-model="device.onFirstDim" ng-true-value=true
ng-false-value=false> {{device.onFirstDim}}</td>
</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>Filter Address (comma separated list)</label></td>
<td><input type="text" class="form-control" id="device-requester-addr"

View File

@@ -824,6 +824,11 @@
<td><input type="checkbox" ng-model="bridge.settings.upnporiginal" ng-true-value=true
ng-false-value=false> {{bridge.settings.upnporiginal}}</td>
</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>Trace UPNP Calls</td>
<td><input type="checkbox" ng-model="bridge.settings.traceupnp" ng-true-value=true

View File

@@ -1,5 +1,6 @@
package com.bwssystems.color.test;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -9,23 +10,143 @@ import org.junit.Test;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.HueSatBri;
import com.bwssystems.HABridge.hue.XYColorSpace;
import com.bwssystems.HABridge.hue.ColorConverter;
public class ConvertCIEColorTestCase {
@Test
public void testColorConversion() {
public void testColorConverterXYtoRGB() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.20821628789344535"), Double.parseDouble("0.22503526273269103")));
XYColorSpace xyColor = new XYColorSpace();
xyColor.setBrightness(56);
float[] xyFloat = new float[2];
xyFloat[0] = xy.get(0).floatValue();
xyFloat[1] = xy.get(1).floatValue();
xyColor.setXy(xyFloat);
float[] xyz = ColorConverter.XYtoXYZ(xyColor);
int[] rgb = ColorConverter.normalizeRGB(ColorConverter.XYZtoRGB(xyz[0], xyz[1], xyz[2]));
List<Integer> rgbDecode = new ArrayList<Integer>();
rgbDecode.add(0, rgb[0]);
rgbDecode.add(1, rgb[1]);
rgbDecode.add(2, rgb[2]);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 60);
assertDecode.add(1, 134);
assertDecode.add(2, 196);
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
public void testColorConversionXYtoRGB1() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.671254"), Double.parseDouble("0.303273")));
List<Integer> colorDecode = ColorDecode.convertCIEtoRGB(xy, 254);
List<Integer> colorDecode = ColorDecode.convertCIEtoRGB(xy, 50);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 255);
assertDecode.add(1, 47);
assertDecode.add(2, 43);
assertDecode.add(1, 0);
assertDecode.add(2, 5);
Assert.assertEquals(colorDecode, assertDecode);
ColorData colorData = new ColorData(ColorData.ColorMode.XY, xy);
int rgbIntVal = ColorDecode.getIntRGB(colorData, 254);
Assert.assertEquals(rgbIntVal, 16723755);
int rgbIntVal = ColorDecode.getIntRGB(colorData, 50);
Assert.assertEquals(rgbIntVal, 16711685);
}
@Test
public void testColorConversionXYtoRGB2() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(Double.parseDouble("0.32312"), Double.parseDouble("0.15539")));
List<Integer> colorDecode = ColorDecode.convertCIEtoRGB(xy, 59);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 233);
assertDecode.add(1, 0);
assertDecode.add(2, 231);
Assert.assertEquals(colorDecode, assertDecode);
ColorData colorData = new ColorData(ColorData.ColorMode.XY, xy);
int rgbIntVal = ColorDecode.getIntRGB(colorData, 59);
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
public void testColorConversionHSBtoRGB1() {
HueSatBri hsb = new HueSatBri();
hsb.setHue(37767);
hsb.setSat(135);
hsb.setBri(128);
List<Integer> colorDecode = ColorDecode.convertHSBtoRGB(hsb);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 61);
assertDecode.add(1, 134);
assertDecode.add(2, 196);
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
public void testColorConversionCTtoRGB() {
Integer ct = 500;
List<Integer> colorDecode = ColorDecode.convertCTtoRGB(ct);
List<Integer> assertDecode = new ArrayList<Integer>();
assertDecode.add(0, 255);
assertDecode.add(1, 137);
assertDecode.add(2, 14);
Assert.assertEquals(colorDecode, assertDecode);
}
}