From 6eb29ad01952dd3905e1295af5fdf49e79ac8d29 Mon Sep 17 00:00:00 2001 From: Parijat Das Date: Thu, 22 Sep 2016 17:42:56 +0530 Subject: [PATCH 1/9] 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..e82c8a9 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", deviceJoinName: "Z-Wave Switch" + fingerprint mfr:"0063", prod:"4F50", deviceJoinName: "Z-Wave 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 b63d4a91568248fe5feaac11c7da2fb17e8d63cf Mon Sep 17 00:00:00 2001 From: "piyush.c" Date: Wed, 19 Oct 2016 10:06:38 +0530 Subject: [PATCH 2/9] CHF-406 Updated HealthCheck Implementation for Z-wave Dimmer (GE 12718, GE 12724, GE 12729) with checkInterval of 32min --- .../smartthings/dimmer-switch.src/.st-ignore | 2 + .../smartthings/dimmer-switch.src/README.md | 45 +++++++++++++++++++ .../dimmer-switch.src/dimmer-switch.groovy | 10 +++++ 3 files changed, 57 insertions(+) create mode 100644 devicetypes/smartthings/dimmer-switch.src/.st-ignore create mode 100644 devicetypes/smartthings/dimmer-switch.src/README.md diff --git a/devicetypes/smartthings/dimmer-switch.src/.st-ignore b/devicetypes/smartthings/dimmer-switch.src/.st-ignore new file mode 100644 index 0000000..f78b46e --- /dev/null +++ b/devicetypes/smartthings/dimmer-switch.src/.st-ignore @@ -0,0 +1,2 @@ +.st-ignore +README.md diff --git a/devicetypes/smartthings/dimmer-switch.src/README.md b/devicetypes/smartthings/dimmer-switch.src/README.md new file mode 100644 index 0000000..3c2cdaf --- /dev/null +++ b/devicetypes/smartthings/dimmer-switch.src/README.md @@ -0,0 +1,45 @@ +# Z-wave Dimmer Switch + + + +Works with: + +* [GE Z-Wave In-Wall Smart Dimmer (GE 12724)](http://products.z-wavealliance.org/products/1197) +* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729)](http://products.z-wavealliance.org/products/1201) +* [GE Z-Wave Plug-in Smart Dimmer (GE 12718)](http://products.z-wavealliance.org/products/1191) + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) +* [Troubleshooting](#Troubleshooting) + +## Capabilities + +* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming +* **Actuator** - represents that a Device has commands +* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch +* **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 +* **Health Check** - indicates ability to get device health notifications + +## Device Health + +Z-Wave Smart Dimmers (In-Wall, In-Wall(Toggle), Plug-In) 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. +Check-in interval = 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: +* [General Z-Wave Dimmer/Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-) +* [GE Z-Wave In-Wall Smart Dimmer (GE 12724) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200902600-GE-In-Wall-Paddle-Dimmer-Switch-GE-12724-Z-Wave-) +* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207568463-GE-In-Wall-Smart-Toggle-Dimmer-GE-12729-Z-Wave-) +* [GE Z-Wave Plug-in Smart Dimmer (GE 12718) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088474-GE-Plug-In-Smart-Dimmer-GE-12718-Z-Wave-) \ No newline at end of file diff --git a/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy b/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy index df06581..bcf0146 100644 --- a/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy +++ b/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy @@ -20,6 +20,7 @@ metadata { capability "Polling" capability "Refresh" capability "Sensor" + capability "Health Check" fingerprint mfr:"0063", prod:"4457", deviceJoinName: "Z-Wave Wall Dimmer" fingerprint mfr:"0063", prod:"4944", deviceJoinName: "Z-Wave Wall Dimmer" @@ -82,6 +83,8 @@ metadata { } def updated(){ + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) switch (ledIndicator) { case "on": indicatorWhenOn() @@ -215,6 +218,13 @@ def poll() { zwave.switchMultilevelV1.switchMultilevelGet().format() } +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + def refresh() { log.debug "refresh() is called" def commands = [] From 3fba7c9422f1584238567847bb5dbe63e500fcd9 Mon Sep 17 00:00:00 2001 From: "sushant.k1" Date: Mon, 17 Oct 2016 20:05:04 +0530 Subject: [PATCH 3/9] Added Health Check Implementation for following Z-wave switches: 1. Plug-In Smart Switch (GE 12719) 2. In-Wall Smart Outlet (GE 12721) 3. In-Wall Smart Switch (GE 12722) 4. In-Wall Smart Toggle Switch (GE 12727) Added Health Check Implementation for following Z-wave switches: 1. Plug-In Smart Switch (GE 12719) 2. In-Wall Smart Outlet (GE 12721) 3. In-Wall Smart Switch (GE 12722) 4. In-Wall Smart Toggle Switch (GE 12727) --- .../smartthings/zwave-switch.src/.st-ignore | 2 + .../smartthings/zwave-switch.src/README.md | 49 +++++++++++++++++++ .../zwave-switch.src/zwave-switch.groovy | 10 ++++ 3 files changed, 61 insertions(+) create mode 100644 devicetypes/smartthings/zwave-switch.src/.st-ignore create mode 100644 devicetypes/smartthings/zwave-switch.src/README.md diff --git a/devicetypes/smartthings/zwave-switch.src/.st-ignore b/devicetypes/smartthings/zwave-switch.src/.st-ignore new file mode 100644 index 0000000..f78b46e --- /dev/null +++ b/devicetypes/smartthings/zwave-switch.src/.st-ignore @@ -0,0 +1,2 @@ +.st-ignore +README.md diff --git a/devicetypes/smartthings/zwave-switch.src/README.md b/devicetypes/smartthings/zwave-switch.src/README.md new file mode 100644 index 0000000..7843a42 --- /dev/null +++ b/devicetypes/smartthings/zwave-switch.src/README.md @@ -0,0 +1,49 @@ +# Z-Wave Switch + + +Works with: + +* [GE Z-Wave Plug-In Smart Switch (12719)](http://products.z-wavealliance.org/products/1193) +* [GE Z-Wave In-Wall Smart Outlet (12721)](http://products.z-wavealliance.org/products/1195) +* [GE Z-Wave In-Wall Smart Switch (12722)](http://products.z-wavealliance.org/products/1196) +* [GE Z-Wave In-Wall Smart Toggle Switch (12727)](http://products.z-wavealliance.org/products/1200) + + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) +* [Troubleshooting](#Troubleshooting) + +## Capabilities + +* **Actuator** - represents that a Device has commands +* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch +* **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 +* **Health Check** - indicates ability to get device health notifications + +## Device Health + +Z-Wave Switches (Plug-In, In-Wall(Toggle Switch, Switch, Outlet)) 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 +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: +* [General Z-Wave Dimmer/Switch Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-) +* [GE Z-Wave Plug-In Smart Switch (12719) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903070-GE-Plug-In-Smart-Switch-GE-12719-Z-Wave) +* [GE Z-Wave In-Wall Smart Outlet (12721) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903020-GE-In-Wall-Smart-Outlet-GE-12721-Z-Wave) +* [GE Z-Wave In-Wall Smart Switch (12722) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200902540-GE-In-Wall-Smart-Switch-GE-12722-Z-Wave) +* [GE Z-Wave In-Wall Smart Toggle Switch (12727) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/207568933-GE-In-Wall-Smart-Toggle-Switch-GE-12727-Z-Wave) + + diff --git a/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy b/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy index afec29b..df56c69 100644 --- a/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy +++ b/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy @@ -19,6 +19,7 @@ metadata { capability "Polling" capability "Refresh" capability "Sensor" + capability "Health Check" fingerprint mfr:"0063", prod:"4952", deviceJoinName: "Z-Wave Wall Switch" fingerprint mfr:"0063", prod:"5257", deviceJoinName: "Z-Wave Wall Switch" @@ -64,6 +65,8 @@ metadata { } def updated(){ + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) switch (ledIndicator) { case "on": indicatorWhenOn() @@ -156,6 +159,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 cf1a46e3091aa1408ebd416f6100cce5a5ee75c5 Mon Sep 17 00:00:00 2001 From: Kevin Shuk Date: Wed, 19 Oct 2016 22:38:57 -0700 Subject: [PATCH 4/9] DVCSMP-2134 health check ZLL white color temp bulb * checkInterval set to 12 min (2 misses + leeway) * configure a healthPoll every 5 min * refreshes on/off state, switch level, and white color temperature * schedule and set interval from either configure() or updated() * but only once per execution * ping refreshes level setting --- .../zll-white-color-temperature-bulb.groovy | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy index bbdc73b..ab9575b 100644 --- a/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy @@ -11,6 +11,9 @@ * for the specific language governing permissions and limitations under the License. * */ +import groovy.transform.Field + +@Field Boolean hasConfiguredHealthCheck = false metadata { definition (name: "ZLL White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings") { @@ -22,6 +25,7 @@ metadata { capability "Refresh" capability "Switch" capability "Switch Level" + capability "Health Check" attribute "colorName", "string" command "setGenericName" @@ -96,9 +100,41 @@ def poll() { zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() } +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return zigbee.levelRefresh() +} + +def healthPoll() { + log.debug "healthPoll()" + def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))} +} + +def configureHealthCheck() { + Integer hcIntervalMinutes = 12 + if (!hasConfiguredHealthCheck) { + log.debug "Configuring Health Check, Reporting" + unschedule("healthPoll") + runEvery5Minutes("healthPoll") + // Device-Watch allows 2 check-in misses from device + sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + hasConfiguredHealthCheck = true + } +} + def configure() { - log.debug "Configuring Reporting and Bindings." + log.debug "configure()" + configureHealthCheck() zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + +} + +def updated() { + log.debug "updated()" + configureHealthCheck() } def setColorTemperature(value) { From 5c015cf6789fc3e635fbf7b7c4b7e9abe8fab9f9 Mon Sep 17 00:00:00 2001 From: Kevin Shuk Date: Wed, 19 Oct 2016 22:40:23 -0700 Subject: [PATCH 5/9] DVCSMP-2135 health check ZLL dimmable bulb * checkInterval set to 12 min (2 misses + leeway) * configure a healthPoll every 5 min * refreshes on/off state, switch level, and white color temperature * schedule and set interval from either configure() or updated() * but only once per execution * ping refreshes level setting --- .../zll-dimmer-bulb.groovy | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy index eb0d0e1..9b3c68e 100644 --- a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy +++ b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy @@ -11,6 +11,9 @@ * for the specific language governing permissions and limitations under the License. * */ +import groovy.transform.Field + +@Field Boolean hasConfiguredHealthCheck = false metadata { definition (name: "ZLL Dimmer Bulb", namespace: "smartthings", author: "SmartThings") { @@ -21,6 +24,7 @@ metadata { capability "Refresh" capability "Switch" capability "Switch Level" + capability "Health Check" //fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019" fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019" @@ -96,7 +100,38 @@ def poll() { refresh() } -def configure() { - log.debug "Configuring Reporting and Bindings." - zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return zigbee.levelRefresh() +} + +def healthPoll() { + log.debug "healthPoll()" + def cmds = refresh() + cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))} +} + +def configureHealthCheck() { + Integer hcIntervalMinutes = 12 + if (!hasConfiguredHealthCheck) { + log.debug "Configuring Health Check, Reporting" + unschedule("healthPoll") + runEvery5Minutes("healthPoll") + // Device-Watch allows 2 check-in misses from device + sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + hasConfiguredHealthCheck = true + } +} + +def configure() { + log.debug "configure()" + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + configureHealthCheck() +} + +def updated() { + log.debug "updated()" + configureHealthCheck() } From f1309b2ee2b15727e83ecc793005977563e1f84a Mon Sep 17 00:00:00 2001 From: Parijat Das Date: Mon, 24 Oct 2016 17:34:35 +0530 Subject: [PATCH 6/9] Added health check for Leviton DZPD3-1LW Plug-in Lamp Dimmer Module (Z-Wave) along with the README.md --- .../.st-ignore | 2 + .../zwave-dimmer-switch-generic.src/README.md | 39 +++++++++++++++++++ .../zwave-dimmer-switch-generic.groovy | 14 +++++++ 3 files changed, 55 insertions(+) create mode 100644 devicetypes/smartthings/zwave-dimmer-switch-generic.src/.st-ignore create mode 100644 devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/.st-ignore b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/.st-ignore new file mode 100644 index 0000000..f78b46e --- /dev/null +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/.st-ignore @@ -0,0 +1,2 @@ +.st-ignore +README.md diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md new file mode 100644 index 0000000..5bbc091 --- /dev/null +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/README.md @@ -0,0 +1,39 @@ +# Z-wave Dimmer + + + +Works with: + +* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW)](http://www.leviton.com/OA_HTML/ProductDetail.jsp?partnumber=DZPD3-1LW) + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) +* [Troubleshooting](#troubleshooting) + +## Capabilities + +* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming +* **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 Plug-in Lamp Dimmer Module (DZPA1-1LW) (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 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 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 4dd77ef..bd1668b 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 @@ -15,12 +15,14 @@ metadata { definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings") { capability "Switch Level" capability "Actuator" + capability "Health Check" capability "Switch" capability "Polling" capability "Refresh" capability "Sensor" fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer" + fingerprint mfr:"001D", prod:"1902", deviceJoinName: "Z-Wave Dimmer" } simulator { @@ -68,6 +70,11 @@ metadata { } } +def updated(){ +// Device-Watch simply pings if no device events received for 32min(checkInterval) + 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 if (description != "updated") { @@ -185,6 +192,13 @@ def poll() { zwave.switchMultilevelV1.switchMultilevelGet().format() } +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + def refresh() { log.debug "refresh() is called" def commands = [] From ef2323f1b16216e5e8b453642d8b36e1cd97e2cb Mon Sep 17 00:00:00 2001 From: Lars Finander Date: Tue, 25 Oct 2016 16:10:48 -0600 Subject: [PATCH 7/9] Revert "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 d196125092baf857d87b919cca2a345323e97303 Mon Sep 17 00:00:00 2001 From: Jack Chi Date: Mon, 31 Oct 2016 11:48:49 -0700 Subject: [PATCH 8/9] Revert "[CHF-404] [CHF-422] Health check for Leviton DZPA1 Plug-in Appliance Module and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)" --- .../zwave-switch-generic.src/.st-ignore | 2 - .../zwave-switch-generic.src/README.md | 39 ------------------- .../zwave-switch-generic.groovy | 15 ------- 3 files changed, 56 deletions(-) delete mode 100644 devicetypes/smartthings/zwave-switch-generic.src/.st-ignore delete 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 deleted file mode 100644 index f78b46e..0000000 --- a/devicetypes/smartthings/zwave-switch-generic.src/.st-ignore +++ /dev/null @@ -1,2 +0,0 @@ -.st-ignore -README.md diff --git a/devicetypes/smartthings/zwave-switch-generic.src/README.md b/devicetypes/smartthings/zwave-switch-generic.src/README.md deleted file mode 100644 index 72ba38d..0000000 --- a/devicetypes/smartthings/zwave-switch-generic.src/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# 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 e82c8a9..798b89d 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -14,15 +14,12 @@ 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", deviceJoinName: "Z-Wave Switch" - fingerprint mfr:"0063", prod:"4F50", deviceJoinName: "Z-Wave Switch" } // simulator metadata @@ -53,11 +50,6 @@ 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]) @@ -134,13 +126,6 @@ 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 b07b34f66cc2b50c5d7146a9a262f926af42c912 Mon Sep 17 00:00:00 2001 From: Vinay Rao Date: Tue, 1 Nov 2016 12:28:47 -0700 Subject: [PATCH 9/9] Revert "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, 49 insertions(+), 78 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 5ecfae0..d98e8d7 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,6 +23,7 @@ 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" @@ -63,8 +64,12 @@ metadata { } } -void installed() { - sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}") +// 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() } // handle commands @@ -187,17 +192,14 @@ def off() { return [] } -def refresh() { - log.debug "Executing 'refresh'" - +def poll() { + log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}" def resp = parent.apiGET("/lights/${selector()}") if (resp.status == 404) { - state.online = false - sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) - log.warn "$device is Offline" + sendEvent(name: "switch", value: "unreachable") return [] } else if (resp.status != 200) { - log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") + log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}") return [] } def data = resp.data[0] @@ -206,20 +208,19 @@ def refresh() { 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.power) + sendEvent(name: "switch", value: data.connected ? data.power : "unreachable") 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.name) + sendEvent(name: "model", value: "${data.product.company} ${data.product.name}") - 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" + return [] } + +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 16e7c57..d089f77 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,12 +22,13 @@ 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" } @@ -52,10 +53,15 @@ metadata { main "switch" details(["switch", "colorTempSliderControl", "colorTemp", "refresh"]) } + } -void installed() { - sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}") +// 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() } // handle commands @@ -116,17 +122,14 @@ def off() { return [] } -def refresh() { - log.debug "Executing 'refresh'" - +def poll() { + log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}" def resp = parent.apiGET("/lights/${selector()}") if (resp.status == 404) { - state.online = false - sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) - log.warn "$device is Offline" + sendEvent(name: "switch", value: "unreachable") return [] } else if (resp.status != 200) { - log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") + log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}") return [] } def data = resp.data[0] @@ -134,17 +137,16 @@ def refresh() { 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.power) + sendEvent(name: "switch", value: data.connected ? data.power : "unreachable") sendEvent(name: "colorTemperature", value: data.color.kelvin) sendEvent(name: "model", value: data.product.name) - 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" + return [] } + +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 41f20ef..8988011 100644 --- a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy +++ b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy @@ -242,6 +242,8 @@ def installed() { } else { initialize() } + // Check for new devices and remove old ones every 3 hours + runEvery3Hours('updateDevices') } // called after settings are changed @@ -269,19 +271,9 @@ 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}", @@ -384,7 +376,7 @@ def updateDevices() { def data = [ label: device.label, level: Math.round((device.brightness ?: 1) * 100), - switch: device.power, + switch: device.connected ? device.power : "unreachable", colorTemperature: device.color.kelvin ] if (device.product.capabilities.has_color) { @@ -395,42 +387,18 @@ 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() + } +}