From b8111e8760647ebb5bad22073c967ab61962db6c Mon Sep 17 00:00:00 2001 From: Lars Finander Date: Tue, 25 Oct 2016 15:17:34 -0600 Subject: [PATCH] Revert LIFX device watch DVCSMP-2108 LIFX: Add devicewatch support DVCSMP-2168 LIFX: Send device watch registration events in update() Left Hue change for second ticket above --- .../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() + } +}