Compare commits

..

1 Commits

Author SHA1 Message Date
Dr. Bunsen Honeydew
22bbe08d0c DEVC-489: Adding a fingerprint line to the DTH 2016-09-27 16:30:34 -05:00
5 changed files with 72 additions and 82 deletions

View File

@@ -180,9 +180,9 @@ private Map parseIasMessage(String description) {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -194,9 +194,9 @@ private Map parseIasMessage(String description) {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -261,9 +261,9 @@ def updated() {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -21,6 +21,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Wireless Load Control Module-30amp"
} }
// simulator metadata // simulator metadata
@@ -79,4 +80,4 @@ def refresh() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.onOffRefresh() zigbee.onOffConfig() + zigbee.onOffRefresh()
} }

View File

@@ -83,7 +83,7 @@ def bridgeDiscovery(params=[:])
return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) { return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) {
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.") { 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.") {
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options
} }
} }
} }
@@ -333,9 +333,9 @@ def bulbListHandler(hub, data = "") {
def bridge = null def bridge = null
if (selectedHue) { if (selectedHue) {
bridge = getChildDevice(selectedHue) bridge = getChildDevice(selectedHue)
bridge?.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
} }
msg = "${bulbs.size()} bulbs found. ${bulbs}" bridge.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
msg = "${bulbs.size()} bulbs found. ${bulbs}"
return msg return msg
} }
@@ -490,25 +490,24 @@ def ssdpBridgeHandler(evt) {
def host = ip + ":" + port def host = ip + ":" + port
log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host." log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host."
def dstate = bridges."${parsedEvent.ssdpUSN.toString()}" def dstate = bridges."${parsedEvent.ssdpUSN.toString()}"
def dniReceived = "${parsedEvent.mac}" def dni = "${parsedEvent.mac}"
def currentDni = dstate.mac def d = getChildDevice(dni)
def d = getChildDevice(dniReceived)
def networkAddress = null def networkAddress = null
if (!d) { if (!d) {
// There might be a mismatch between bridge DNI and the actual bridge mac address, correct that childDevices.each {
log.debug "Bridge with $dniReceived not found" if (it.getDeviceDataByName("mac")) {
def bridge = childDevices.find { it.deviceNetworkId == currentDni } def newDNI = "${it.getDeviceDataByName("mac")}"
if (bridge != null) { d = it
log.warn "Bridge is set to ${bridge.deviceNetworkId}, updating to $dniReceived" if (newDNI != it.deviceNetworkId) {
bridge.setDeviceNetworkId("${dniReceived}") def oldDNI = it.deviceNetworkId
dstate.mac = dniReceived log.debug "updating dni for device ${it} with $newDNI - previous DNI = ${it.deviceNetworkId}"
// Check to see if selectedHue is a valid bridge, otherwise update it it.setDeviceNetworkId("${newDNI}")
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue} if (oldDNI == selectedHue) {
if (isSelectedValid == null) { app.updateSetting("selectedHue", newDNI)
log.warn "Correcting selectedHue in state" }
app.updateSetting("selectedHue", dniReceived) doDeviceSync()
}
} }
doDeviceSync()
} }
} else { } else {
updateBridgeStatus(d) updateBridgeStatus(d)
@@ -526,18 +525,6 @@ def ssdpBridgeHandler(evt) {
d.sendEvent(name:"networkAddress", value: host) d.sendEvent(name:"networkAddress", value: host)
d.updateDataValue("networkAddress", host) d.updateDataValue("networkAddress", host)
} }
if (dstate.mac != dniReceived) {
log.warn "Correcting bridge mac address in state"
dstate.mac = dniReceived
}
if (selectedHue != dniReceived) {
// Check to see if selectedHue is a valid bridge, otherwise update it
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
if (isSelectedValid == null) {
log.warn "Correcting selectedHue in state"
app.updateSetting("selectedHue", dniReceived)
}
}
} }
} }
} }
@@ -963,14 +950,6 @@ private handleCommandResponse(body) {
* @return empty array * @return empty array
*/ */
private handlePoll(body) { private handlePoll(body) {
// Used to track "unreachable" time
// Device is considered "offline" if it has been in the "unreachable" state for
// 11 minutes (e.g. two poll intervals)
// Note, Hue Bridge marks devices as "unreachable" often even when they accept commands
Calendar time11 = Calendar.getInstance()
time11.add(Calendar.MINUTE, -11)
Calendar currentTime = Calendar.getInstance()
def bulbs = getChildDevices() def bulbs = getChildDevices()
for (bulb in body) { for (bulb in body) {
def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"} def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
@@ -980,10 +959,7 @@ private handlePoll(body) {
// light just came back online, notify device watch // light just came back online, notify device watch
def lastActivity = now() def lastActivity = now()
device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true) device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true)
log.debug "$device is Online"
} }
// Mark light as "online"
state.bulbs[bulb.key]?.unreachableSince = null
state.bulbs[bulb.key]?.online = true state.bulbs[bulb.key]?.online = true
// If user just executed commands, then do not send events to avoid confusing the turning on/off state // If user just executed commands, then do not send events to avoid confusing the turning on/off state
@@ -993,18 +969,9 @@ private handlePoll(body) {
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode) sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode)
} }
} else { } else {
if (state.bulbs[bulb.key]?.unreachableSince == null) { state.bulbs[bulb.key]?.online = false
// Store the first time where device was reported as "unreachable" log.warn "$device is not reachable by Hue bridge"
state.bulbs[bulb.key]?.unreachableSince = currentTime.getTimeInMillis() device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
} else if (state.bulbs[bulb.key]?.online) {
// Check if device was "unreachable" for more than 11 minutes and mark "offline" if necessary
if (state.bulbs[bulb.key]?.unreachableSince < time11.getTimeInMillis()) {
log.warn "$device went Offline"
state.bulbs[bulb.key]?.online = false
device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
}
}
log.warn "$device may not reachable by Hue bridge"
} }
} }
} }
@@ -1039,6 +1006,9 @@ def hubVerification(bodytext) {
def on(childDevice) { def on(childDevice) {
log.debug "Executing 'on'" log.debug "Executing 'on'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/$id/state", [on: true]) put("lights/$id/state", [on: true])
@@ -1048,6 +1018,9 @@ def on(childDevice) {
def off(childDevice) { def off(childDevice) {
log.debug "Executing 'off'" log.debug "Executing 'off'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "off") createSwitchEvent(childDevice, "off")
put("lights/$id/state", [on: false]) put("lights/$id/state", [on: false])
@@ -1057,6 +1030,9 @@ def off(childDevice) {
def setLevel(childDevice, percent) { def setLevel(childDevice, percent) {
log.debug "Executing 'setLevel'" log.debug "Executing 'setLevel'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 1 - 254 // 1 - 254
def level def level
@@ -1081,6 +1057,10 @@ def setLevel(childDevice, percent) {
def setSaturation(childDevice, percent) { def setSaturation(childDevice, percent) {
log.debug "Executing 'setSaturation($percent)'" log.debug "Executing 'setSaturation($percent)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 0 - 254 // 0 - 254
def level = Math.min(Math.round(percent * 254 / 100), 254) def level = Math.min(Math.round(percent * 254 / 100), 254)
@@ -1093,6 +1073,9 @@ def setSaturation(childDevice, percent) {
def setHue(childDevice, percent) { def setHue(childDevice, percent) {
log.debug "Executing 'setHue($percent)'" log.debug "Executing 'setHue($percent)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 0 - 65535 // 0 - 65535
def level = Math.min(Math.round(percent * 65535 / 100), 65535) def level = Math.min(Math.round(percent * 65535 / 100), 65535)
@@ -1105,6 +1088,9 @@ def setHue(childDevice, percent) {
def setColorTemperature(childDevice, huesettings) { def setColorTemperature(childDevice, huesettings) {
log.debug "Executing 'setColorTemperature($huesettings)'" log.debug "Executing 'setColorTemperature($huesettings)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 153 (6500K) to 500 (2000K) // 153 (6500K) to 500 (2000K)
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings) def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
@@ -1116,6 +1102,9 @@ def setColorTemperature(childDevice, huesettings) {
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'" log.debug "Executing 'setColor($huesettings)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
def value = [:] def value = [:]
@@ -1131,7 +1120,7 @@ def setColor(childDevice, huesettings) {
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535) value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
if (huesettings.saturation != null) if (huesettings.saturation != null)
value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254) value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254)
} else if (huesettings.hex != null) { } else if (huesettings.hex != null && false) {
// For now ignore model to get a consistent color if same color is set across multiple devices // For now ignore model to get a consistent color if same color is set across multiple devices
// def model = state.bulbs[getId(childDevice)]?.modelid // def model = state.bulbs[getId(childDevice)]?.modelid
// value.xy = calculateXY(huesettings.hex, model) // value.xy = calculateXY(huesettings.hex, model)
@@ -1235,7 +1224,7 @@ private getBridgeIP() {
if (d) { if (d) {
if (d.getDeviceDataByName("networkAddress")) if (d.getDeviceDataByName("networkAddress"))
host = d.getDeviceDataByName("networkAddress") host = d.getDeviceDataByName("networkAddress")
else else
host = d.latestState('networkAddress').stringValue host = d.latestState('networkAddress').stringValue
} }
if (host == null || host == "") { if (host == null || host == "") {
@@ -1674,7 +1663,7 @@ private boolean checkPointInLampsReach(p, colorPoints) {
} }
/** /**
* Converts an RGB color in hex to HSV/HSB. * Converts an RGB color in hex to HSV.
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
* *
* @param colorStr color value in hex (#ff03d3) * @param colorStr color value in hex (#ff03d3)
@@ -1684,32 +1673,32 @@ private boolean checkPointInLampsReach(p, colorPoints) {
def hexToHsv(colorStr){ def hexToHsv(colorStr){
def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255 def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255
def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255 def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255
def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255 def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255;
def max = Math.max(Math.max(r, g), b) def max = Math.max(Math.max(r, g), b)
def min = Math.min(Math.min(r, g), b) def min = Math.min(Math.min(r, g), b)
def h, s, v = max def h, s, v = max;
def d = max - min def d = max - min;
s = max == 0 ? 0 : d / max s = max == 0 ? 0 : d / max;
if(max == min){ if(max == min){
h = 0 h = 0;
}else{ }else{
switch(max){ switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break case b: h = (r - g) / d + 4; break;
} }
h /= 6; h /= 6;
} }
return [Math.round(h * 100), Math.round(s * 100), Math.round(v * 100)] return [(h * 100).round(), (s * 100).round(), (v * 100).round()];
} }
/** /**
* Converts HSV/HSB color to RGB in hex. * Converts HSV color to RGB in hex.
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
* *
* @param hue hue 0-100 * @param hue hue 0-100
@@ -1724,11 +1713,11 @@ def hsvToHex(hue, sat, value = 100){
def s = sat / 100 def s = sat / 100
def v = value / 100 def v = value / 100
def i = Math.floor(h * 6) def i = Math.floor(h * 6);
def f = h * 6 - i def f = h * 6 - i;
def p = v * (1 - s) def p = v * (1 - s);
def q = v * (1 - f * s) def q = v * (1 - f * s);
def t = v * (1 - (1 - f) * s) def t = v * (1 - (1 - f) * s);
switch (i % 6) { switch (i % 6) {
case 0: case 0:
@@ -1764,9 +1753,9 @@ def hsvToHex(hue, sat, value = 100){
} }
// Converting float components to int components. // Converting float components to int components.
def r1 = String.format("%02X", (int) (r * 255.0f)) def r1 = String.format("%02X", (int) (r * 255.0f));
def g1 = String.format("%02X", (int) (g * 255.0f)) def g1 = String.format("%02X", (int) (g * 255.0f));
def b1 = String.format("%02X", (int) (b * 255.0f)) def b1 = String.format("%02X", (int) (b * 255.0f));
return "#$r1$g1$b1" return "#$r1$g1$b1"
} }