From 6a1a2b0ed9607d2c964480e2924c82b10ec9075d Mon Sep 17 00:00:00 2001 From: ShilpaMathew Date: Tue, 27 Sep 2016 14:49:25 -0700 Subject: [PATCH 1/9] Add fingerprint for Leviton 73A00-3ZB --- devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 7e243f4..2e2e90d 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -21,6 +21,7 @@ metadata { 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: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Wireless Load Control Module-30amp" } // simulator metadata From 72b2016b7dc392b03178ebbd2dcfdfd391ee16aa Mon Sep 17 00:00:00 2001 From: "piyush.c" Date: Mon, 24 Oct 2016 14:26:22 +0530 Subject: [PATCH 2/9] CHF-435 Implementation of Health Check for Zigbee Dimmer (GE Plug-In/In-Wall Smart Dimmer) --- .../zigbee-dimmer-power.src/.st-ignore | 2 + .../zigbee-dimmer-power.src/README.md | 41 +++++++++++++++++++ .../zigbee-dimmer-power.groovy | 30 ++++++++++++-- 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 devicetypes/smartthings/zigbee-dimmer-power.src/.st-ignore create mode 100644 devicetypes/smartthings/zigbee-dimmer-power.src/README.md diff --git a/devicetypes/smartthings/zigbee-dimmer-power.src/.st-ignore b/devicetypes/smartthings/zigbee-dimmer-power.src/.st-ignore new file mode 100644 index 0000000..f78b46e --- /dev/null +++ b/devicetypes/smartthings/zigbee-dimmer-power.src/.st-ignore @@ -0,0 +1,2 @@ +.st-ignore +README.md diff --git a/devicetypes/smartthings/zigbee-dimmer-power.src/README.md b/devicetypes/smartthings/zigbee-dimmer-power.src/README.md new file mode 100644 index 0000000..81ab641 --- /dev/null +++ b/devicetypes/smartthings/zigbee-dimmer-power.src/README.md @@ -0,0 +1,41 @@ +# GE Plug-In/In-Wall Smart Dimmer (ZigBee) + + + +Works with: + +* [GE In-Wall Smart Dimmer (ZigBee)](https://shop.smartthings.com/#!/products/ge-in-wall-smart-dimmer-switch) +* [GE Plug-In Smart Dimmer (ZigBee)](https://www.smartthings.com/works-with-smartthings/ge/ge-plug-in-smart-dimmer-zigbee) + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) +* [Troubleshooting](#Troubleshooting) + +## Capabilities + +* **Actuator** - represents that a Device has commands +* **Configuration** - _configure()_ command called when device is installed or device preferences updated +* **Refresh** - _refresh()_ command for status updates +* **Power Meter** - ability to check the power meter(energy consumption) of device +* **Sensor** - represents the device sensor capability +* **Switch** - can detect state (possible values: on/off) +* **Switch Level** - represents current light level, usually 0-100 in percent +* **Health Check** - indicates ability to get device health notifications + +## Device Health + +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. +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. +Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link: +* [GE Z-Wave In-Wall Smart Dimmer (GE 45857) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204988564-GE-In-Wall-Smart-Dimmer-45857GE-ZigBee-) +* [GE Zigbee Plug-in Smart Dimmer (GE 45852) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205239280-GE-Plug-In-Smart-Dimmer-45852GE-ZigBee-) diff --git a/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy b/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy index 6ffdf22..c6f4e78 100644 --- a/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy +++ b/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy @@ -21,6 +21,7 @@ metadata { capability "Sensor" capability "Switch" capability "Switch Level" + capability "Health Check" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702" @@ -70,8 +71,20 @@ def parse(String description) { } } else { - log.warn "DID NOT PARSE MESSAGE for description : $description" - log.debug zigbee.parseDescriptionAsMap(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]}" + } + } + else { + log.warn "DID NOT PARSE MESSAGE for description : $description" + log.debug zigbee.parseDescriptionAsMap(description) + } } } @@ -87,11 +100,22 @@ def setLevel(value) { zigbee.setLevel(value) } +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return zigbee.onOffRefresh() +} + def refresh() { - zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig() } def configure() { log.debug "Configuring Reporting and Bindings." + + // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) refresh() } From 47522facc710e74b0a1e8c2c05f66d349e2ca5e0 Mon Sep 17 00:00:00 2001 From: jackchi Date: Tue, 25 Oct 2016 16:01:17 -0700 Subject: [PATCH 3/9] [CHF-429] Device Health enrollment refactored into updated() from configure() --- .../cree-bulb.src/cree-bulb.groovy | 23 ++++++-- .../smartpower-outlet.groovy | 15 ++++- .../smartsense-moisture-sensor.groovy | 13 ++++- .../smartsense-motion-sensor.groovy | 13 ++++- .../smartsense-multi-sensor.groovy | 55 +++++++++++-------- .../smartsense-open-closed-sensor.groovy | 14 ++++- .../smartsense-temp-humidity-sensor.groovy | 13 ++++- .../zigbee-dimmer.src/zigbee-dimmer.groovy | 14 ++++- .../zigbee-rgbw-bulb.groovy | 17 +++++- ...zigbee-white-color-temperature-bulb.groovy | 16 +++++- 10 files changed, 150 insertions(+), 43 deletions(-) diff --git a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy index 69d26f7..4fb4599 100644 --- a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy +++ b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy @@ -59,6 +59,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -96,6 +105,14 @@ def refresh() { zigbee.onOffRefresh() + zigbee.levelRefresh() } +def configureHealthCheck() { + log.debug "configureHealthCheck" + unschedule("healthPoll") + runEvery5Minutes("healthPoll") + // Device-Watch allows 2 check-in misses from device + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} + def healthPoll() { log.debug "healthPoll()" def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() @@ -103,9 +120,5 @@ def healthPoll() { } def configure() { - unschedule() - runEvery5Minutes("healthPoll") - // Device-Watch allows 2 check-in misses from device - sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - zigbee.onOffRefresh() + zigbee.levelRefresh() + refresh() } diff --git a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy index d96dd77..ef81fc5 100644 --- a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy +++ b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy @@ -74,6 +74,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -140,10 +149,14 @@ def refresh() { zigbee.onOffRefresh() + zigbee.electricMeasurementPowerRefresh() } -def configure() { +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) +} + +def configure() { + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity refresh() + zigbee.onOffConfig(0, 300) + powerConfig() 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 f214cbd..8ff9180 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -84,6 +84,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + def parse(String description) { log.debug "description: $description" @@ -303,11 +312,13 @@ def refresh() { return refreshCmds + enrollResponse() } -def configure() { +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} +def configure() { // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity // battery minReport 30 seconds, maxReportTime 6 hrs by default return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config 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 d02d41d..a9f0f52 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -88,6 +88,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + def parse(String description) { log.debug "description: $description" @@ -318,11 +327,13 @@ def refresh() { return refreshCmds + enrollResponse() } -def configure() { +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} +def configure() { // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity // battery minReport 30 seconds, maxReportTime 6 hrs by default return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config 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 94104b9..b1c333a 100644 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -115,6 +115,34 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "updated called" + log.info "garage value : $garageSensor" + if (garageSensor == "Yes") { + def descriptionText = "Updating device to garage sensor" + if (device.latestValue("status") == "open") { + sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) + } + else if (device.latestValue("status") == "closed") { + sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) + } + } + else { + def descriptionText = "Updating device to open/close sensor" + if (device.latestValue("status") == "garage-open") { + sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) + } + else if (device.latestValue("status") == "garage-closed") { + sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) + } + } + configureHealthCheck() +} + def parse(String description) { Map map = [:] if (description?.startsWith('catchall:')) { @@ -246,29 +274,6 @@ private Map parseIasMessage(String description) { return resultMap } -def updated() { - log.debug "updated called" - log.info "garage value : $garageSensor" - if (garageSensor == "Yes") { - def descriptionText = "Updating device to garage sensor" - if (device.latestValue("status") == "open") { - sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) - } - else if (device.latestValue("status") == "closed") { - sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) - } - } - else { - def descriptionText = "Updating device to open/close sensor" - if (device.latestValue("status") == "garage-open") { - sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) - } - else if (device.latestValue("status") == "garage-closed") { - sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) - } - } -} - def getTemperature(value) { def celsius = Integer.parseInt(value, 16).shortValue() / 100 if(getTemperatureScale() == "C"){ @@ -411,11 +416,13 @@ def refresh() { return refreshCmds + enrollResponse() } -def configure() { +def configureHealthCheck(){ // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} +def configure() { log.debug "Configuring Reporting" // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity 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 7d411f5..483f31a 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 @@ -75,6 +75,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + def parse(String description) { log.debug "description: $description" @@ -265,11 +274,12 @@ def refresh() { return refreshCmds + enrollResponse() } -def configure() { +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - +} +def configure() { log.debug "Configuring Reporting, IAS CIE, and Bindings." // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity 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 638b9d4..07557d5 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 @@ -69,6 +69,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + def parse(String description) { log.debug "description: $description" @@ -269,11 +278,13 @@ def refresh() zigbee.readAttribute(0x0001, 0x0020) } -def configure() { +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} +def configure() { log.debug "Configuring Reporting and Bindings." def humidityConfigCmds = [ "zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500", diff --git a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy index ef17d94..280caaf 100644 --- a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy @@ -48,6 +48,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -100,12 +109,13 @@ def refresh() { zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() } -def configure() { - log.debug "Configuring Reporting and Bindings." +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) +} +def configure() { // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() } diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index aa4defb..9e13b39 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -70,6 +70,16 @@ metadata { } } + +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + //Globals private getATTRIBUTE_HUE() { 0x0000 } private getATTRIBUTE_SATURATION() { 0x0001 } @@ -138,16 +148,17 @@ def ping() { } def refresh() { + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) } -def configure() { - log.debug "Configuring Reporting and Bindings." +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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 +def configure() { refresh() } 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..92779ce 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 @@ -69,6 +69,15 @@ metadata { } } +def installed() { + log.debug "${device} installed" +} + +def updated() { + log.debug "${device} updated" + configureHealthCheck() +} + // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -121,16 +130,17 @@ def ping() { } def refresh() { + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() } -def configure() { - log.debug "Configuring Reporting and Bindings." +def configureHealthCheck() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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 +def configure() { refresh() } From c9d1b168f705a9868cd14fa41ad557df2b1da40e Mon Sep 17 00:00:00 2001 From: Kevin Shuk Date: Fri, 21 Oct 2016 16:22:30 -0700 Subject: [PATCH 4/9] DVCSMP-2155 ZigBee switch power DH health check * Add capability Health Check * specify 5 minute reporting interval to `zigbee.onOffConfig()` * set the checkInterval attribute in `configure()` (as it sets the reporting interval) * implements `ping()` by sending the `zigbee.onOffRefresh()` command For the Google Home project, supports specifically * GE/Jasco ZigBee Plug-in Smart Switch (45853) * GE/Jasco ZigBee In-Wall Smart Switch (45856) The DH itself supports those, plus the Smartthings Outlet V4 * `fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019"` and two other generic fingerprints: * `fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04"` * `fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"` --- .../zigbee-switch-power.groovy | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy index bb5f754..d86de90 100644 --- a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy +++ b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy @@ -20,6 +20,7 @@ metadata { capability "Power Meter" capability "Sensor" capability "Switch" + capability "Health Check" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702" @@ -77,10 +78,26 @@ def on() { } def refresh() { - zigbee.onOffRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig() + Integer reportIntervalMinutes = 5 + zigbee.onOffRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig(0,reportIntervalMinutes * 60) + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig() } def configure() { - log.debug "Configuring Reporting and Bindings." - refresh() + log.debug "in configure()" + configureHealthCheck() +} + +def configureHealthCheck() { + Integer hcIntervalMinutes = 12 + refresh() + sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} + +def updated() { + log.debug "in updated()" + configureHealthCheck() +} + +def ping() { + return zigbee.onOffRefresh() } From 3343273d402b50addcf83a67997d38e4de9afbc3 Mon Sep 17 00:00:00 2001 From: Jack Chi Date: Mon, 31 Oct 2016 11:56:02 -0700 Subject: [PATCH 5/9] Revert "[CHF-429] Device Health enrollment refactored into updated()" --- .../cree-bulb.src/cree-bulb.groovy | 23 ++------ .../smartpower-outlet.groovy | 15 +---- .../smartsense-moisture-sensor.groovy | 13 +---- .../smartsense-motion-sensor.groovy | 13 +---- .../smartsense-multi-sensor.groovy | 55 ++++++++----------- .../smartsense-open-closed-sensor.groovy | 14 +---- .../smartsense-temp-humidity-sensor.groovy | 13 +---- .../zigbee-dimmer.src/zigbee-dimmer.groovy | 14 +---- .../zigbee-rgbw-bulb.groovy | 17 +----- ...zigbee-white-color-temperature-bulb.groovy | 16 +----- 10 files changed, 43 insertions(+), 150 deletions(-) diff --git a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy index 4fb4599..69d26f7 100644 --- a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy +++ b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy @@ -59,15 +59,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -105,14 +96,6 @@ def refresh() { zigbee.onOffRefresh() + zigbee.levelRefresh() } -def configureHealthCheck() { - log.debug "configureHealthCheck" - unschedule("healthPoll") - runEvery5Minutes("healthPoll") - // Device-Watch allows 2 check-in misses from device - sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} - def healthPoll() { log.debug "healthPoll()" def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() @@ -120,5 +103,9 @@ def healthPoll() { } def configure() { - refresh() + unschedule() + runEvery5Minutes("healthPoll") + // Device-Watch allows 2 check-in misses from device + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + zigbee.onOffRefresh() + zigbee.levelRefresh() } diff --git a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy index ef81fc5..d96dd77 100644 --- a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy +++ b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy @@ -74,15 +74,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -149,14 +140,10 @@ def refresh() { zigbee.onOffRefresh() + zigbee.electricMeasurementPowerRefresh() } -def configureHealthCheck() { +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) -} - -def configure() { - // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity refresh() + zigbee.onOffConfig(0, 300) + powerConfig() 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 8ff9180..f214cbd 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -84,15 +84,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - def parse(String description) { log.debug "description: $description" @@ -312,13 +303,11 @@ def refresh() { return refreshCmds + enrollResponse() } -def configureHealthCheck() { +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} -def configure() { // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity // battery minReport 30 seconds, maxReportTime 6 hrs by default return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config 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 a9f0f52..d02d41d 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -88,15 +88,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - def parse(String description) { log.debug "description: $description" @@ -327,13 +318,11 @@ def refresh() { return refreshCmds + enrollResponse() } -def configureHealthCheck() { +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} -def configure() { // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity // battery minReport 30 seconds, maxReportTime 6 hrs by default return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config 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 b1c333a..94104b9 100644 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -115,34 +115,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "updated called" - log.info "garage value : $garageSensor" - if (garageSensor == "Yes") { - def descriptionText = "Updating device to garage sensor" - if (device.latestValue("status") == "open") { - sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) - } - else if (device.latestValue("status") == "closed") { - sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) - } - } - else { - def descriptionText = "Updating device to open/close sensor" - if (device.latestValue("status") == "garage-open") { - sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) - } - else if (device.latestValue("status") == "garage-closed") { - sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) - } - } - configureHealthCheck() -} - def parse(String description) { Map map = [:] if (description?.startsWith('catchall:')) { @@ -274,6 +246,29 @@ private Map parseIasMessage(String description) { return resultMap } +def updated() { + log.debug "updated called" + log.info "garage value : $garageSensor" + if (garageSensor == "Yes") { + def descriptionText = "Updating device to garage sensor" + if (device.latestValue("status") == "open") { + sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) + } + else if (device.latestValue("status") == "closed") { + sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) + } + } + else { + def descriptionText = "Updating device to open/close sensor" + if (device.latestValue("status") == "garage-open") { + sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) + } + else if (device.latestValue("status") == "garage-closed") { + sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) + } + } +} + def getTemperature(value) { def celsius = Integer.parseInt(value, 16).shortValue() / 100 if(getTemperatureScale() == "C"){ @@ -416,13 +411,11 @@ def refresh() { return refreshCmds + enrollResponse() } -def configureHealthCheck(){ +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} -def configure() { log.debug "Configuring Reporting" // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity 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 483f31a..7d411f5 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 @@ -75,15 +75,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - def parse(String description) { log.debug "description: $description" @@ -274,12 +265,11 @@ def refresh() { return refreshCmds + enrollResponse() } -def configureHealthCheck() { +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} -def configure() { + log.debug "Configuring Reporting, IAS CIE, and Bindings." // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity 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 b7873c7..98af1a4 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 @@ -69,15 +69,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - def parse(String description) { log.debug "description: $description" @@ -277,13 +268,11 @@ def refresh() zigbee.readAttribute(0x0001, 0x0020) } -def configureHealthCheck() { +def configure() { // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -} -def configure() { log.debug "Configuring Reporting and Bindings." def humidityConfigCmds = [ "zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500", diff --git a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy index 280caaf..ef17d94 100644 --- a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy @@ -48,15 +48,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -109,13 +100,12 @@ def refresh() { zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() } -def configureHealthCheck() { +def configure() { + log.debug "Configuring Reporting and Bindings." // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) -} -def configure() { // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() } diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 9e13b39..aa4defb 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -70,16 +70,6 @@ metadata { } } - -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - //Globals private getATTRIBUTE_HUE() { 0x0000 } private getATTRIBUTE_SATURATION() { 0x0001 } @@ -148,17 +138,16 @@ def ping() { } def refresh() { - // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) } -def configureHealthCheck() { +def configure() { + log.debug "Configuring Reporting and Bindings." // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) -} -def configure() { + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity refresh() } 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 92779ce..15a83f6 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 @@ -69,15 +69,6 @@ metadata { } } -def installed() { - log.debug "${device} installed" -} - -def updated() { - log.debug "${device} updated" - configureHealthCheck() -} - // Parse incoming device messages to generate events def parse(String description) { log.debug "description is $description" @@ -130,17 +121,16 @@ def ping() { } def refresh() { - // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() } -def configureHealthCheck() { +def configure() { + log.debug "Configuring Reporting and Bindings." // Device-Watch allows 3 check-in misses from device (plus 1 min lag time) // 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]) -} -def configure() { + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity refresh() } From 44088d626a9747f108fa04e2d64023c20145c237 Mon Sep 17 00:00:00 2001 From: Lars Finander Date: Mon, 31 Oct 2016 13:23:42 -0600 Subject: [PATCH 6/9] DVCSMP-2108 LIFX: Add devicewatch support -Fixed a color state issue introduced by previous PR -Fixed original LIFX setup state bug --- .../lifx-connect.src/lifx-connect.groovy | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy index 41f20ef..7a4afe7 100644 --- a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy +++ b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy @@ -381,38 +381,28 @@ def updateDevices() { selectors.add("${device.id}") if (!childDevice) { // log.info("Adding device ${device.id}: ${device.product}") - def data = [ - label: device.label, - level: Math.round((device.brightness ?: 1) * 100), - switch: device.power, - colorTemperature: device.color.kelvin - ] if (device.product.capabilities.has_color) { - data["color"] = colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int) - data["hue"] = device.color.hue / 3.6 - data["saturation"] = device.color.saturation * 100 - childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, data) + childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, ["label": device.label, "completedSetup": true]) } else { - childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, data) + childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, ["label": device.label, "completedSetup": true]) } - childDevice?.completedSetup = true - } else { - if (device.product.capabilities.has_color) { - sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)) - sendEvent(name: "hue", value: device.color.hue / 3.6) - sendEvent(name: "saturation", value: device.color.saturation * 100) - } - childDevice.sendEvent(name: "label", value: device.label) - childDevice.sendEvent(name: "level", value: Math.round((device.brightness ?: 1) * 100)) - childDevice.sendEvent(name: "switch.setLevel", value: Math.round((device.brightness ?: 1) * 100)) - childDevice.sendEvent(name: "switch", value: device.power) - childDevice.sendEvent(name: "colorTemperature", value: device.color.kelvin) - childDevice.sendEvent(name: "model", value: device.product.name) } + if (device.product.capabilities.has_color) { + childDevice.sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)) + childDevice.sendEvent(name: "hue", value: device.color.hue / 3.6) + childDevice.sendEvent(name: "saturation", value: device.color.saturation * 100) + } + childDevice.sendEvent(name: "label", value: device.label) + childDevice.sendEvent(name: "level", value: Math.round((device.brightness ?: 1) * 100)) + childDevice.sendEvent(name: "switch.setLevel", value: Math.round((device.brightness ?: 1) * 100)) + childDevice.sendEvent(name: "switch", value: device.power) + childDevice.sendEvent(name: "colorTemperature", value: device.color.kelvin) + childDevice.sendEvent(name: "model", value: device.product.name) + if (state.devices[device.id] == null) { // State missing, add it and set it to opposite status as current status to provoke event below - state.devices[device.id] = [online : !device.connected] + state.devices[device.id] = [online: !device.connected] } if (!state.devices[device.id]?.online && device.connected) { From 699f80e9f7b1f124148d4ffb7fd60a94ddd54a95 Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Fri, 28 Oct 2016 09:36:34 -0500 Subject: [PATCH 7/9] Treat over voltage as 100% battery level Many DTHs that are generating battery events use the same bit of copy/pasted code and in that code over voltage is sent as a battery event with a value of "--" however, that non-numeric value results in stack traces. Instead we now report over voltage as 100% battery. This resolves: https://smartthings.atlassian.net/browse/DVCSMP-2177 --- .../smartsense-moisture-sensor.groovy | 63 ++++++++----------- .../smartsense-motion-sensor.groovy | 63 ++++++++----------- .../smartsense-motion-temp-sensor.groovy | 31 ++++----- .../smartsense-multi-sensor.groovy | 62 ++++++++---------- ...se-open-closed-accelerometer-sensor.groovy | 44 ++++++------- .../smartsense-open-closed-sensor.groovy | 14 ++--- .../smartsense-temp-humidity-sensor.groovy | 19 +++--- .../tyco-door-window-sensor.groovy | 15 ++--- 8 files changed, 123 insertions(+), 188 deletions(-) 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 8ff9180..1d6776d 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -211,48 +211,37 @@ private Map getBatteryResult(rawValue) { log.debug "Battery rawValue = ${rawValue}" def linkText = getLinkText(device) - def result = [ - name: 'battery', - value: '--', - translatable: true - ] + def result = [:] def volts = rawValue / 10 - if (rawValue == 0 || rawValue == 255) {} - else { - if (volts > 3.5) { - result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." - } - else { - if (device.getDataValue("manufacturer") == "SmartThings") { - volts = rawValue // For the batteryMap to work the key needs to be an int - def batteryMap = [28:100, 27:100, 26:100, 25:90, 24:90, 23:70, - 22:70, 21:50, 20:50, 19:30, 18:30, 17:15, 16:1, 15:0] - def minVolts = 15 - def maxVolts = 28 + if (!(rawValue == 0 || rawValue == 255)) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" + if (device.getDataValue("manufacturer") == "SmartThings") { + volts = rawValue // For the batteryMap to work the key needs to be an int + def batteryMap = [28: 100, 27: 100, 26: 100, 25: 90, 24: 90, 23: 70, + 22: 70, 21: 50, 20: 50, 19: 30, 18: 30, 17: 15, 16: 1, 15: 0] + def minVolts = 15 + def maxVolts = 28 - if (volts < minVolts) - volts = minVolts - else if (volts > maxVolts) - volts = maxVolts - def pct = batteryMap[volts] - if (pct != null) { - result.value = pct - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } - } - else { - def minVolts = 2.1 - def maxVolts = 3.0 - def pct = (volts - minVolts) / (maxVolts - minVolts) - def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } + if (volts < minVolts) + volts = minVolts + else if (volts > maxVolts) + volts = maxVolts + def pct = batteryMap[volts] + result.value = pct + } else { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) } + } return result 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 a9f0f52..fdbdcf6 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -229,48 +229,35 @@ private Map getBatteryResult(rawValue) { log.debug "Battery rawValue = ${rawValue}" def linkText = getLinkText(device) - def result = [ - name: 'battery', - value: '--', - translatable: true - ] + def result = [:] def volts = rawValue / 10 - if (rawValue == 0 || rawValue == 255) {} - else { - if (volts > 3.5) { - result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." - } - else { - if (device.getDataValue("manufacturer") == "SmartThings") { - volts = rawValue // For the batteryMap to work the key needs to be an int - def batteryMap = [28:100, 27:100, 26:100, 25:90, 24:90, 23:70, - 22:70, 21:50, 20:50, 19:30, 18:30, 17:15, 16:1, 15:0] - def minVolts = 15 - def maxVolts = 28 + if (!(rawValue == 0 || rawValue == 255)) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" + if (device.getDataValue("manufacturer") == "SmartThings") { + volts = rawValue // For the batteryMap to work the key needs to be an int + def batteryMap = [28: 100, 27: 100, 26: 100, 25: 90, 24: 90, 23: 70, + 22: 70, 21: 50, 20: 50, 19: 30, 18: 30, 17: 15, 16: 1, 15: 0] + def minVolts = 15 + def maxVolts = 28 - if (volts < minVolts) - volts = minVolts - else if (volts > maxVolts) - volts = maxVolts - def pct = batteryMap[volts] - if (pct != null) { - result.value = pct - def value = pct - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } - } - else { - def minVolts = 2.1 - def maxVolts = 3.0 - def pct = (volts - minVolts) / (maxVolts - minVolts) - def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } + if (volts < minVolts) + volts = minVolts + else if (volts > maxVolts) + volts = maxVolts + def pct = batteryMap[volts] + result.value = pct + } else { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) } } 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 6146673..057ec7e 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 @@ -188,29 +188,20 @@ private Map getBatteryResult(rawValue) { log.debug rawValue - def result = [ - name: 'battery', - value: '--' - ] + def result = [:] def volts = rawValue / 10 - def descriptionText - if (rawValue == 0 || rawValue == 255) {} - else { - if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." - } - else if (volts > 0){ - def minVolts = 2.1 - def maxVolts = 3.0 - def pct = (volts - minVolts) / (maxVolts - minVolts) - def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - result.descriptionText = "${linkText} battery was ${result.value}%" - } + if (!(rawValue == 0 || rawValue == 255)) { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.name = 'battery' + result.value = Math.min(100, roundedPct) + result.descriptionText = "${linkText} battery was ${result.value}%" } return result 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 b1c333a..bdde60a 100644 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -286,47 +286,35 @@ def getTemperature(value) { private Map getBatteryResult(rawValue) { log.debug "Battery rawValue = ${rawValue}" - def result = [ - name: 'battery', - value: '--', - translatable: true - ] + def result = [:] def volts = rawValue / 10 - if (rawValue == 0 || rawValue == 255) {} - else { - if (volts > 3.5) { - result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." - } - else { - if (device.getDataValue("manufacturer") == "SmartThings") { - volts = rawValue // For the batteryMap to work the key needs to be an int - def batteryMap = [28:100, 27:100, 26:100, 25:90, 24:90, 23:70, - 22:70, 21:50, 20:50, 19:30, 18:30, 17:15, 16:1, 15:0] - def minVolts = 15 - def maxVolts = 28 + if (!(rawValue == 0 || rawValue == 255)) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" + if (device.getDataValue("manufacturer") == "SmartThings") { + volts = rawValue // For the batteryMap to work the key needs to be an int + def batteryMap = [28: 100, 27: 100, 26: 100, 25: 90, 24: 90, 23: 70, + 22: 70, 21: 50, 20: 50, 19: 30, 18: 30, 17: 15, 16: 1, 15: 0] + def minVolts = 15 + def maxVolts = 28 - if (volts < minVolts) - volts = minVolts - else if (volts > maxVolts) - volts = maxVolts - def pct = batteryMap[volts] - if (pct != null) { - result.value = pct - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } - } - else { - def minVolts = 2.1 - def maxVolts = 3.0 - def pct = (volts - minVolts) / (maxVolts - minVolts) - def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - } + if (volts < minVolts) + volts = minVolts + else if (volts > maxVolts) + volts = maxVolts + def pct = batteryMap[volts] + result.value = pct + } else { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) } } diff --git a/devicetypes/smartthings/smartsense-open-closed-accelerometer-sensor.src/smartsense-open-closed-accelerometer-sensor.groovy b/devicetypes/smartthings/smartsense-open-closed-accelerometer-sensor.src/smartsense-open-closed-accelerometer-sensor.groovy index 9af4f2d..d7178dd 100644 --- a/devicetypes/smartthings/smartsense-open-closed-accelerometer-sensor.src/smartsense-open-closed-accelerometer-sensor.groovy +++ b/devicetypes/smartthings/smartsense-open-closed-accelerometer-sensor.src/smartsense-open-closed-accelerometer-sensor.groovy @@ -187,35 +187,31 @@ def getTemperature(value) { } } - private Map getBatteryResult(rawValue) { - log.debug 'Battery' - def linkText = getLinkText(device) +private Map getBatteryResult(rawValue) { + log.debug 'Battery' + def linkText = getLinkText(device) - def result = [ - name: 'battery' - ] + def result = [:] - def volts = rawValue / 10 - def descriptionText - if (rawValue == 0 || rawValue == 255) {} - else if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." - } - else { - def minVolts = 2.1 - def maxVolts = 3.0 - def pct = (volts - minVolts) / (maxVolts - minVolts) - def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - result.descriptionText = "${linkText} battery was ${result.value}%" - } + def volts = rawValue / 10 + + if (!(rawValue == 0 || rawValue == 255)) { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.name = 'battery' + result.value = Math.min(100, roundedPct) + result.descriptionText = "${linkText} battery was ${result.value}%" - return result } - private Map getTemperatureResult(value) { + return result +} + +private Map getTemperatureResult(value) { log.debug 'TEMP' def linkText = getLinkText(device) if (tempOffset) { 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 483f31a..659ef52 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 @@ -205,25 +205,19 @@ private Map getBatteryResult(rawValue) { log.debug 'Battery' def linkText = getLinkText(device) - def result = [ - name: 'battery' - ] + def result = [:] def volts = rawValue / 10 - def descriptionText - if (rawValue == 0 || rawValue == 255) {} - else if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." - } - else { + if (!(rawValue == 0 || rawValue == 255)) { def minVolts = 2.1 - def maxVolts = 3.0 + def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) if (roundedPct <= 0) roundedPct = 1 result.value = Math.min(100, roundedPct) result.descriptionText = "${linkText} battery was ${result.value}%" + result.name = 'battery' } return result 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 b7873c7..88b52d7 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 @@ -216,25 +216,20 @@ private Map getBatteryResult(rawValue) { log.debug 'Battery' def linkText = getLinkText(device) - def result = [ - name: 'battery' - ] + def result = [:] def volts = rawValue / 10 - def descriptionText - if (rawValue == 0 || rawValue == 255) {} - else if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." - } - else { + if (!(rawValue == 0 || rawValue == 255)) { def minVolts = 2.1 - def maxVolts = 3.0 + def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) - if (roundedPct <= 0) - roundedPct = 1 + if (roundedPct <= 0) + roundedPct = 1 result.value = Math.min(100, roundedPct) result.descriptionText = "${linkText} battery was ${result.value}%" + result.name = 'battery' + } return result diff --git a/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy b/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy index 98f75a0..95238d4 100644 --- a/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy +++ b/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy @@ -181,22 +181,17 @@ private Map getBatteryResult(rawValue) { log.debug 'Battery' def linkText = getLinkText(device) - def result = [ - name: 'battery' - ] + def result = [:] - def volts = rawValue / 10 - def descriptionText - if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." - } - else { + if (!(rawValue == 0 || rawValue == 255)) { + def volts = rawValue / 10 def minVolts = 2.1 - def maxVolts = 3.0 + def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) result.value = Math.min(100, roundedPct) result.descriptionText = "${linkText} battery was ${result.value}%" + result.name = 'battery' } return result From d258c46aee6cc15a53f6ef75b8fdff7f9016d9f8 Mon Sep 17 00:00:00 2001 From: Vinay Rao Date: Tue, 1 Nov 2016 14:24:10 -0700 Subject: [PATCH 8/9] Revert "Revert of DVCSMP-2108 Revert of Revert LIFX device watch" --- .../lifx-color-bulb.groovy | 37 +++++++------ .../lifx-white-bulb.groovy | 38 +++++++------- .../lifx-connect.src/lifx-connect.groovy | 52 +++++++++++++++---- 3 files changed, 78 insertions(+), 49 deletions(-) diff --git a/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy b/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy index d98e8d7..5ecfae0 100644 --- a/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy +++ b/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy @@ -11,9 +11,9 @@ metadata { capability "Color Temperature" capability "Switch" capability "Switch Level" // brightness - capability "Polling" capability "Refresh" capability "Sensor" + capability "Health Check" } simulator { @@ -23,7 +23,6 @@ metadata { tiles(scale: 2) { multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { - attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666" attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff" attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff" @@ -64,12 +63,8 @@ metadata { } } -// parse events into attributes -def parse(String description) { - if (description == 'updated') { - return // don't poll when config settings is being updated as it may time out - } - poll() +void installed() { + sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}") } // handle commands @@ -192,14 +187,17 @@ def off() { return [] } -def poll() { - log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}" +def refresh() { + log.debug "Executing 'refresh'" + def resp = parent.apiGET("/lights/${selector()}") if (resp.status == 404) { - sendEvent(name: "switch", value: "unreachable") + state.online = false + sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) + log.warn "$device is Offline" return [] } else if (resp.status != 200) { - log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}") + log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") return [] } def data = resp.data[0] @@ -208,19 +206,20 @@ def poll() { sendEvent(name: "label", value: data.label) sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100)) sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch", value: data.connected ? data.power : "unreachable") + sendEvent(name: "switch", value: data.power) sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int)) sendEvent(name: "hue", value: data.color.hue / 3.6) sendEvent(name: "saturation", value: data.color.saturation * 100) sendEvent(name: "colorTemperature", value: data.color.kelvin) - sendEvent(name: "model", value: "${data.product.company} ${data.product.name}") + sendEvent(name: "model", value: data.product.name) - return [] + if (data.connected) { + sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) + log.debug "$device is Online" + } else { + sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) + log.warn "$device is Offline" } - -def refresh() { - log.debug "Executing 'refresh'" - poll() } def selector() { diff --git a/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy b/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy index d089f77..16e7c57 100644 --- a/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy +++ b/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy @@ -10,9 +10,9 @@ metadata { capability "Color Temperature" capability "Switch" capability "Switch Level" // brightness - capability "Polling" capability "Refresh" capability "Sensor" + capability "Health Check" } simulator { @@ -22,13 +22,12 @@ metadata { tiles(scale: 2) { multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { - attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666" attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff" attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff" attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" - } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" } @@ -53,15 +52,10 @@ metadata { main "switch" details(["switch", "colorTempSliderControl", "colorTemp", "refresh"]) } - } -// parse events into attributes -def parse(String description) { - if (description == 'updated') { - return // don't poll when config settings is being updated as it may time out - } - poll() +void installed() { + sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}") } // handle commands @@ -122,14 +116,17 @@ def off() { return [] } -def poll() { - log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}" +def refresh() { + log.debug "Executing 'refresh'" + def resp = parent.apiGET("/lights/${selector()}") if (resp.status == 404) { - sendEvent(name: "switch", value: "unreachable") + state.online = false + sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) + log.warn "$device is Offline" return [] } else if (resp.status != 200) { - log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}") + log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") return [] } def data = resp.data[0] @@ -137,16 +134,17 @@ def poll() { sendEvent(name: "label", value: data.label) sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100)) sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch", value: data.connected ? data.power : "unreachable") + sendEvent(name: "switch", value: data.power) sendEvent(name: "colorTemperature", value: data.color.kelvin) sendEvent(name: "model", value: data.product.name) - return [] + if (data.connected) { + sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) + log.debug "$device is Online" + } else { + sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) + log.warn "$device is Offline" } - -def refresh() { - log.debug "Executing 'refresh'" - poll() } def selector() { diff --git a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy index 8988011..41f20ef 100644 --- a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy +++ b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy @@ -242,8 +242,6 @@ def installed() { } else { initialize() } - // Check for new devices and remove old ones every 3 hours - runEvery3Hours('updateDevices') } // called after settings are changed @@ -271,9 +269,19 @@ private removeChildDevices(devices) { def initialize() { log.debug "initialize" updateDevices() + // Check for new devices and remove old ones every 3 hours + runEvery5Minutes('updateDevices') + setupDeviceWatch() } // Misc +private setupDeviceWatch() { + def hub = location.hubs[0] + // Make sure that all child devices are enrolled in device watch + getChildDevices().each { + it.sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${hub?.hub?.hardwareID}\"}") + } +} Map apiRequestHeaders() { return ["Authorization": "Bearer ${state.lifxAccessToken}", @@ -376,7 +384,7 @@ def updateDevices() { def data = [ label: device.label, level: Math.round((device.brightness ?: 1) * 100), - switch: device.connected ? device.power : "unreachable", + switch: device.power, colorTemperature: device.color.kelvin ] if (device.product.capabilities.has_color) { @@ -387,18 +395,42 @@ def updateDevices() { } else { childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, data) } + childDevice?.completedSetup = true + } else { + if (device.product.capabilities.has_color) { + sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)) + sendEvent(name: "hue", value: device.color.hue / 3.6) + sendEvent(name: "saturation", value: device.color.saturation * 100) } + childDevice.sendEvent(name: "label", value: device.label) + childDevice.sendEvent(name: "level", value: Math.round((device.brightness ?: 1) * 100)) + childDevice.sendEvent(name: "switch.setLevel", value: Math.round((device.brightness ?: 1) * 100)) + childDevice.sendEvent(name: "switch", value: device.power) + childDevice.sendEvent(name: "colorTemperature", value: device.color.kelvin) + childDevice.sendEvent(name: "model", value: device.product.name) + } + + if (state.devices[device.id] == null) { + // State missing, add it and set it to opposite status as current status to provoke event below + state.devices[device.id] = [online : !device.connected] + } + + if (!state.devices[device.id]?.online && device.connected) { + // Device came online after being offline + childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) + log.debug "$device is back Online" + } else if (state.devices[device.id]?.online && !device.connected) { + // Device went offline after being online + childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) + log.debug "$device went Offline" + } + state.devices[device.id] = [online: device.connected] } getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each { log.info("Deleting ${it.deviceNetworkId}") + state.devices[it.deviceNetworkId] = null deleteChildDevice(it.deviceNetworkId) } - runIn(1, 'refreshDevices') // Asynchronously refresh devices so we don't block } -def refreshDevices() { - log.info("Refreshing all devices...") - getChildDevices().each { device -> - device.refresh() - } -} + From 6aa0ff97b3c0d5a6b44e6bd9e04bdc2ade092493 Mon Sep 17 00:00:00 2001 From: Kevin Shuk Date: Fri, 4 Nov 2016 15:18:18 -0700 Subject: [PATCH 9/9] Fix CHF-453 on ZigBee switch power * original Health check implementation did not send refresh() commands to hub and thus the device. This fixes that problem. * updated() does not have its return value processed as a list of hub commands. These must be sent explicitly * Explicit returns rock --- .../zigbee-switch-power.src/zigbee-switch-power.groovy | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy index d86de90..c118fe6 100644 --- a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy +++ b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy @@ -84,18 +84,20 @@ def refresh() { def configure() { log.debug "in configure()" - configureHealthCheck() + return configureHealthCheck() } def configureHealthCheck() { Integer hcIntervalMinutes = 12 - refresh() sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + return refresh() } def updated() { log.debug "in updated()" - configureHealthCheck() + // updated() doesn't have it's return value processed as hub commands, so we have to send them explicitly + def cmds = configureHealthCheck() + cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it)) } } def ping() {