From cf9d123aa0afda9375f3d640ac289d3d2a9907c8 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Mon, 14 Nov 2016 11:06:09 -0600 Subject: [PATCH 1/5] Handle all messages in smartpower dimming outlet Previously the implementation of isKnownDescription didn't cover all possible messages that could be parsed and this caused null pointer exceptions with certain messages. This now handles all the possibilities. This resolves: https://smartthings.atlassian.net/browse/DVCSMP-2227 --- .../smartpower-dimming-outlet.groovy | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy b/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy index a4c240a..9539376 100644 --- a/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy +++ b/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy @@ -71,7 +71,7 @@ def parse(String description) { def event = [:] def finalResult = isKnownDescription(description) - if (finalResult != "false") { + if (finalResult) { log.info finalResult if (finalResult.type == "update") { log.info "$device updates: ${finalResult.value}" @@ -212,13 +212,16 @@ def isKnownDescription(description) { else if (descMap.cluster == "0B04" || descMap.clusterId == "0B04"){ isDescriptionPower(descMap) } + else { + return [:] + } } else if(description?.startsWith("on/off:")) { def switchValue = description?.endsWith("1") ? "on" : "off" return [type: "switch", value : switchValue] } else { - return "false" + return [:] } } @@ -252,7 +255,7 @@ def isDescriptionOnOff(descMap) { return [type: "switch", value : switchValue] } else { - return "false" + return [:] } } @@ -279,10 +282,9 @@ def isDescriptionLevel(descMap) { if (dimmerValue != -1){ return [type: "level", value : dimmerValue] - } else { - return "false" + return [:] } } @@ -304,7 +306,7 @@ def isDescriptionPower(descMap) { return [type: "power", value : powerValue] } else { - return "false" + return [:] } } From 3f93de247b3c0ea05ed97fcfffe15d440de1dea9 Mon Sep 17 00:00:00 2001 From: jackchi Date: Mon, 14 Nov 2016 12:05:10 -0800 Subject: [PATCH 2/5] [CHF-442][DVCSMP-2179] Hotfix for EcoBee thermostat & Osram RT5/6 Tunable White naming --- .../smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy | 2 +- .../zigbee-white-color-temperature-bulb.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy index 198fc0a..0f281a2 100644 --- a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy +++ b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy @@ -125,7 +125,7 @@ metadata { void installed() { // The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline // Using 12 minutes because in testing, device health team found that there could be "jitter" - sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud", hubHardwareId: device.hub.hardwareID], displayed: false) + sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud"], displayed: false) } // Device Watch will ping the device to proactively determine if the device has gone offline diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 123a203..d35ec61 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -33,7 +33,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04", outClusters: "0019" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY RT5/6 Tunable White" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM LIGHTIFY Classic B40 Tunable White" From 65bb10d6d6424660874707a61be8c1d9a05ff8f1 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Mon, 14 Nov 2016 14:34:53 -0600 Subject: [PATCH 3/5] Do not delete all binding table entries There was a bug when comparing the destination address for binding table entries that would cause all binding table entries to be deleted. This fixes that. This is a fix for: https://smartthings.atlassian.net/browse/DVCSMP-2175 --- .../zigbee-white-color-temperature-bulb.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 123a203..e8310a1 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -88,7 +88,7 @@ def parse(String description) { List cmds = [] bindingTable.table_entries.inject(cmds) { acc, entry -> // The binding entry is not for our hub and should be deleted - if (entry["dstAddr"] != zigbeeEui) { + if (entry["dstAddr"] != zigbee.zigbeeEui) { acc.addAll(removeBinding(entry.clusterId, entry.srcAddr, entry.srcEndpoint, entry.dstAddr, entry.dstEndpoint)) } acc From 3034cc8bcb334aac0de6d97a9130c75a78a2d846 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Tue, 15 Nov 2016 13:23:57 -0600 Subject: [PATCH 4/5] Revert "Do not delete all binding table entries" This reverts commit 65bb10d6d6424660874707a61be8c1d9a05ff8f1. --- .../zigbee-white-color-temperature-bulb.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 1a7afb9..d35ec61 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -88,7 +88,7 @@ def parse(String description) { List cmds = [] bindingTable.table_entries.inject(cmds) { acc, entry -> // The binding entry is not for our hub and should be deleted - if (entry["dstAddr"] != zigbee.zigbeeEui) { + if (entry["dstAddr"] != zigbeeEui) { acc.addAll(removeBinding(entry.clusterId, entry.srcAddr, entry.srcEndpoint, entry.dstAddr, entry.dstEndpoint)) } acc From a84ffdde918a95beeaf14b1f65d802a5a0860f97 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Tue, 15 Nov 2016 13:24:23 -0600 Subject: [PATCH 5/5] Revert "ETI Clear binding table entries to other devices" This reverts commit 969852602c163f4064736c90ba2635ede50f5994. --- ...zigbee-white-color-temperature-bulb.groovy | 104 ++---------------- 1 file changed, 12 insertions(+), 92 deletions(-) diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index d35ec61..e6c6c7e 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -83,105 +83,24 @@ def parse(String description) { } } else { - Map bindingTable = parseBindingTableResponse(description) - if (bindingTable) { - List cmds = [] - bindingTable.table_entries.inject(cmds) { acc, entry -> - // The binding entry is not for our hub and should be deleted - if (entry["dstAddr"] != zigbeeEui) { - acc.addAll(removeBinding(entry.clusterId, entry.srcAddr, entry.srcEndpoint, entry.dstAddr, entry.dstEndpoint)) - } - acc - } - // There are more entries that we haven't examined yet - if (bindingTable.numTableEntries > bindingTable.startIndex + bindingTable.numEntriesReturned) { - def startPos - if (cmds) { - log.warn "Removing binding entries for other devices: $cmds" - // Since we are removing some entries, we should start in the same spot as we just read since values - // will fill in the newly vacated spots - startPos = bindingTable.startIndex - } else { - // Since we aren't removing anything we move forward to the next set of table entries - startPos = bindingTable.startIndex + bindingTable.numEntriesReturned - } - cmds.addAll(requestBindingTable(startPos)) - } - sendHubCommand(cmds.collect { it -> - new physicalgraph.device.HubAction(it) - }, 2000) - } else { - def cluster = zigbee.parse(description) + def cluster = zigbee.parse(description) - if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) { - if (cluster.data[0] == 0x00) { - log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster - sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - } - else { - log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" - } + if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) { + if (cluster.data[0] == 0x00) { + log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else { - log.warn "DID NOT PARSE MESSAGE for description : $description" - log.debug "${cluster}" + log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" } } + else { + log.warn "DID NOT PARSE MESSAGE for description : $description" + log.debug "${cluster}" + } } } -def parseBindingTableResponse(description) { - Map descMap = zigbee.parseDescriptionAsMap(description) - if (descMap["clusterInt"] == 0x8033) { - def header_field_lengths = ["transactionSeqNo": 1, "status": 1, "numTableEntries": 1, "startIndex": 1, "numEntriesReturned": 1] - def field_values = [:] - def data = descMap["data"] - header_field_lengths.each { k, v -> - field_values[k] = Integer.parseInt(data.take(v).join(""), 16); - data = data.drop(v); - } - - List table = [] - if (field_values.numEntriesReturned) { - def table_entry_lengths = ["srcAddr": 8, "srcEndpoint": 1, "clusterId": 2, "dstAddrMode": 1] - for (def i : 0..(field_values.numEntriesReturned - 1)) { - def entryMap = [:] - table_entry_lengths.each { k, v -> - def val = data.take(v).reverse().join("") - entryMap[k] = val.length() < 8 ? Integer.parseInt(val, 16) : val - data = data.drop(v) - } - - switch (entryMap.dstAddrMode) { - case 0x01: - entryMap["dstAddr"] = data.take(2).reverse().join("") - data = data.drop(2) - break - case 0x03: - entryMap["dstAddr"] = data.take(8).reverse().join("") - data = data.drop(8) - entryMap["dstEndpoint"] = Integer.parseInt(data.take(1).join(""), 16) - data = data.drop(1) - break - } - table << entryMap - } - } - field_values["table_entries"] = table - return field_values - } - return [:] -} - -def requestBindingTable(startPos=0) { - return ["zdo mgmt-bind 0x${zigbee.deviceNetworkId} $startPos"] -} - -def removeBinding(cluster, srcAddr, srcEndpoint, destAddr, destEndpoint) { - return ["zdo unbind unicast 0x${zigbee.deviceNetworkId} {${srcAddr}} $srcEndpoint $cluster {${destAddr}} $destEndpoint"] -} - - def off() { zigbee.off() } @@ -211,7 +130,8 @@ def configure() { // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - refresh() + requestBindingTable(0) + ["delay 2000"] + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity + refresh() } def setColorTemperature(value) {