@@ -83,7 +83,7 @@ def bridgeDiscovery(params=[:])
83
83
84
84
return dynamicPage(name :" bridgeDiscovery" , title :" Discovery Started!" , nextPage :" bridgeBtnPush" , refreshInterval :refreshInterval, uninstall : true ) {
85
85
section(" Please wait while we discover your Hue Bridge. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered." ) {
86
- input " selectedHue" , " enum" , required :false , title :" Select Hue Bridge (${ numFound} found)" , multiple :false , options :options
86
+ input " selectedHue" , " enum" , required :false , title :" Select Hue Bridge (${ numFound} found)" , multiple :false , options :options, submitOnChange : true
87
87
}
88
88
}
89
89
}
@@ -963,6 +963,14 @@ private handleCommandResponse(body) {
963
963
* @return empty array
964
964
*/
965
965
private handlePoll (body ) {
966
+ // Used to track "unreachable" time
967
+ // Device is considered "offline" if it has been in the "unreachable" state for
968
+ // 11 minutes (e.g. two poll intervals)
969
+ // Note, Hue Bridge marks devices as "unreachable" often even when they accept commands
970
+ Calendar time11 = Calendar . getInstance()
971
+ time11. add(Calendar . MINUTE , -11 )
972
+ Calendar currentTime = Calendar . getInstance()
973
+
966
974
def bulbs = getChildDevices()
967
975
for (bulb in body) {
968
976
def device = bulbs. find{it. deviceNetworkId == " ${ app.id} /${ bulb.key} " }
@@ -972,7 +980,10 @@ private handlePoll(body) {
972
980
// light just came back online, notify device watch
973
981
def lastActivity = now()
974
982
device. sendEvent(name : " deviceWatch-status" , value : " ONLINE" , description : " Last Activity is on ${ new Date((long) lastActivity)} " , displayed : false , isStateChange : true )
983
+ log. debug " $device is Online"
975
984
}
985
+ // Mark light as "online"
986
+ state. bulbs[bulb. key]?. unreachableSince = null
976
987
state. bulbs[bulb. key]?. online = true
977
988
978
989
// If user just executed commands, then do not send events to avoid confusing the turning on/off state
@@ -982,9 +993,18 @@ private handlePoll(body) {
982
993
sendColorEvents(device, bulb. value?. state?. xy, bulb. value?. state?. hue, bulb. value?. state?. sat, bulb. value?. state?. ct, bulb. value?. state?. colormode)
983
994
}
984
995
} else {
985
- state. bulbs[bulb. key]?. online = false
986
- log. warn " $device is not reachable by Hue bridge"
987
- device. sendEvent(name : " DeviceWatch-DeviceOffline" , value : " offline" , displayed : false , isStateChange : true )
996
+ if (state. bulbs[bulb. key]?. unreachableSince == null ) {
997
+ // Store the first time where device was reported as "unreachable"
998
+ state. bulbs[bulb. key]?. unreachableSince = currentTime. getTimeInMillis()
999
+ } else if (state. bulbs[bulb. key]?. online) {
1000
+ // Check if device was "unreachable" for more than 11 minutes and mark "offline" if necessary
1001
+ if (state. bulbs[bulb. key]?. unreachableSince < time11. getTimeInMillis()) {
1002
+ log. warn " $device went Offline"
1003
+ state. bulbs[bulb. key]?. online = false
1004
+ device. sendEvent(name : " DeviceWatch-DeviceOffline" , value : " offline" , displayed : false , isStateChange : true )
1005
+ }
1006
+ }
1007
+ log. warn " $device may not reachable by Hue bridge"
988
1008
}
989
1009
}
990
1010
}
@@ -1019,9 +1039,6 @@ def hubVerification(bodytext) {
1019
1039
def on (childDevice ) {
1020
1040
log. debug " Executing 'on'"
1021
1041
def id = getId(childDevice)
1022
- if (! isOnline(id)) {
1023
- return " Bulb is unreachable"
1024
- }
1025
1042
updateInProgress()
1026
1043
createSwitchEvent(childDevice, " on" )
1027
1044
put(" lights/$id /state" , [on : true ])
@@ -1031,9 +1048,6 @@ def on(childDevice) {
1031
1048
def off (childDevice ) {
1032
1049
log. debug " Executing 'off'"
1033
1050
def id = getId(childDevice)
1034
- if (! isOnline(id)) {
1035
- return " Bulb is unreachable"
1036
- }
1037
1051
updateInProgress()
1038
1052
createSwitchEvent(childDevice, " off" )
1039
1053
put(" lights/$id /state" , [on : false ])
@@ -1043,9 +1057,6 @@ def off(childDevice) {
1043
1057
def setLevel (childDevice , percent ) {
1044
1058
log. debug " Executing 'setLevel'"
1045
1059
def id = getId(childDevice)
1046
- if (! isOnline(id)) {
1047
- return " Bulb is unreachable"
1048
- }
1049
1060
updateInProgress()
1050
1061
// 1 - 254
1051
1062
def level
@@ -1070,10 +1081,6 @@ def setLevel(childDevice, percent) {
1070
1081
def setSaturation (childDevice , percent ) {
1071
1082
log. debug " Executing 'setSaturation($percent )'"
1072
1083
def id = getId(childDevice)
1073
- if (! isOnline(id)) {
1074
- return " Bulb is unreachable"
1075
- }
1076
-
1077
1084
updateInProgress()
1078
1085
// 0 - 254
1079
1086
def level = Math . min(Math . round(percent * 254 / 100 ), 254 )
@@ -1086,9 +1093,6 @@ def setSaturation(childDevice, percent) {
1086
1093
def setHue (childDevice , percent ) {
1087
1094
log. debug " Executing 'setHue($percent )'"
1088
1095
def id = getId(childDevice)
1089
- if (! isOnline(id)) {
1090
- return " Bulb is unreachable"
1091
- }
1092
1096
updateInProgress()
1093
1097
// 0 - 65535
1094
1098
def level = Math . min(Math . round(percent * 65535 / 100 ), 65535 )
@@ -1101,9 +1105,6 @@ def setHue(childDevice, percent) {
1101
1105
def setColorTemperature (childDevice , huesettings ) {
1102
1106
log. debug " Executing 'setColorTemperature($huesettings )'"
1103
1107
def id = getId(childDevice)
1104
- if (! isOnline(id)) {
1105
- return " Bulb is unreachable"
1106
- }
1107
1108
updateInProgress()
1108
1109
// 153 (6500K) to 500 (2000K)
1109
1110
def ct = hueSettings == 6500 ? 153 : Math . round(1000000 / huesettings)
@@ -1115,9 +1116,6 @@ def setColorTemperature(childDevice, huesettings) {
1115
1116
def setColor (childDevice , huesettings ) {
1116
1117
log. debug " Executing 'setColor($huesettings )'"
1117
1118
def id = getId(childDevice)
1118
- if (! isOnline(id)) {
1119
- return " Bulb is unreachable"
1120
- }
1121
1119
updateInProgress()
1122
1120
1123
1121
def value = [:]
@@ -1133,7 +1131,7 @@ def setColor(childDevice, huesettings) {
1133
1131
value. hue = Math . min(Math . round(huesettings. hue * 65535 / 100 ), 65535 )
1134
1132
if (huesettings. saturation != null )
1135
1133
value. sat = Math . min(Math . round(huesettings. saturation * 254 / 100 ), 254 )
1136
- } else if (huesettings. hex != null && false ) {
1134
+ } else if (huesettings. hex != null ) {
1137
1135
// For now ignore model to get a consistent color if same color is set across multiple devices
1138
1136
// def model = state.bulbs[getId(childDevice)]?.modelid
1139
1137
// value.xy = calculateXY(huesettings.hex, model)
@@ -1237,7 +1235,7 @@ private getBridgeIP() {
1237
1235
if (d) {
1238
1236
if (d. getDeviceDataByName(" networkAddress" ))
1239
1237
host = d. getDeviceDataByName(" networkAddress" )
1240
- else
1238
+ else
1241
1239
host = d. latestState(' networkAddress' ). stringValue
1242
1240
}
1243
1241
if (host == null || host == " " ) {
@@ -1676,7 +1674,7 @@ private boolean checkPointInLampsReach(p, colorPoints) {
1676
1674
}
1677
1675
1678
1676
/**
1679
- * Converts an RGB color in hex to HSV.
1677
+ * Converts an RGB color in hex to HSV/HSB .
1680
1678
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
1681
1679
*
1682
1680
* @param colorStr color value in hex (#ff03d3)
@@ -1686,32 +1684,32 @@ private boolean checkPointInLampsReach(p, colorPoints) {
1686
1684
def hexToHsv (colorStr ){
1687
1685
def r = Integer . valueOf( colorStr. substring( 1 , 3 ), 16 ) / 255
1688
1686
def g = Integer . valueOf( colorStr. substring( 3 , 5 ), 16 ) / 255
1689
- def b = Integer . valueOf( colorStr. substring( 5 , 7 ), 16 ) / 255 ;
1687
+ def b = Integer . valueOf( colorStr. substring( 5 , 7 ), 16 ) / 255
1690
1688
1691
1689
def max = Math . max(Math . max(r, g), b)
1692
1690
def min = Math . min(Math . min(r, g), b)
1693
1691
1694
- def h, s, v = max;
1692
+ def h, s, v = max
1695
1693
1696
- def d = max - min;
1697
- s = max == 0 ? 0 : d / max;
1694
+ def d = max - min
1695
+ s = max == 0 ? 0 : d / max
1698
1696
1699
1697
if (max == min){
1700
- h = 0 ;
1698
+ h = 0
1701
1699
}else {
1702
1700
switch (max){
1703
- case r: h = (g - b) / d + (g < b ? 6 : 0 ); break ;
1704
- case g: h = (b - r) / d + 2 ; break ;
1705
- case b: h = (r - g) / d + 4 ; break ;
1701
+ case r: h = (g - b) / d + (g < b ? 6 : 0 ); break
1702
+ case g: h = (b - r) / d + 2 ; break
1703
+ case b: h = (r - g) / d + 4 ; break
1706
1704
}
1707
1705
h / = 6 ;
1708
1706
}
1709
1707
1710
- return [(h * 100 ). round(), ( s * 100 ). round(), ( v * 100 ). round()];
1708
+ return [Math . round (h * 100 ), Math . round(s * 100 ), Math . round(v * 100 )]
1711
1709
}
1712
1710
1713
1711
/**
1714
- * Converts HSV color to RGB in hex.
1712
+ * Converts HSV/HSB color to RGB in hex.
1715
1713
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
1716
1714
*
1717
1715
* @param hue hue 0-100
@@ -1726,11 +1724,11 @@ def hsvToHex(hue, sat, value = 100){
1726
1724
def s = sat / 100
1727
1725
def v = value / 100
1728
1726
1729
- def i = Math . floor(h * 6 );
1730
- def f = h * 6 - i;
1731
- def p = v * (1 - s);
1732
- def q = v * (1 - f * s);
1733
- def t = v * (1 - (1 - f) * s);
1727
+ def i = Math . floor(h * 6 )
1728
+ def f = h * 6 - i
1729
+ def p = v * (1 - s)
1730
+ def q = v * (1 - f * s)
1731
+ def t = v * (1 - (1 - f) * s)
1734
1732
1735
1733
switch (i % 6 ) {
1736
1734
case 0 :
@@ -1766,9 +1764,9 @@ def hsvToHex(hue, sat, value = 100){
1766
1764
}
1767
1765
1768
1766
// Converting float components to int components.
1769
- def r1 = String . format(" %02X" , (int ) (r * 255.0f ));
1770
- def g1 = String . format(" %02X" , (int ) (g * 255.0f ));
1771
- def b1 = String . format(" %02X" , (int ) (b * 255.0f ));
1767
+ def r1 = String . format(" %02X" , (int ) (r * 255.0f ))
1768
+ def g1 = String . format(" %02X" , (int ) (g * 255.0f ))
1769
+ def b1 = String . format(" %02X" , (int ) (b * 255.0f ))
1772
1770
1773
1771
return " #$r1 $g1 $b1 "
1774
1772
}
0 commit comments