From 8a66742bb538204b6f89f8573bce6bf83d10f20b Mon Sep 17 00:00:00 2001 From: David Sainte-Claire Date: Tue, 1 Nov 2016 13:30:35 -0700 Subject: [PATCH 01/11] added device watch implementation for ecobee based on the code from lyric --- .../ecobee-thermostat.groovy | 23 ++++++++++++++++++- .../ecobee-connect.src/ecobee-connect.groovy | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy index adf6433..296e381 100644 --- a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy +++ b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy @@ -23,6 +23,7 @@ metadata { capability "Sensor" capability "Refresh" capability "Relative Humidity Measurement" + capability "Health Check" command "generateEvent" command "raiseSetpoint" @@ -38,6 +39,7 @@ metadata { attribute "maxCoolingSetpoint", "number" attribute "minCoolingSetpoint", "number" attribute "deviceTemperatureUnit", "string" + attribute "deviceAlive", "enum", ["true", "false"] } tiles { @@ -120,6 +122,21 @@ 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) +} + +// Device Watch will ping the device to proactively determine if the device has gone offline +// If the device was online the last time we refreshed, trigger another refresh as part of the ping. +def ping() { + def isAlive = device.currentValue("deviceAlive") == "true" ? true : false + if (isAlive) { + refresh() + } +} + // parse events into attributes def parse(String description) { log.debug "Parsing '${description}'" @@ -164,7 +181,11 @@ def generateEvent(Map results) { } else if (name=="humidity") { isChange = isStateChange(device, name, value.toString()) event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"] - } else { + } else if (name == "deviceAlive") { + isChange = isStateChange(device, name, value.toString()) + event['isStateChange'] = isChange + event['displayed'] = false + } else { isChange = isStateChange(device, name, value.toString()) isDisplayed = isChange event << [value: value.toString(), isStateChange: isChange, displayed: isDisplayed] diff --git a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy index d8c2179..9b4c178 100644 --- a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy +++ b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy @@ -842,6 +842,7 @@ private void storeThermostatData(thermostats) { minCoolingSetpoint: (stat.settings.coolRangeLow / 10), maxCoolingSetpoint: (stat.settings.coolRangeHigh / 10), autoMode: stat.settings.autoHeatCoolFeatureEnabled, + deviceAlive: stat.runtime.connected == true ? "true" : "false", auxHeatMode: (stat.settings.hasHeatPump) && (stat.settings.hasForcedAir || stat.settings.hasElectric || stat.settings.hasBoiler), temperature: (stat.runtime.actualTemperature / 10), heatingSetpoint: stat.runtime.desiredHeat / 10, From 3a377ba1479feeb42805738603edc9098a811ee9 Mon Sep 17 00:00:00 2001 From: David Sainte-Claire Date: Tue, 1 Nov 2016 23:04:45 -0700 Subject: [PATCH 02/11] added code formatting based on pull request comments --- .../ecobee-thermostat.src/ecobee-thermostat.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy index 296e381..198fc0a 100644 --- a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy +++ b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy @@ -182,9 +182,9 @@ def generateEvent(Map results) { isChange = isStateChange(device, name, value.toString()) event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"] } else if (name == "deviceAlive") { - isChange = isStateChange(device, name, value.toString()) - event['isStateChange'] = isChange - event['displayed'] = false + isChange = isStateChange(device, name, value.toString()) + event['isStateChange'] = isChange + event['displayed'] = false } else { isChange = isStateChange(device, name, value.toString()) isDisplayed = isChange From 492315b78ace6394abc7e9f4e390b200cf86c804 Mon Sep 17 00:00:00 2001 From: Parijat Das Date: Thu, 22 Sep 2016 17:42:56 +0530 Subject: [PATCH 03/11] Added health check for Leviton DZPA1 Plug-in Appliance Module and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) along with the README.md --- .../zwave-switch-generic.src/.st-ignore | 2 + .../zwave-switch-generic.src/README.md | 39 +++++++++++++++++++ .../zwave-switch-generic.groovy | 15 +++++++ 3 files changed, 56 insertions(+) create mode 100644 devicetypes/smartthings/zwave-switch-generic.src/.st-ignore create mode 100644 devicetypes/smartthings/zwave-switch-generic.src/README.md diff --git a/devicetypes/smartthings/zwave-switch-generic.src/.st-ignore b/devicetypes/smartthings/zwave-switch-generic.src/.st-ignore new file mode 100644 index 0000000..f78b46e --- /dev/null +++ b/devicetypes/smartthings/zwave-switch-generic.src/.st-ignore @@ -0,0 +1,2 @@ +.st-ignore +README.md diff --git a/devicetypes/smartthings/zwave-switch-generic.src/README.md b/devicetypes/smartthings/zwave-switch-generic.src/README.md new file mode 100644 index 0000000..72ba38d --- /dev/null +++ b/devicetypes/smartthings/zwave-switch-generic.src/README.md @@ -0,0 +1,39 @@ +# Z-wave Switch + + + +Works with: + +* [Leviton Appliance Module (DZPA1-1LW)](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-) +* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-) + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) + +## Capabilities + +* **Actuator** - represents that a Device has commands +* **Health Check** - indicates ability to get device health notifications +* **Switch** - can detect state (possible values: on/off) +* **Polling** - represents that poll() can be implemented for the device +* **Refresh** - _refresh()_ command for status updates +* **Sensor** - detects sensor events + +## Device Health + +A Category C5 Leviton Appliance Module (DZPA1-1LW) and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) polled by the hub. +As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed. +Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins. +Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for +the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row, +it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time. + +## Troubleshooting + +If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range. +Pairing needs to be tried again by placing the device closer to the hub. +Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link: +* [Leviton Appliance Module (DZPA1-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-) +* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-) \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy index 798b89d..411440f 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -14,12 +14,15 @@ metadata { definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings") { capability "Actuator" + capability "Health Check" capability "Switch" capability "Polling" capability "Refresh" capability "Sensor" fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch" + fingerprint mfr:"001D", prod:"1A02", model:"0334", deviceJoinName: "Leviton Appliance Module" + fingerprint mfr:"0063", prod:"4F50", model:"3031", deviceJoinName: "GE Plug-in Outdoor Switch" } // simulator metadata @@ -50,6 +53,11 @@ metadata { } } +def updated(){ +// Device-Watch simply pings if no device events received for checkInterval duration of 32min = 2 * 15min + 2min lag time + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + def parse(String description) { def result = null def cmd = zwave.parse(description, [0x20: 1, 0x70: 1]) @@ -126,6 +134,13 @@ def poll() { ]) } +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + def refresh() { delayBetween([ zwave.switchBinaryV1.switchBinaryGet().format(), From 4115d8c65f33494a2cc71b784187639b27fe5a22 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Wed, 2 Nov 2016 11:06:13 -0500 Subject: [PATCH 04/11] Pass unhandled messages up to the cloud Currently these DTHs return null when they parse a message that they don't have specific handling for. This ends up sending the message up to the cloud as an event, which prevented us from potentially parsing that message in the cloud. By instead returning an empty map we can instead send the message up to the cloud to be parsed there. This allows us to add handling in the cloud for new message without requiring and AppEngine deploy for them to work. This resolves: https://smartthings.atlassian.net/browse/DPROT-200 --- .../smartpower-dimming-outlet.groovy | 7 ++-- .../smartpower-outlet.groovy | 10 ++++-- .../smartsense-garage-door-multi.groovy | 2 +- .../smartsense-moisture-sensor.groovy | 2 +- .../smartsense-motion-sensor.groovy | 2 +- .../smartsense-motion-temp-sensor.groovy | 2 +- .../smartsense-motion.groovy | 34 +++++++++++-------- .../smartsense-multi-sensor.groovy | 2 +- .../smartsense-open-closed-sensor.groovy | 2 +- .../smartsense-temp-humidity-sensor.groovy | 2 +- 10 files changed, 38 insertions(+), 27 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 27e9734..a4c240a 100644 --- a/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy +++ b/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy @@ -69,15 +69,17 @@ metadata { def parse(String description) { log.debug "description is $description" + def event = [:] def finalResult = isKnownDescription(description) if (finalResult != "false") { log.info finalResult if (finalResult.type == "update") { log.info "$device updates: ${finalResult.value}" + event = null } else if (finalResult.type == "power") { def powerValue = (finalResult.value as Integer)/10 - sendEvent(name: "power", value: powerValue) + event = createEvent(name: "power", value: powerValue) /* Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10 @@ -87,13 +89,14 @@ def parse(String description) { */ } else { - sendEvent(name: finalResult.type, value: finalResult.value) + event = createEvent(name: finalResult.type, value: finalResult.value) } } else { log.warn "DID NOT PARSE MESSAGE for description : $description" log.debug parseDescriptionAsMap(description) } + return event } // Commands to device diff --git a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy index d96dd77..192f75a 100644 --- a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy +++ b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy @@ -79,6 +79,7 @@ def parse(String description) { log.debug "description is $description" def finalResult = zigbee.getKnownDescription(description) + def event = [:] //TODO: Remove this after getKnownDescription can parse it automatically if (!finalResult && description!="updated") @@ -88,10 +89,11 @@ def parse(String description) { log.info "final result = $finalResult" if (finalResult.type == "update") { log.info "$device updates: ${finalResult.value}" + event = null } else if (finalResult.type == "power") { def powerValue = (finalResult.value as Integer)/10 - sendEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true ) + event = createEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) /* Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10 power level is an integer. The exact power level with correct units needs to be handled in the device type @@ -100,7 +102,7 @@ def parse(String description) { } else { def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' - sendEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true) + event = createEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true) } } else { @@ -109,10 +111,11 @@ def parse(String 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]) + event = createEvent(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]}" + event = null } } else { @@ -120,6 +123,7 @@ def parse(String description) { log.debug "${cluster}" } } + return event } def off() { diff --git a/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy b/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy index 73b0fcf..8454b9c 100644 --- a/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy +++ b/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy @@ -86,7 +86,7 @@ metadata { def parse(String description) { log.debug "parse($description)" - def results = null + def results = [:] if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) { // Ignore this in favor of orientation-based state diff --git a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy index b426cd8..61fefc3 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -102,7 +102,7 @@ def parse(String description) { } log.debug "Parse returned $map" - def result = map ? createEvent(map) : null + def result = map ? createEvent(map) : [:] if (description?.startsWith('enroll request')) { List cmds = enrollResponse() diff --git a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy index de99678..3244898 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -106,7 +106,7 @@ def parse(String description) { } log.debug "Parse returned $map" - def result = map ? createEvent(map) : null + def result = map ? createEvent(map) : [:] if (description?.startsWith('enroll request')) { List cmds = enrollResponse() diff --git a/devicetypes/smartthings/smartsense-motion-temp-sensor.src/smartsense-motion-temp-sensor.groovy b/devicetypes/smartthings/smartsense-motion-temp-sensor.src/smartsense-motion-temp-sensor.groovy index 057ec7e..c3e4e7c 100644 --- a/devicetypes/smartthings/smartsense-motion-temp-sensor.src/smartsense-motion-temp-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-temp-sensor.src/smartsense-motion-temp-sensor.groovy @@ -90,7 +90,7 @@ def parse(String description) { } log.debug "Parse returned $map" - def result = map ? createEvent(map) : null + def result = map ? createEvent(map) : [:] if (description?.startsWith('enroll request')) { List cmds = enrollResponse() diff --git a/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy b/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy index bbb1b7d..5cf3743 100644 --- a/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy +++ b/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy @@ -44,7 +44,7 @@ metadata { } def parse(String description) { - def results + def results = [:] if (isZoneType19(description) || !isSupportedDescription(description)) { results = parseBasicMessage(description) } @@ -57,21 +57,25 @@ def parse(String description) { private Map parseBasicMessage(description) { def name = parseName(description) - def value = parseValue(description) - def linkText = getLinkText(device) - def descriptionText = parseDescriptionText(linkText, value, description) - def handlerName = value - def isStateChange = isStateChange(device, name, value) + if (name != null) { + def value = parseValue(description) + def linkText = getLinkText(device) + def descriptionText = parseDescriptionText(linkText, value, description) + def handlerName = value + def isStateChange = isStateChange(device, name, value) - def results = [ - name: name, - value: value, - linkText: linkText, - descriptionText: descriptionText, - handlerName: handlerName, - isStateChange: isStateChange, - displayed: displayed(description, isStateChange) - ] + def results = [ + name : name, + value : value, + linkText : linkText, + descriptionText: descriptionText, + handlerName : handlerName, + isStateChange : isStateChange, + displayed : displayed(description, isStateChange) + ] + } else { + results = [:] + } log.debug "Parse returned $results.descriptionText" return results } diff --git a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy index bc8092d..2c1c2e3 100644 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -127,7 +127,7 @@ def parse(String description) { map = parseIasMessage(description) } - def result = map ? createEvent(map) : null + def result = map ? createEvent(map) : [:] if (description?.startsWith('enroll request')) { List cmds = enrollResponse() diff --git a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy index 8e697f1..8c779d8 100644 --- a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy +++ b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy @@ -93,7 +93,7 @@ def parse(String description) { } log.debug "Parse returned $map" - def result = map ? createEvent(map) : null + def result = map ? createEvent(map) : [:] if (description?.startsWith('enroll request')) { List cmds = enrollResponse() diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index 0caa602..e0dc7e2 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -84,7 +84,7 @@ def parse(String description) { } log.debug "Parse returned $map" - return map ? createEvent(map) : null + return map ? createEvent(map) : [:] } private Map parseCatchAllMessage(String description) { From 969852602c163f4064736c90ba2635ede50f5994 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Mon, 31 Oct 2016 11:23:48 -0500 Subject: [PATCH 05/11] ETI Clear binding table entries to other devices This adds support for ETI devices which have a firmware bug in which the binding table is not properly cleared on network leave. So the DTH will on configure (and refresh) look at the binding table and remove any entries to not the current hub. This resolves: https://smartthings.atlassian.net/browse/DVCSMP-2175 --- ...zigbee-white-color-temperature-bulb.groovy | 104 ++++++++++++++++-- 1 file changed, 92 insertions(+), 12 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 15a83f6..d7db5bd 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,24 +83,105 @@ def parse(String description) { } } else { - def cluster = zigbee.parse(description) + 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) - 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]) + 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]}" + } } else { - log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" + log.warn "DID NOT PARSE MESSAGE for description : $description" + log.debug "${cluster}" } } - 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() } @@ -130,8 +211,7 @@ def configure() { // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity - refresh() + refresh() + requestBindingTable(0) + ["delay 2000"] } def setColorTemperature(value) { From bd1ace96ded912fa4f34699735f92e016a6a9410 Mon Sep 17 00:00:00 2001 From: Juan Pablo Risso Date: Fri, 4 Nov 2016 16:41:41 -0400 Subject: [PATCH 06/11] DVCSMP-2178 - Add thermostats to Logitech Harmony (#1408) --- .../logitech-harmony-connect.groovy | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy index 3cf64e1..9df77ca 100644 --- a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy +++ b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy @@ -24,6 +24,12 @@ * switches | switch | on, off | on, off * motionSensors | motion | | active, inactive * contactSensors | contact | | open, closed + * thermostat | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint + * | | setCoolingSetpoint(number) | coolingSetpoint, thermostatSetpoint + * | | off, heat, emergencyHeat | thermostatMode — ["emergency heat", "auto", "cool", "off", "heat"] + * | | cool, setThermostatMode | thermostatFanMode — ["auto", "on", "circulate"] + * | | fanOn, fanAuto, fanCirculate| thermostatOperatingState — ["cooling", "heating", "pending heat", + * | | setThermostatFanMode, auto | "fan only", "vent economizer", "pending cool", "idle"] * presenceSensors | presence | | present, 'not present' * temperatureSensors | temperature | | * accelerationSensors | acceleration | | active, inactive @@ -58,6 +64,7 @@ preferences(oauthPage: "deviceAuthorization") { input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors?", multiple: true, required: false + input "thermostats", "capability.thermostat", title: "Which Thermostats?", multiple: true, required: false input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors?", multiple: true, required: false input "temperatureSensors", "capability.temperatureMeasurement", title: "Which Temperature Sensors?", multiple: true, required: false input "accelerationSensors", "capability.accelerationSensor", title: "Which Vibration Sensors?", multiple: true, required: false @@ -936,7 +943,7 @@ def deleteHarmony() { } private getAllDevices() { - ([] + switches + motionSensors + contactSensors + presenceSensors + temperatureSensors + accelerationSensors + waterSensors + lightSensors + humiditySensors + alarms + locks)?.findAll()?.unique { it.id } + ([] + switches + motionSensors + contactSensors + thermostats + presenceSensors + temperatureSensors + accelerationSensors + waterSensors + lightSensors + humiditySensors + alarms + locks)?.findAll()?.unique { it.id } } private deviceItem(device) { From b6790729c6b6a6cbbf8cdee6be3123f089b41239 Mon Sep 17 00:00:00 2001 From: Parijat Das Date: Mon, 7 Nov 2016 18:37:46 +0530 Subject: [PATCH 07/11] Added fingerprint of Leviton Universal Dimmer with health check already implemented --- .../smartthings/zwave-dimmer-switch-generic.src/README.md | 8 +++++--- .../zwave-dimmer-switch-generic.groovy | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md index 5bbc091..f5f4fef 100644 --- a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md @@ -4,7 +4,8 @@ Works with: -* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW)](http://www.leviton.com/OA_HTML/ProductDetail.jsp?partnumber=DZPD3-1LW) +* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW)](https://www.smartthings.com/works-with-smartthings/outlets/leviton-plug-in-lamp-dimmer-module) +* [Leviton Universal Dimmer (DZMX1-LZ)](https://www.smartthings.com/works-with-smartthings/switches-and-dimmers/leviton-universal-dimmer) ## Table of contents @@ -24,7 +25,7 @@ Works with: ## Device Health -A Category C5 Leviton Plug-in Lamp Dimmer Module (DZPA1-1LW) (Z-Wave) polled by the hub. +Leviton Plug-in Lamp Dimmer Module (DZPA1-1LW) (Z-wave) and Leviton Universal Dimmer (DZMX1-LZ) (Z-Wave) are polled by the hub. As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed. Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins. Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for @@ -36,4 +37,5 @@ it is not polled for 5 minutes by the hub. This can delay up the process of bein If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range. Pairing needs to be tried again by placing the device closer to the hub. Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link: -* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) \ No newline at end of file +* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) +* [Leviton Universal Dimmer (DZMX1-LZ) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy index bd1668b..43a65b8 100644 --- a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy @@ -23,6 +23,7 @@ metadata { fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer" fingerprint mfr:"001D", prod:"1902", deviceJoinName: "Z-Wave Dimmer" + fingerprint mfr:"001D", prod:"1B03", model:"0334", deviceJoinName: "Leviton Universal Dimmer" } simulator { From c0bb0554d89b60384227bcc4ffbcbd6394410927 Mon Sep 17 00:00:00 2001 From: Parijat Das Date: Mon, 7 Nov 2016 19:02:25 +0530 Subject: [PATCH 08/11] Added fingerprint of Leviton Outlet and Leviton Switch with health check already implemented and modified readme file accordingly --- .../smartthings/zwave-switch-generic.src/README.md | 14 +++++++++----- .../zwave-switch-generic.groovy | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/devicetypes/smartthings/zwave-switch-generic.src/README.md b/devicetypes/smartthings/zwave-switch-generic.src/README.md index 72ba38d..765bcd1 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/README.md +++ b/devicetypes/smartthings/zwave-switch-generic.src/README.md @@ -4,8 +4,10 @@ Works with: -* [Leviton Appliance Module (DZPA1-1LW)](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-) -* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-) +* [Leviton Appliance Module (DZPA1-1LW)](https://www.smartthings.com/works-with-smartthings/outlets/leviton-appliance-module) +* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)](https://www.smartthings.com/works-with-smartthings/outlets/ge-plug-in-outdoor-smart-switch) +* [Leviton Outlet (DZR15-1LZ)](https://www.smartthings.com/works-with-smartthings/outlets/leviton-outlet) +* [Leviton Switch (DZS15-1LZ)](https://www.smartthings.com/works-with-smartthings/switches-and-dimmers/leviton-switch) ## Table of contents @@ -23,7 +25,7 @@ Works with: ## Device Health -A Category C5 Leviton Appliance Module (DZPA1-1LW) and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) polled by the hub. +Leviton Appliance Module (DZPA1-1LW), GE Plug-In Outdoor Smart Switch (GE 12720), Leviton Outlet (DZR15-1LZ) and Leviton Switch (DZS15-1LZ) (Z-Wave) are polled by the hub. As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed. Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins. Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for @@ -35,5 +37,7 @@ it is not polled for 5 minutes by the hub. This can delay up the process of bein If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range. Pairing needs to be tried again by placing the device closer to the hub. Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link: -* [Leviton Appliance Module (DZPA1-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-) -* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-) \ No newline at end of file +* [Leviton Appliance Module (DZPA1-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) +* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-) +* [Leviton Outlet (DZR15-1LZ) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) +* [Leviton Switch (DZS15-1LZ) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices) \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy index 411440f..01ce695 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -23,6 +23,8 @@ metadata { fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch" fingerprint mfr:"001D", prod:"1A02", model:"0334", deviceJoinName: "Leviton Appliance Module" fingerprint mfr:"0063", prod:"4F50", model:"3031", deviceJoinName: "GE Plug-in Outdoor Switch" + fingerprint mfr:"001D", prod:"1D04", model:"0334", deviceJoinName: "Leviton Outlet" + fingerprint mfr:"001D", prod:"1C02", model:"0334", deviceJoinName: "Leviton Switch" } // simulator metadata From c1d520a578365bd351f7e9d4158a1d00832e4706 Mon Sep 17 00:00:00 2001 From: "sushant.k1" Date: Mon, 7 Nov 2016 18:13:54 +0530 Subject: [PATCH 09/11] Added Health Check Implementation for following Osram RT5/6 Tunable White --- .../README.md | 13 ++++++++----- .../zigbee-white-color-temperature-bulb.groovy | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/README.md b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/README.md index 3bd9229..779d119 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/README.md +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/README.md @@ -1,10 +1,11 @@ -# OSRAM Lightify Tunable 60 White +# ZigBee White Color Temperature Bulb Works with: * [OSRAM Lightify Tunable 60 White](http://www.osram.com/osram_com/tools-and-services/tools/lightify---smart-connected-light/lightify-for-home---what-is-light-to-you/lightify-products/lightify-classic-a60-tunable-white/index.jsp) +* [OSRAM LIGHTIFY RT5/6 Tunable White](https://www.smartthings.com/works-with-smartthings/light-bulbs/osram-lightify-rt56-tunable-white) ## Table of contents @@ -24,14 +25,16 @@ Works with: ## Device Health -A Category C1 OSRAM Lightify Tunable 60 White with maxReportTime of 5 mins. -Check-in interval is double the value of maxReportTime. +Zigbee Bulb with maxReportTime of 5 mins. +Check-in interval is double the value of maxReportTime. This gives the device twice the amount of time to respond before it is marked as offline. -Check-in interval = 12 mins +Enrolls with default periodic reporting until newer 5 min interval is confirmed +It then enrolls the device with updated checkInterval i.e. 12 mins ## Troubleshooting If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range. Pairing needs to be tried again by placing the device closer to the hub. Other troubleshooting tips are listed as follows: -* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/204576454-OSRAM-LIGHTIFY-Tunable-White-60-Bulb) +* [OSRAM Lightify Tunable 60 White Troubleshooting](https://support.smartthings.com/hc/en-us/articles/204576454-OSRAM-LIGHTIFY-Tunable-White-60-Bulb) +* [OSRAM LIGHTIFY RT5/6 Tunable White Troubleshooting](https://support.smartthings.com/hc/en-us/articles/214191863-How-to-connect-OSRAM-LIGHTIFY-Bulbs) \ No newline at end of file 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 15a83f6..fb06954 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 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: "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: "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 8ca20ce87e9dc5fb94a21392c70cef2ce305abf2 Mon Sep 17 00:00:00 2001 From: "sushant.k1" Date: Sun, 6 Nov 2016 20:18:03 +0530 Subject: [PATCH 10/11] Added Health Check Implementation for following WeMo LED Bulb --- devicetypes/smartthings/zigbee-dimmer.src/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/devicetypes/smartthings/zigbee-dimmer.src/README.md b/devicetypes/smartthings/zigbee-dimmer.src/README.md index 35997a5..61f3ed0 100644 --- a/devicetypes/smartthings/zigbee-dimmer.src/README.md +++ b/devicetypes/smartthings/zigbee-dimmer.src/README.md @@ -1,10 +1,11 @@ -# OSRAM Lightify LED On/Off/Dim +# Zigbee Dimmer Works with: * [OSRAM Lightify LED On/Off/Dim](https://shop.smartthings.com/#!/products/osram-led-smart-bulb-on-off-dim) +* [WeMo LED Bulb](https://support.smartthings.com/hc/en-us/articles/204259040-Belkin-WeMo-LED-Bulb-F7C033-) ## Table of contents @@ -23,14 +24,16 @@ Works with: ## Device Health -A Category C1 Zigbee dimmer with maxReportTime of 5 mins. -Check-in interval is double the value of maxReportTime. +A Zigbee dimmer with maxReportTime of 5 mins. +Check-in interval is double the value of maxReportTime. This gives the device twice the amount of time to respond before it is marked as offline. -Check-in interval = 12 mins +Enrolls with default periodic reporting until newer 5 min interval is confirmed +It then enrolls the device with updated checkInterval i.e. 12 mins ## Troubleshooting If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range. Pairing needs to be tried again by placing the device closer to the hub. Other troubleshooting tips are listed as follows: -* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/207191763-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-On-Off-Dim) +* [OSRAM Lightify LED On/Off/Dim Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/207191763-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-On-Off-Dim) +* [WeMo LED Bulb Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/204259040-Belkin-WeMo-LED-Bulb-F7C033-) From af8590ab01fc89f410a6694d388911df58ff41fa Mon Sep 17 00:00:00 2001 From: Tom Manley Date: Tue, 8 Nov 2016 14:48:42 -0600 Subject: [PATCH 11/11] GE Link: fixed problem creating level events The bug causing level events not to be created happens when the setLevel command runs in the cloud but the Device Type Handler is running locally in the hub. Since state is not synced from the cloud to the hub the `state.trigger` value was never set to `"setLevel"` on the hub which means no level events would be created. The change is to not be reliant on state. Instead we just don't create level events if the level is 0 since there is no legitimate way for the level to be 0. https://smartthings.atlassian.net/browse/DVCSMP-2219 --- devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy b/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy index 3e62197..d806b69 100644 --- a/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy +++ b/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy @@ -87,7 +87,7 @@ metadata { def parse(String description) { def resultMap = zigbee.getEvent(description) if (resultMap) { - if ((resultMap.name == "level" && state.trigger == "setLevel") || resultMap.name != "level") { //doing this to account for weird level reporting bug with GE Link Bulbs + if (resultMap.name != "level" || resultMap.value != 0) { // Ignore level reports of 0 sent when bulb turns off sendEvent(resultMap) } } @@ -188,12 +188,10 @@ def updated() { } def on() { - state.trigger = "on/off" zigbee.on() } def off() { - state.trigger = "on/off" zigbee.off() } @@ -206,7 +204,6 @@ def refresh() { } def setLevel(value) { - state.trigger = "setLevel" def cmd def delayForRefresh = 500 if (dimRate && (state?.rate != null)) {