mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
16 Commits
v5.3.0RC11
...
v5.3.1RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d568d8d68 | ||
|
|
f5e100667e | ||
|
|
c376253488 | ||
|
|
a3fd2ca722 | ||
|
|
fe4df16e10 | ||
|
|
768eebfc78 | ||
|
|
79ce23b80a | ||
|
|
bddc7c1c31 | ||
|
|
51c6ffc48a | ||
|
|
ee4afc00c0 | ||
|
|
8b48f23741 | ||
|
|
87f79df8b1 | ||
|
|
1142704d22 | ||
|
|
d014240fba | ||
|
|
5c2d30e24b | ||
|
|
28d84f667a |
@@ -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.1RC1.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.1RC1.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.1RC1/ha-bridge-5.3.1RC1.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.1RC1.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>5.3.0RC11</version>
|
||||
<version>5.3.1RC1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
@@ -111,7 +111,7 @@
|
||||
<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>
|
||||
@@ -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>
|
||||
|
||||
@@ -376,6 +376,13 @@ public class BridgeSecurity {
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public void removeHttpsSettings() {
|
||||
securityDescriptor.setUseHttps(false);
|
||||
securityDescriptor.setKeyfilePassword(null);
|
||||
securityDescriptor.setKeyfilePath(null);
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
|
||||
public void removeTestUsers() {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||
import com.bwssystems.HABridge.util.UDPDatagramSender;
|
||||
|
||||
public class HABridge {
|
||||
private static SystemControl theSystem;
|
||||
|
||||
/*
|
||||
* This program is based on the work of armzilla from this github repository:
|
||||
@@ -39,7 +40,6 @@ public class HABridge {
|
||||
UDPDatagramSender udpSender;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
SystemControl theSystem;
|
||||
BridgeSettings bridgeSettings;
|
||||
Version theVersion;
|
||||
@SuppressWarnings("unused")
|
||||
@@ -153,8 +153,14 @@ public class HABridge {
|
||||
}
|
||||
|
||||
private static void theExceptionHandler(Exception e, Integer thePort) {
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
log.error("Could not start ha-bridge webservice on port [{}] due to: {}", thePort, e.getMessage());
|
||||
System.exit(0);
|
||||
}
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
if(e.getMessage().equals("no valid keystore") || e.getMessage().equals("keystore password was incorrect")) {
|
||||
log.error("Https settings have been removed as {}. Restart system manually after this process exits....", e.getMessage());
|
||||
log.warn(theSystem.removeHttpsSettings());
|
||||
}
|
||||
else {
|
||||
log.error("Could not start ha-bridge webservice on port [{}] due to: {}", thePort, e.getMessage());
|
||||
log.warn(theSystem.stop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +598,12 @@ public class SystemControl {
|
||||
log.warn("Error pinging listener. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String removeHttpsSettings() {
|
||||
bridgeSettings.getBridgeSecurity().removeHttpsSettings();
|
||||
return stop();
|
||||
}
|
||||
|
||||
public String reinit() {
|
||||
bridgeSettings.getBridgeControl().setReinit(true);
|
||||
pingListener();
|
||||
|
||||
@@ -75,6 +75,8 @@ public class DeviceRepository extends BackupHandler {
|
||||
nextId = Integer.decode(list[i].getId());
|
||||
}
|
||||
}
|
||||
|
||||
nextId = nextId + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,11 +201,15 @@ public class GroupRepository extends BackupHandler {
|
||||
private String repositoryReader(Path filePath) {
|
||||
|
||||
String content = null;
|
||||
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
|
||||
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
|
||||
if(Files.notExists(filePath)){
|
||||
log.debug("Error, the file: " + filePath + " - does not exist. continuing...");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!Files.isReadable(filePath)){
|
||||
log.warn("Error, the file: " + filePath + " - is not readable. continuing...");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
content = new String(Files.readAllBytes(filePath));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
963
src/main/java/com/bwssystems/HABridge/hue/ColorConverter.java
Normal file
@@ -0,0 +1,963 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
/**
|
||||
* Convert between different color spaces supported.
|
||||
* RGB -> CMYK -> RGB
|
||||
* RGB -> YIQ -> RGB
|
||||
* RGB -> YCbCr -> RGB
|
||||
* RGB -> YUV -> RGB
|
||||
* RGB -> RGChromaticity
|
||||
* RGB -> HSV -> RGB
|
||||
* RGB -> YCC -> RGB
|
||||
* RGB -> YCoCg -> RGB
|
||||
* RGB -> XYZ -> RGB
|
||||
* RGB -> HunterLAB -> RGB
|
||||
* RGB -> HLS -> RGB
|
||||
* RGB -> CIE-LAB -> RGB
|
||||
* XYZ -> HunterLAB -> XYZ
|
||||
* XYZ -> CIE-LAB -> XYZ
|
||||
* @author Diego Catalano
|
||||
*/
|
||||
public class ColorConverter {
|
||||
|
||||
/**
|
||||
* Don't let anyone instantiate this class.
|
||||
*/
|
||||
private ColorConverter() {}
|
||||
|
||||
public static enum YCbCrColorSpace {ITU_BT_601,ITU_BT_709_HDTV};
|
||||
|
||||
// XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
|
||||
|
||||
//2o Observer (CIE 1931)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE2_A = {109.850f, 100f, 35.585f}; //Incandescent
|
||||
public static float[] CIE2_C = {98.074f, 100f, 118.232f};
|
||||
public static float[] CIE2_D50 = {96.422f, 100f, 82.521f};
|
||||
public static float[] CIE2_D55 = {95.682f, 100f, 92.149f};
|
||||
public static float[] CIE2_D65 = {95.047f, 100f, 108.883f}; //Daylight
|
||||
public static float[] CIE2_D75 = {94.972f, 100f, 122.638f};
|
||||
public static float[] CIE2_F2 = {99.187f, 100f, 67.395f}; //Fluorescent
|
||||
public static float[] CIE2_F7 = {95.044f, 100f, 108.755f};
|
||||
public static float[] CIE2_F11 = {100.966f, 100f, 64.370f};
|
||||
|
||||
//10o Observer (CIE 1964)
|
||||
// X2, Y2, Z2
|
||||
public static float[] CIE10_A = {111.144f, 100f, 35.200f}; //Incandescent
|
||||
public static float[] CIE10_C = {97.285f, 100f, 116.145f};
|
||||
public static float[] CIE10_D50 = {96.720f, 100f, 81.427f};
|
||||
public static float[] CIE10_D55 = {95.799f, 100f, 90.926f};
|
||||
public static float[] CIE10_D65 = {94.811f, 100f, 107.304f}; //Daylight
|
||||
public static float[] CIE10_D75 = {94.416f, 100f, 120.641f};
|
||||
public static float[] CIE10_F2 = {103.280f, 100f, 69.026f}; //Fluorescent
|
||||
public static float[] CIE10_F7 = {95.792f, 100f, 107.687f};
|
||||
public static float[] CIE10_F11 = {103.866f, 100f, 65.627f};
|
||||
|
||||
/**
|
||||
* RFB -> CMYK
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return CMYK color space. Normalized.
|
||||
*/
|
||||
public static float[] RGBtoCMYK(int red, int green, int blue){
|
||||
float[] cmyk = new float[4];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float k = 1.0f - Math.max(r, Math.max(g, b));
|
||||
float c = (1f-r-k) / (1f-k);
|
||||
float m = (1f-g-k) / (1f-k);
|
||||
float y = (1f-b-k) / (1f-k);
|
||||
|
||||
cmyk[0] = c;
|
||||
cmyk[1] = m;
|
||||
cmyk[2] = y;
|
||||
cmyk[3] = k;
|
||||
|
||||
return cmyk;
|
||||
}
|
||||
|
||||
/**
|
||||
* CMYK -> RGB
|
||||
* @param c Cyan.
|
||||
* @param m Magenta.
|
||||
* @param y Yellow.
|
||||
* @param k Black.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] CMYKtoRGB(float c, float m, float y, float k){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
rgb[0] = (int)(255 * (1-c) * (1-k));
|
||||
rgb[1] = (int)(255 * (1-m) * (1-k));
|
||||
rgb[2] = (int)(255 * (1-y) * (1-k));
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YUV.
|
||||
* Y in the range [0..1].
|
||||
* U in the range [-0.5..0.5].
|
||||
* V in the range [-0.5..0.5].
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YUV color space.
|
||||
*/
|
||||
public static float[] RGBtoYUV(int red, int green, int blue){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] yuv = new float[3];
|
||||
float y,u,v;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
u = (float)(-0.14713 * r - 0.28886 * g + 0.436 * b);
|
||||
v = (float)(0.615 * r - 0.51499 * g - 0.10001 * b);
|
||||
|
||||
yuv[0] = y;
|
||||
yuv[1] = u;
|
||||
yuv[2] = v;
|
||||
|
||||
return yuv;
|
||||
}
|
||||
|
||||
/**
|
||||
* YUV -> RGB.
|
||||
* @param y Luma. In the range [0..1].
|
||||
* @param u Chrominance. In the range [-0.5..0.5].
|
||||
* @param v Chrominance. In the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YUVtoRGB(float y, float u, float v){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
r = (float)((y + 0.000 * u + 1.140 * v) * 255);
|
||||
g = (float)((y - 0.396 * u - 0.581 * v) * 255);
|
||||
b = (float)((y + 2.029 * u + 0.000 * v) * 255);
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YIQ.
|
||||
* @param red Values in the range [0..255].
|
||||
* @param green Values in the range [0..255].
|
||||
* @param blue Values in the range [0..255].
|
||||
* @return YIQ color space.
|
||||
*/
|
||||
public static float[] RGBtoYIQ(int red, int green, int blue){
|
||||
float[] yiq = new float[3];
|
||||
float y,i,q;
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
i = (float)(0.596 * r - 0.275 * g - 0.322 * b);
|
||||
q = (float)(0.212 * r - 0.523 * g + 0.311 * b);
|
||||
|
||||
yiq[0] = y;
|
||||
yiq[1] = i;
|
||||
yiq[2] = q;
|
||||
|
||||
return yiq;
|
||||
}
|
||||
|
||||
/**
|
||||
* YIQ -> RGB.
|
||||
* @param y Luma. Values in the range [0..1].
|
||||
* @param i In-phase. Values in the range [-0.5..0.5].
|
||||
* @param q Quadrature. Values in the range [-0.5..0.5].
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YIQtoRGB(double y, double i, double q){
|
||||
int[] rgb = new int[3];
|
||||
int r,g,b;
|
||||
|
||||
r = (int)((y + 0.956 * i + 0.621 * q) * 255);
|
||||
g = (int)((y - 0.272 * i - 0.647 * q) * 255);
|
||||
b = (int)((y - 1.105 * i + 1.702 * q) * 255);
|
||||
|
||||
r = Math.max(0,Math.min(255,r));
|
||||
g = Math.max(0,Math.min(255,g));
|
||||
b = Math.max(0,Math.min(255,b));
|
||||
|
||||
rgb[0] = r;
|
||||
rgb[1] = g;
|
||||
rgb[2] = b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
public static float[] RGBtoYCbCr(int red, int green, int blue, YCbCrColorSpace colorSpace){
|
||||
|
||||
float r = (float)red / 255;
|
||||
float g = (float)green / 255;
|
||||
float b = (float)blue / 255;
|
||||
|
||||
float[] YCbCr = new float[3];
|
||||
float y,cb,cr;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
y = (float)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
cb = (float)(-0.169 * r - 0.331 * g + 0.500 * b);
|
||||
cr = (float)(0.500 * r - 0.419 * g - 0.081 * b);
|
||||
}
|
||||
else{
|
||||
y = (float)(0.2215 * r + 0.7154 * g + 0.0721 * b);
|
||||
cb = (float)(-0.1145 * r - 0.3855 * g + 0.5000 * b);
|
||||
cr = (float)(0.5016 * r - 0.4556 * g - 0.0459 * b);
|
||||
}
|
||||
|
||||
YCbCr[0] = (float)y;
|
||||
YCbCr[1] = (float)cb;
|
||||
YCbCr[2] = (float)cr;
|
||||
|
||||
return YCbCr;
|
||||
}
|
||||
|
||||
public static int[] YCbCrtoRGB(float y, float cb, float cr, YCbCrColorSpace colorSpace){
|
||||
int[] rgb = new int[3];
|
||||
float r,g,b;
|
||||
|
||||
if (colorSpace == YCbCrColorSpace.ITU_BT_601) {
|
||||
r = (float)(y + 0.000 * cb + 1.403 * cr) * 255;
|
||||
g = (float)(y - 0.344 * cb - 0.714 * cr) * 255;
|
||||
b = (float)(y + 1.773 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
else{
|
||||
r = (float)(y + 0.000 * cb + 1.5701 * cr) * 255;
|
||||
g = (float)(y - 0.1870 * cb - 0.4664 * cr) * 255;
|
||||
b = (float)(y + 1.8556 * cb + 0.000 * cr) * 255;
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rg-Chromaticity space is already known to remove ambiguities due to illumination or surface pose.
|
||||
* @see Neural Information Processing - Chi Sing Leung. p. 668
|
||||
* @param red Red coefficient.
|
||||
* @param green Green coefficient.
|
||||
* @param blue Blue coefficient.
|
||||
* @return Normalized RGChromaticity. Range[0..1].
|
||||
*/
|
||||
public static double[] RGChromaticity(int red, int green, int blue){
|
||||
double[] color = new double[5];
|
||||
|
||||
double sum = red + green + blue;
|
||||
|
||||
//red
|
||||
color[0] = red / sum;
|
||||
|
||||
//green
|
||||
color[1] = green / sum;
|
||||
|
||||
//blue
|
||||
color[2] = 1 - color[0] - color[1];
|
||||
|
||||
double rS = color[0] - 0.333;
|
||||
double gS = color[1] - 0.333;
|
||||
|
||||
//saturation
|
||||
color[3] = Math.sqrt(rS * rS + gS * gS);
|
||||
|
||||
//hue
|
||||
color[4] = Math.atan(rS / gS);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HSV.
|
||||
* Adds (hue + 360) % 360 for represent hue in the range [0..359].
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HSV color space.
|
||||
*/
|
||||
public static float[] RGBtoHSV(int red, int green, int blue){
|
||||
float[] hsv = new float[3];
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float max = Math.max(r, Math.max(g, b));
|
||||
float min = Math.min(r, Math.min(g, b));
|
||||
float delta = max - min;
|
||||
|
||||
// Hue
|
||||
if (max == min){
|
||||
hsv[0] = 0;
|
||||
}
|
||||
else if (max == r){
|
||||
hsv[0] = ((g - b) / delta) * 60f;
|
||||
}
|
||||
else if (max == g){
|
||||
hsv[0] = ((b - r) / delta + 2f) * 60f;
|
||||
}
|
||||
else if (max == b){
|
||||
hsv[0] = ((r - g) / delta + 4f) * 60f;
|
||||
}
|
||||
|
||||
// Saturation
|
||||
if (delta == 0)
|
||||
hsv[1] = 0;
|
||||
else
|
||||
hsv[1] = delta / max;
|
||||
|
||||
//Value
|
||||
hsv[2] = max;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
/**
|
||||
* HSV -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation. In the range[0..1].
|
||||
* @param value Value. In the range[0..1].
|
||||
* @return RGB color space. In the range[0..255].
|
||||
*/
|
||||
public static int[] HSVtoRGB(float hue, float saturation, float value){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float hi = (float)Math.floor(hue / 60.0) % 6;
|
||||
float f = (float)((hue / 60.0) - Math.floor(hue / 60.0));
|
||||
float p = (float)(value * (1.0 - saturation));
|
||||
float q = (float)(value * (1.0 - (f * saturation)));
|
||||
float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));
|
||||
|
||||
if (hi == 0){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(t * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 1){
|
||||
rgb[0] = (int)(q * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 2){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(t * 255);
|
||||
}
|
||||
else if (hi == 3){
|
||||
rgb[0] = (int)(p * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
else if (hi == 4){
|
||||
rgb[0] = (int)(t * 255);
|
||||
rgb[1] = (int)(value * 255);
|
||||
rgb[2] = (int)(p * 255);
|
||||
}
|
||||
else if (hi == 5){
|
||||
rgb[0] = (int)(value * 255);
|
||||
rgb[1] = (int)(p * 255);
|
||||
rgb[2] = (int)(q * 255);
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCC.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCC color space. In the range [0..1].
|
||||
*/
|
||||
public static float[] RGBtoYCC(int red, int green, int blue){
|
||||
float[] ycc = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = 0.213f * r + 0.419f * g + 0.081f * b;
|
||||
float c1 = -0.131f * r - 0.256f * g + 0.387f * b + 0.612f;
|
||||
float c2 = 0.373f * r - 0.312f * r - 0.061f * b + 0.537f;
|
||||
|
||||
ycc[0] = y;
|
||||
ycc[1] = c1;
|
||||
ycc[2] = c2;
|
||||
|
||||
return ycc;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCC -> RGB.
|
||||
* @param y Y coefficient.
|
||||
* @param c1 C coefficient.
|
||||
* @param c2 C coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCCtoRGB(float y, float c1, float c2){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = 0.981f * y + 1.315f * (c2 - 0.537f);
|
||||
float g = 0.981f * y - 0.311f * (c1 - 0.612f)- 0.669f * (c2 - 0.537f);
|
||||
float b = 0.981f * y + 1.601f * (c1 - 0.612f);
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> YCoCg.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return YCoCg color space.
|
||||
*/
|
||||
public static float[] RGBtoYCoCg(int red, int green, int blue){
|
||||
float[] yCoCg = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float y = r / 4f + g / 2f + b / 4f;
|
||||
float co = r / 2f - b / 2f;
|
||||
float cg = -r / 4f + g / 2f - b / 4f;
|
||||
|
||||
yCoCg[0] = y;
|
||||
yCoCg[1] = co;
|
||||
yCoCg[2] = cg;
|
||||
|
||||
return yCoCg;
|
||||
}
|
||||
|
||||
/**
|
||||
* YCoCg -> RGB.
|
||||
* @param y Pseudo luminance, or intensity.
|
||||
* @param co Orange chrominance.
|
||||
* @param cg Green chrominance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] YCoCgtoRGB(float y, float co, float cg){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
float r = y + co - cg;
|
||||
float g = y + cg;
|
||||
float b = y - co - cg;
|
||||
|
||||
rgb[0] = (int)(r * 255f);
|
||||
rgb[1] = (int)(g * 255f);
|
||||
rgb[2] = (int)(b * 255f);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> XYZ
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] RGBtoXYZ(int red, int green, int blue){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
//R
|
||||
if ( r > 0.04045)
|
||||
r = (float)Math.pow(( ( r + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
r /= 12.92f;
|
||||
|
||||
//G
|
||||
if ( g > 0.04045)
|
||||
g = (float)Math.pow(( ( g + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
g /= 12.92f;
|
||||
|
||||
//B
|
||||
if ( b > 0.04045)
|
||||
b = (float)Math.pow(( ( b + 0.055f ) / 1.055f ), 2.4f);
|
||||
else
|
||||
b /= 12.92f;
|
||||
|
||||
r *= 100;
|
||||
g *= 100;
|
||||
b *= 100;
|
||||
|
||||
float x = 0.412453f * r + 0.35758f * g + 0.180423f * b;
|
||||
float y = 0.212671f * r + 0.71516f * g + 0.072169f * b;
|
||||
float z = 0.019334f * r + 0.119193f * g + 0.950227f * b;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> RGB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] XYZtoRGB(float x, float y, float z){
|
||||
int[] rgb = new int[3];
|
||||
|
||||
x /= 100;
|
||||
y /= 100;
|
||||
z /= 100;
|
||||
|
||||
float r = 3.240479f * x - 1.53715f * y - 0.498535f * z;
|
||||
float g = -0.969256f * x + 1.875991f * y + 0.041556f * z;
|
||||
float b = 0.055648f * x - 0.204043f * y + 1.057311f * z;
|
||||
|
||||
if ( r > 0.0031308 )
|
||||
r = 1.055f * ( (float)Math.pow(r, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
r = 12.92f * r;
|
||||
|
||||
if ( g > 0.0031308 )
|
||||
g = 1.055f * ( (float)Math.pow(g, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
g = 12.92f * g;
|
||||
|
||||
if ( b > 0.0031308 )
|
||||
b = 1.055f * ( (float)Math.pow(b, 0.4166f) ) - 0.055f;
|
||||
else
|
||||
b = 12.92f * b;
|
||||
|
||||
rgb[0] = (int)(r * 255);
|
||||
rgb[1] = (int)(g * 255);
|
||||
rgb[2] = (int)(b * 255);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> HunterLAB
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return HunterLab coefficient.
|
||||
*/
|
||||
public static float[] XYZtoHunterLAB(float x, float y, float z){
|
||||
float[] hunter = new float[3];
|
||||
|
||||
|
||||
float sqrt = (float)Math.sqrt(y);
|
||||
|
||||
float l = 10 * sqrt;
|
||||
float a = 17.5f * (((1.02f * x) - y) / sqrt);
|
||||
float b = 7f * ((y - (0.847f * z)) / sqrt);
|
||||
|
||||
hunter[0] = l;
|
||||
hunter[1] = a;
|
||||
hunter[2] = b;
|
||||
|
||||
return hunter;
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> XYZ
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] HunterLABtoXYZ(float l, float a, float b){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
|
||||
float tempY = l / 10f;
|
||||
float tempX = a / 17.5f * l / 10f;
|
||||
float tempZ = b / 7f * l / 10f;
|
||||
|
||||
float y = tempY * tempY;
|
||||
float x = (tempX + y) / 1.02f;
|
||||
float z = -(tempZ - y) / 0.847f;
|
||||
|
||||
xyz[0] = x;
|
||||
xyz[1] = y;
|
||||
xyz[2] = z;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HunterLAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HunterLAB color space.
|
||||
*/
|
||||
public static float[] RGBtoHunterLAB(int red, int green, int blue){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
return XYZtoHunterLAB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* HunterLAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HunterLABtoRGB(float l, float a, float b){
|
||||
float[] xyz = HunterLABtoXYZ(l, a, b);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> HLS.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @return HLS color space.
|
||||
*/
|
||||
public static float[] RGBtoHLS(int red, int green, int blue){
|
||||
float[] hsl = new float[3];
|
||||
|
||||
float r = red / 255f;
|
||||
float g = green / 255f;
|
||||
float b = blue / 255f;
|
||||
|
||||
float max = Math.max(r,Math.max(r,b));
|
||||
float min = Math.min(r,Math.min(r,b));
|
||||
float delta = max - min;
|
||||
|
||||
//HSK
|
||||
float h = 0;
|
||||
float s = 0;
|
||||
float l = (max + min) / 2;
|
||||
|
||||
if ( delta == 0 ){
|
||||
// gray color
|
||||
h = 0;
|
||||
s = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get saturation value
|
||||
s = ( l <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) );
|
||||
|
||||
// get hue value
|
||||
float hue;
|
||||
|
||||
if ( r == max )
|
||||
{
|
||||
hue = ( ( g - b ) / 6 ) / delta;
|
||||
}
|
||||
else if ( g == max )
|
||||
{
|
||||
hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta;
|
||||
}
|
||||
|
||||
// correct hue if needed
|
||||
if ( hue < 0 )
|
||||
hue += 1;
|
||||
if ( hue > 1 )
|
||||
hue -= 1;
|
||||
|
||||
h = (int) ( hue * 360 );
|
||||
}
|
||||
|
||||
hsl[0] = h;
|
||||
hsl[1] = s;
|
||||
hsl[2] = l;
|
||||
|
||||
return hsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* HLS -> RGB.
|
||||
* @param hue Hue.
|
||||
* @param saturation Saturation.
|
||||
* @param luminance Luminance.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] HSLtoRGB(float hue, float saturation, float luminance){
|
||||
int[] rgb = new int[3];
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
if ( saturation == 0 )
|
||||
{
|
||||
// gray values
|
||||
r = g = b = (int) ( luminance * 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
float v1, v2;
|
||||
float h = (float) hue / 360;
|
||||
|
||||
v2 = ( luminance < 0.5 ) ?
|
||||
( luminance * ( 1 + saturation ) ) :
|
||||
( ( luminance + saturation ) - ( luminance * saturation ) );
|
||||
v1 = 2 * luminance - v2;
|
||||
|
||||
r = (int) ( 255 * Hue_2_RGB( v1, v2, h + ( 1.0f / 3 ) ) );
|
||||
g = (int) ( 255 * Hue_2_RGB( v1, v2, h ) );
|
||||
b = (int) ( 255 * Hue_2_RGB( v1, v2, h - ( 1.0f / 3 ) ) );
|
||||
}
|
||||
|
||||
rgb[0] = (int)r;
|
||||
rgb[1] = (int)g;
|
||||
rgb[2] = (int)b;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
private static float Hue_2_RGB( float v1, float v2, float vH ){
|
||||
if ( vH < 0 )
|
||||
vH += 1;
|
||||
if ( vH > 1 )
|
||||
vH -= 1;
|
||||
if ( ( 6 * vH ) < 1 )
|
||||
return ( v1 + ( v2 - v1 ) * 6 * vH );
|
||||
if ( ( 2 * vH ) < 1 )
|
||||
return v2;
|
||||
if ( ( 3 * vH ) < 2 )
|
||||
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
|
||||
return v1;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> CIE-LAB.
|
||||
* @param red Red coefficient. Values in the range [0..255].
|
||||
* @param green Green coefficient. Values in the range [0..255].
|
||||
* @param blue Blue coefficient. Values in the range [0..255].
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] RGBtoLAB(int red, int green, int blue, float[] tristimulus){
|
||||
float[] xyz = RGBtoXYZ(red, green, blue);
|
||||
float[] lab = XYZtoLAB(xyz[0], xyz[1], xyz[2], tristimulus);
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> RGB.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return RGB color space.
|
||||
*/
|
||||
public static int[] LABtoRGB(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = LABtoXYZ(l, a, b, tristimulus);
|
||||
return XYZtoRGB(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> CIE-LAB.
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return CIE-LAB color space.
|
||||
*/
|
||||
public static float[] XYZtoLAB(float x, float y, float z, float[] tristimulus){
|
||||
float[] lab = new float[3];
|
||||
|
||||
x /= tristimulus[0];
|
||||
y /= tristimulus[1];
|
||||
z /= tristimulus[2];
|
||||
|
||||
if (x > 0.008856)
|
||||
x = (float)Math.pow(x,0.33f);
|
||||
else
|
||||
x = (7.787f * x) + ( 0.1379310344827586f );
|
||||
|
||||
if (y > 0.008856)
|
||||
y = (float)Math.pow(y,0.33f);
|
||||
else
|
||||
y = (7.787f * y) + ( 0.1379310344827586f );
|
||||
|
||||
if (z > 0.008856)
|
||||
z = (float)Math.pow(z,0.33f);
|
||||
else
|
||||
z = (7.787f * z) + ( 0.1379310344827586f );
|
||||
|
||||
lab[0] = ( 116 * y ) - 16;
|
||||
lab[1] = 500 * ( x - y );
|
||||
lab[2] = 200 * ( y - z );
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIE-LAB -> XYZ.
|
||||
* @param l L coefficient.
|
||||
* @param a A coefficient.
|
||||
* @param b B coefficient.
|
||||
* @param tristimulus XYZ Tristimulus.
|
||||
* @return XYZ color space.
|
||||
*/
|
||||
public static float[] LABtoXYZ(float l, float a, float b, float[] tristimulus){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
float y = ( l + 16f ) / 116f;
|
||||
float x = a / 500f + y;
|
||||
float z = y - b / 200f;
|
||||
|
||||
//Y
|
||||
if ( Math.pow(y,3) > 0.008856 )
|
||||
y = (float)Math.pow(y,3);
|
||||
else
|
||||
y = (float)(( y - 16 / 116 ) / 7.787);
|
||||
|
||||
//X
|
||||
if ( Math.pow(x,3) > 0.008856 )
|
||||
x = (float)Math.pow(x,3);
|
||||
else
|
||||
x = (float)(( x - 16 / 116 ) / 7.787);
|
||||
|
||||
// Z
|
||||
if ( Math.pow(z,3) > 0.008856 )
|
||||
z = (float)Math.pow(z,3);
|
||||
else
|
||||
z = (float)(( z - 16 / 116 ) / 7.787);
|
||||
|
||||
xyz[0] = x * tristimulus[0];
|
||||
xyz[1] = y * tristimulus[1];
|
||||
xyz[2] = z * tristimulus[2];
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> C1C2C3.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return C1C2C3 color space.
|
||||
*/
|
||||
public static float[] RGBtoC1C2C3(int r, int g, int b){
|
||||
|
||||
float[] c = new float[3];
|
||||
|
||||
c[0] = (float)Math.atan(r / Math.max(g, b));
|
||||
c[1] = (float)Math.atan(g / Math.max(r, b));
|
||||
c[2] = (float)Math.atan(b / Math.max(r, g));
|
||||
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> O1O2.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return O1O2 color space.
|
||||
*/
|
||||
public static float[] RGBtoO1O2(int r, int g, int b){
|
||||
|
||||
float[] o = new float[2];
|
||||
|
||||
o[0] = (r - g) / 2f;
|
||||
o[1] = (r + g) / 4f - (b / 2f);
|
||||
|
||||
return o;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB -> Grayscale.
|
||||
* @param r Red coefficient. Values in the range [0..255].
|
||||
* @param g Green coefficient. Values in the range [0..255].
|
||||
* @param b Blue coefficient. Values in the range [0..255].
|
||||
* @return Grayscale color space.
|
||||
*/
|
||||
public static float RGBtoGrayscale(int r, int g, int b){
|
||||
|
||||
return r*0.2125f + g*0.7154f + b*0.0721f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XYZ -> Philips Hue XY
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @param z Z coefficient.
|
||||
* @return Hue xy array
|
||||
*/
|
||||
public static XYColorSpace XYZtoXY(float x, float y, float z){
|
||||
float[] xy = new float[2];
|
||||
|
||||
xy[0] = x / (x + y + z);
|
||||
xy[1] = y / (x + y + z);
|
||||
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness((int)Math.round(y * 254.0f));
|
||||
xyColor.setXy(xy);
|
||||
return xyColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Philips Hue XY -> XYZ
|
||||
* @param x X coefficient.
|
||||
* @param y Y coefficient.
|
||||
* @return XYZ array
|
||||
*/
|
||||
public static float[] XYtoXYZ(XYColorSpace xy){
|
||||
float[] xyz = new float[3];
|
||||
|
||||
xyz[0] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * xy.getXy()[0];
|
||||
xyz[1] = xy.getBrightnessAdjusted();
|
||||
xyz[2] = (xy.getBrightnessAdjusted() / xy.getXy()[1]) * (1.0f - xy.getXy()[0] - xy.getXy()[1]);
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
public static int[] normalizeRGB(int[] rgb) {
|
||||
int[] newRGB = new int[3];
|
||||
|
||||
newRGB[0] = assureBounds(rgb[0]);
|
||||
newRGB[1] = assureBounds(rgb[1]);
|
||||
newRGB[2] = assureBounds(rgb[2]);
|
||||
|
||||
|
||||
return newRGB;
|
||||
}
|
||||
|
||||
private static int assureBounds(int value) {
|
||||
if (value < 0.0) {
|
||||
value = 0;
|
||||
}
|
||||
if (value > 255.0) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,170 +20,120 @@ 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) {
|
||||
public static List<Integer> convertHSBtoRGB(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;
|
||||
|
||||
if(hsl.getBri() > 0)
|
||||
decimalBrightness = (float) (hsl.getBri() / 255.0);
|
||||
|
||||
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 hue = (Float)(hsb.getHue()*1.0f);
|
||||
Float saturation = (Float)(hsb.getSat()*1.0f);
|
||||
Float brightness = (Float)(hsb.getBri()*1.0f);
|
||||
log.info("Hue = " + hue + ", Sat = " + saturation + ", Bri = " + brightness);
|
||||
//Convert Hue into degrees for HSB
|
||||
hue = hue / 182.04f;
|
||||
//Bri and Sat must be values from 0-1 (~percentage)
|
||||
brightness = brightness / 255.0f;
|
||||
saturation = saturation / 255.0f;
|
||||
|
||||
Float r = 0f;
|
||||
Float g = 0f;
|
||||
Float b = 0f;
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
r = g = b = brightness;
|
||||
}
|
||||
if(hsl.getSat() > 0) {
|
||||
s = (float)(hsl.getSat() / 254.0);
|
||||
else
|
||||
{
|
||||
// the color wheel consists of 6 sectors.
|
||||
Float sectorPos = hue / 60.0f;
|
||||
int sectorNumber = (int)(Math.floor(sectorPos));
|
||||
// get the fractional part of the sector
|
||||
Float fractionalSector = sectorPos - sectorNumber;
|
||||
|
||||
// calculate values for the three axes of the color.
|
||||
Float p = brightness * (1.0f - saturation);
|
||||
Float q = brightness * (1.0f - (saturation * fractionalSector));
|
||||
Float t = brightness * (1.0f - (saturation * (1f - fractionalSector)));
|
||||
|
||||
// assign the fractional colors to r, g, and b based on the sector the angle is in.
|
||||
switch (sectorNumber)
|
||||
{
|
||||
case 0:
|
||||
r = brightness;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = brightness;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = brightness;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = brightness;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = brightness;
|
||||
break;
|
||||
case 5:
|
||||
r = brightness;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
//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));
|
||||
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.debug("Color change with HSB: " + 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)
|
||||
{
|
||||
vh = vh + (float)1;
|
||||
};
|
||||
|
||||
if (vh > 1.0)
|
||||
{
|
||||
vh = vh - (float)1;
|
||||
};
|
||||
|
||||
if (((float)6.0 * vh) < 1.0)
|
||||
{
|
||||
return (v1 + (v2 - v1) * (float)6.0 * vh);
|
||||
};
|
||||
|
||||
if (((float)2.0 * vh) < 1.0)
|
||||
{
|
||||
return (v2);
|
||||
};
|
||||
|
||||
if ((3.0 * vh) < 2.0)
|
||||
{
|
||||
return (v1 + (v2 - v1) * (((float)2.0 / (float)3.0 - vh) * (float)6.0));
|
||||
};
|
||||
|
||||
return (v1);
|
||||
}
|
||||
|
||||
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) + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1)
|
||||
+ " " + rgb.get(2));
|
||||
return rgb;
|
||||
}
|
||||
@@ -253,7 +203,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 +247,66 @@ 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 {
|
||||
List<Double> xyData = (List<Double>) colorData.getData();
|
||||
request = request.replace(COLOR_XY, String.format("%f,%f", xyData.get(0), xyData.get(1)));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_H)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_H, String.format("%d", hslData.getHue()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float hue = hsb[0] * (float) 360.0;
|
||||
request = request.replace(COLOR_H, String.format("%f", hue));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_S)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_S, String.format("%d", hslData.getSat()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
request = request.replace(COLOR_S, String.format("%f", sat));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_BRI)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_BRI, String.format("%d", hslData.getBri()));
|
||||
} else {
|
||||
request = request.replace(COLOR_BRI, String.format("%f", setIntensity));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
if (request.contains(COLOR_HSB)) {
|
||||
if (colorMode == ColorData.ColorMode.HS) {
|
||||
HueSatBri hslData = (HueSatBri) colorData.getData();
|
||||
request = request.replace(COLOR_HSB,
|
||||
String.format("%d,%d,%d", hslData.getHue(), hslData.getSat(), hslData.getBri()));
|
||||
} else {
|
||||
float[] hsb = new float[3];
|
||||
Color.RGBtoHSB(rgb.get(0), rgb.get(1), rgb.get(2), hsb);
|
||||
float hue = hsb[0] * (float) 360.0;
|
||||
float sat = hsb[1] * (float) 100.0;
|
||||
float bright = hsb[2] * (float) 100.0;
|
||||
request = request.replace(COLOR_HSB, String.format("%f,%f,%f", hue, sat, bright));
|
||||
}
|
||||
notDone = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ||
|
||||
@@ -1416,8 +1416,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 +1440,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 {
|
||||
|
||||
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
26
src/main/java/com/bwssystems/HABridge/hue/XYColorSpace.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge.hue;
|
||||
|
||||
public class XYColorSpace {
|
||||
float[] xy;
|
||||
int brightness;
|
||||
|
||||
public float[] getXy() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXy(float[] xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
public float getBrightnessAdjusted() {
|
||||
return ((float) brightness / 254.0f) * 100f;
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
this.brightness = brightness;
|
||||
}
|
||||
}
|
||||
@@ -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 + "}";
|
||||
|
||||
@@ -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.*;
|
||||
@@ -37,63 +38,33 @@ 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 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";
|
||||
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";
|
||||
|
||||
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 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";
|
||||
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";
|
||||
|
||||
public UpnpListener(BridgeSettings theSettings, BridgeControlDescriptor theControl,
|
||||
UDPDatagramSender aUdpDatagramSender) throws IOException {
|
||||
@@ -112,17 +83,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): "
|
||||
@@ -133,6 +105,11 @@ public class UpnpListener {
|
||||
}
|
||||
|
||||
public boolean startListening() {
|
||||
if (bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||
log.warn("UPNP Listener exiting as reinit or stop requested....");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("UPNP Discovery Listener starting....");
|
||||
Enumeration<NetworkInterface> ifs = null;
|
||||
|
||||
@@ -160,7 +137,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);
|
||||
@@ -198,7 +175,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) {
|
||||
@@ -206,6 +184,11 @@ public class UpnpListener {
|
||||
}
|
||||
}
|
||||
|
||||
if (bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||
log.warn("UPNP Listener exiting as reinit or stop requested....");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("UPNP Discovery Listener running and ready....");
|
||||
boolean loopControl = true;
|
||||
boolean error = false;
|
||||
@@ -214,8 +197,8 @@ public class UpnpListener {
|
||||
} 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);
|
||||
@@ -224,26 +207,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());
|
||||
@@ -266,7 +246,7 @@ public class UpnpListener {
|
||||
}
|
||||
}
|
||||
upnpMulticastSocket.close();
|
||||
if(jmdns != null) {
|
||||
if (jmdns != null) {
|
||||
// Unregister all services
|
||||
jmdns.unregisterAllServices();
|
||||
}
|
||||
@@ -287,11 +267,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());
|
||||
@@ -317,63 +297,71 @@ 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, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, 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);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate2, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
|
||||
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
|
||||
bridgeSNUUID, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
|
||||
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate3, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
|
||||
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, httpLocationAddress, httpServerPort, bridgeId,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
|
||||
+ httpServerPort + " to address: " + requester.getHostAddress() + ":" + sourcePort);
|
||||
}
|
||||
log.debug("sendUpnpResponse to address: " + requester.getHostAddress() + ":" + sourcePort
|
||||
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
|
||||
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -391,8 +379,9 @@ public class UpnpListener {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate1, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
|
||||
notifyData = String.format(notifyTemplate1, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID,
|
||||
bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate1");
|
||||
}
|
||||
@@ -405,43 +394,26 @@ public class UpnpListener {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate2, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
notifyData = String.format(notifyTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate2");
|
||||
}
|
||||
log.debug("sendUpnpNotify notifyTemplate2 is <<<{}>>>", notifyData);
|
||||
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(theUpnpSendDelay);
|
||||
} catch (InterruptedException e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
notifyData = String.format(notifyTemplate3, httpType, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
notifyData = String.format(notifyTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
|
||||
Configuration.UPNP_DISCOVERY_PORT, httpType, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
|
||||
if (traceupnp) {
|
||||
log.info("Traceupnp: sendUpnpNotify notifyTemplate3");
|
||||
}
|
||||
log.debug("sendUpnpNotify notifyTemplate3 is <<<{}>>>", notifyData);
|
||||
sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -98,7 +94,13 @@ public class UpnpSettingsResource {
|
||||
httpLocationAddr = theSettings.getUpnpConfigAddress();
|
||||
hueTemplate = hueTemplate_pre + hueTemplate_mid_orig + hueTemplate_post;
|
||||
} else {
|
||||
httpLocationAddr = getOutboundAddress(request.ip(), request.port()).getHostAddress();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -136,28 +138,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;
|
||||
}
|
||||
}
|
||||
|
||||
62
src/main/java/com/bwssystems/HABridge/util/AddressUtil.java
Normal file
62
src/main/java/com/bwssystems/HABridge/util/AddressUtil.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.bwssystems.HABridge.util;
|
||||
|
||||
import java.net.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AddressUtil {
|
||||
final static Logger log = LoggerFactory.getLogger(AddressUtil.class);
|
||||
|
||||
// added by https://github.com/pvint
|
||||
// Ruthlessly stolen from
|
||||
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
|
||||
// Try to get a source IP that makes sense for the requester to contact for use
|
||||
// in the LOCATION header in replies
|
||||
public static InetAddress getOutboundAddress(String remoteAddress, int remotePort) {
|
||||
InetAddress localAddress = null;
|
||||
log.debug("Entering getOutboundAddress with args.");
|
||||
try {
|
||||
localAddress = getOutboundAddress(new InetSocketAddress(remoteAddress, remotePort));
|
||||
} catch (Exception e) {
|
||||
log.debug("getOutboundAddress(SocketAddress) Threw an Exception: " + e.getMessage());
|
||||
ParseRoute theRoute = ParseRoute.getInstance();
|
||||
try {
|
||||
localAddress = InetAddress.getByName(theRoute.getLocalIPAddress());
|
||||
log.warn("Error <" + e.getMessage() + "> on determining interface to reply for <" + remoteAddress
|
||||
+ ">. Using default route IP Address of " + localAddress.getHostAddress());
|
||||
} catch (Exception e1) {
|
||||
log.error("Cannot find address for parsed local ip address: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if(localAddress != null)
|
||||
log.debug("localAddress is IP Address of " + localAddress.getHostAddress());
|
||||
else
|
||||
log.debug("localAddress returning NULL");
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
// added by https://github.com/pvint
|
||||
// Ruthlessly stolen from
|
||||
// https://stackoverflow.com/questions/22045165/java-datagrampacket-receive-how-to-determine-local-ip-interface
|
||||
// Try to get a source IP that makes sense for the requestor to contact for use
|
||||
// in the LOCATION header in replies
|
||||
public static InetAddress getOutboundAddress(SocketAddress remoteAddress) throws SocketException {
|
||||
DatagramSocket sock = new DatagramSocket();
|
||||
// connect is needed to bind the socket and retrieve the local address
|
||||
// later (it would return 0.0.0.0 otherwise)
|
||||
log.debug("Entering getOutboundAddress with socket arg.");
|
||||
sock.connect(remoteAddress);
|
||||
log.debug("getOutboundAddress(SocketAddress) getLocalAddress.");
|
||||
final InetAddress localAddress = sock.getLocalAddress();
|
||||
sock.disconnect();
|
||||
sock.close();
|
||||
sock = null;
|
||||
if(localAddress != null)
|
||||
log.debug("getOutbountAddress(SocketAddress) returning IP Address of " + localAddress.getHostAddress());
|
||||
else
|
||||
log.debug("getOutboundAddress(SocketAddress) returning NULL");
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
@@ -367,6 +367,18 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
|
||||
};
|
||||
|
||||
this.changeSecuritySettings = function (useLinkButton, secureHueApi, execGarden, useHttps, keyfilePath, keyfilePassword) {
|
||||
if(useHttps) {
|
||||
if(!keyfilePassword || keyfilePassword.length == 0 || !keyfilePassword.trim()) {
|
||||
self.displayErrorMessage("Use HTTPS - ", "Key File Password cannot be empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!keyfilePath || keyfilePath.length == 0 || !keyfilePath.trim()) {
|
||||
self.displayErrorMessage("Use HTTPS - ", "Key File Path cannot be empty.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var newSecurityInfo = {};
|
||||
newSecurityInfo = {
|
||||
useLinkButton: useLinkButton,
|
||||
@@ -376,6 +388,7 @@ app.service('bridgeService', function ($rootScope, $http, $base64, $location, ng
|
||||
keyfilePath: keyfilePath,
|
||||
keyfilePassword: keyfilePassword
|
||||
};
|
||||
|
||||
return $http.post(this.state.systemsbase + "/changesecurityinfo", newSecurityInfo).then(
|
||||
function (response) {
|
||||
self.state.securityInfo = response.data;
|
||||
@@ -2082,21 +2095,25 @@ app.controller('SystemController', function ($scope, $location, bridgeService, n
|
||||
}
|
||||
|
||||
var othertypes = [];
|
||||
othertypes = newhomegenieothertypes.split(",");
|
||||
var theModuleTypes = [];
|
||||
var count = 0;
|
||||
if (othertypes.length > 0) {
|
||||
for (var i = 0; i < othertypes.length; i++) {
|
||||
var aType = othertypes[i].trim();
|
||||
if (aType.length > 0) {
|
||||
var moduleType = {
|
||||
moduleType: aType
|
||||
};
|
||||
theModuleTypes.push(moduleType);
|
||||
count++;
|
||||
var theModuleTypes = [];
|
||||
|
||||
if(newhomegenieothertypes && newhomegenieothertypes.trim() && newhomegenieothertypes.length > 0) {
|
||||
othertypes = newhomegenieothertypes.split(",");
|
||||
if (othertypes.length > 0) {
|
||||
for (var i = 0; i < othertypes.length; i++) {
|
||||
var aType = othertypes[i].trim();
|
||||
if (aType.length > 0) {
|
||||
var moduleType = {
|
||||
moduleType: aType
|
||||
};
|
||||
theModuleTypes.push(moduleType);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var theExtension;
|
||||
if (count == 0) {
|
||||
theExtension = undefined;
|
||||
|
||||
@@ -761,7 +761,7 @@
|
||||
<td><input type="checkbox" ng-model="newhomegeniesecure" ng-true-value=true
|
||||
ng-false-value=false></td>
|
||||
<td><button class="btn btn-success" type="submit"
|
||||
ng-click="addHomeGenietoSettings(newhomegeniename, newhomegenieip, newhomegenieport, newshomegenieusername, newhomegeniepassword, newhomegeniewebhook, newhomegeniesecure, newhomegenieothertypes)">Add</button>
|
||||
ng-click="addHomeGenietoSettings(newhomegeniename, newhomegenieip, newhomegenieport, newhomegenieusername, newhomegeniepassword, newhomegeniewebhook, newhomegeniesecure, newhomegenieothertypes)">Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -9,23 +9,92 @@ 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.671254"), Double.parseDouble("0.303273")));
|
||||
|
||||
List<Integer> colorDecode = ColorDecode.convertCIEtoRGB(xy, 254);
|
||||
XYColorSpace xyColor = new XYColorSpace();
|
||||
xyColor.setBrightness(50);
|
||||
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, 255);
|
||||
assertDecode.add(1, 47);
|
||||
assertDecode.add(2, 43);
|
||||
assertDecode.add(1, 0);
|
||||
assertDecode.add(2, 5);
|
||||
Assert.assertEquals(rgbDecode, 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, 50);
|
||||
List<Integer> assertDecode = new ArrayList<Integer>();
|
||||
assertDecode.add(0, 255);
|
||||
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 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, 60);
|
||||
assertDecode.add(1, 97);
|
||||
assertDecode.add(2, 128);
|
||||
Assert.assertEquals(colorDecode, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user