From aa890ae3d5cf1fbc8429b4a1f50a6bbf0826ce4a Mon Sep 17 00:00:00 2001 From: Lars Finander Date: Mon, 3 Oct 2016 12:51:02 -0600 Subject: [PATCH] CHF-413 Philips Hue bulb shows unavailable after 16minutes and CHF-412 Hue Bridge shows OFFLINE instead of "Unavailable" --- .../hue-bridge.src/hue-bridge.groovy | 21 +++-- .../smartthings/hue-bulb.src/hue-bulb.groovy | 2 +- .../hue-connect.src/hue-connect.groovy | 78 +++++++++---------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy b/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy index 18e9a25..fee818f 100644 --- a/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy +++ b/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy @@ -7,9 +7,11 @@ metadata { // Automatically generated. Make future change here. definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") { + capability "Health Check" + attribute "networkAddress", "string" - // Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network - // Possible values "Online" or "Offline" + // Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network + // Possible values "Online" or "Offline" attribute "status", "string" // Id is the number on the back of the hub, Hue uses last six digits of Mac address // This is also used in the Hue application as ID @@ -42,6 +44,10 @@ metadata { } } +void installed() { + sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan"], displayed: false) +} + // parse events into attributes def parse(description) { log.debug "Parsing '${description}'" @@ -70,13 +76,8 @@ def parse(description) { def bulbs = new groovy.json.JsonSlurper().parseText(msg.body) if (bulbs.state) { log.info "Bridge response: $msg.body" - } else { - // Sending Bulbs List to parent" - if (parent.isInBulbDiscovery()) - log.info parent.bulbListHandler(device.hub.id, msg.body) } - } - else if (contentType?.contains("xml")) { + } else if (contentType?.contains("xml")) { log.debug "HUE BRIDGE ALREADY PRESENT" parent.hubVerification(device.hub.id, msg.body) } @@ -85,3 +86,7 @@ def parse(description) { } results } + +def ping() { + log.debug "${parent.ping(this)}" +} diff --git a/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy b/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy index d963d06..b5f25fe 100644 --- a/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy +++ b/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy @@ -174,7 +174,7 @@ void setColorTemperature(value) { void refresh() { log.debug "Executing 'refresh'" - parent.manualRefresh() + parent?.manualRefresh() } def verifyPercent(percent) { diff --git a/smartapps/smartthings/hue-connect.src/hue-connect.groovy b/smartapps/smartthings/hue-connect.src/hue-connect.groovy index d8ed36b..a9f7566 100644 --- a/smartapps/smartthings/hue-connect.src/hue-connect.groovy +++ b/smartapps/smartthings/hue-connect.src/hue-connect.groovy @@ -131,10 +131,7 @@ def bulbDiscovery() { def refreshInterval = 3 state.inBulbDiscovery = true def bridge = null - if (selectedHue) { - bridge = getChildDevice(selectedHue) - subscribe(bridge, "bulbList", bulbListData) - } + state.bridgeRefreshCount = 0 def allLightsFound = bulbsDiscovered() ?: [:] @@ -259,10 +256,6 @@ Map bulbsDiscovered() { return bulbmap } -def bulbListData(evt) { - state.bulbs = evt.jsonData -} - Map getHueBulbs() { state.bulbs = state.bulbs ?: [:] } @@ -316,29 +309,6 @@ def uninstalled(){ state.username = null } -// Handles events to add new bulbs -def bulbListHandler(hub, data = "") { - def msg = "Bulbs list not processed. Only while in settings menu." - def bulbs = [:] - if (state.inBulbDiscovery) { - def logg = "" - log.trace "Adding bulbs to state..." - state.bridgeProcessedLightList = true - def object = new groovy.json.JsonSlurper().parseText(data) - object.each { k,v -> - if (v instanceof Map) - bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, online: v.state?.reachable] - } - } - def bridge = null - if (selectedHue) { - bridge = getChildDevice(selectedHue) - bridge?.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false) - } - msg = "${bulbs.size()} bulbs found. ${bulbs}" - return msg -} - private upgradeDeviceType(device, newHueType) { def deviceType = getDeviceType(newHueType) @@ -570,11 +540,8 @@ void lightsHandler(physicalgraph.device.HubResponse hubResponse) { if (isValidSource(hubResponse.mac)) { def body = hubResponse.json if (!body?.state?.on) { //check if first time poll made it here by mistake - def bulbs = getHueBulbs() log.debug "Adding bulbs to state!" - body.each { k, v -> - bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub: hubResponse.hubId] - } + updateBulbState(body, hubResponse.hubId) } } } @@ -690,11 +657,8 @@ def locationHandler(evt) { } else { //GET /api/${state.username}/lights response (application/json) if (!body?.state?.on) { //check if first time poll made it here by mistake - def bulbs = getHueBulbs() log.debug "Adding bulbs to state!" - body.each { k,v -> - bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:parsedEvent.hub] - } + updateBulbState(body, parsedEvent.hub) } } } @@ -754,7 +718,7 @@ private void checkBridgeStatus() { } if (it.value.lastActivity < time) { // it.value.lastActivity != null && - log.warn "Bridge $it.key is Offline" + log.warn "Bridge $it.value.idNumber is Offline" d.sendEvent(name: "status", value: "Offline") state.bulbs?.each { @@ -779,6 +743,31 @@ def isInBulbDiscovery() { return state.inBulbDiscovery } +private updateBulbState(messageBody, hub) { + def bulbs = getHueBulbs() + + // Copy of bulbs used to locate old lights in state that are no longer on bridge + def toRemove = [:] + toRemove << bulbs + + messageBody.each { k,v -> + + if (v instanceof Map) { + if (bulbs[k] == null) { + bulbs[k] = [:] + } + bulbs[k] << [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, remove: false] + toRemove.remove(k) + } + } + + // Remove bulbs from state that are no longer discovered + toRemove.each { k,v -> + log.warn "${bulbs[k].name} no longer exists on bridge, removing" + bulbs.remove(k) + } +} + ///////////////////////////////////// //CHILD DEVICE METHODS ///////////////////////////////////// @@ -1173,7 +1162,14 @@ def setColor(childDevice, huesettings) { } def ping(childDevice) { - if (isOnline(getId(childDevice))) { + if (childDevice.device?.deviceNetworkId?.equalsIgnoreCase(selectedHue)) { + if (childDevice.device?.currentValue("status")?.equalsIgnoreCase("Online")) { + childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Bridge is reachable", displayed: false, isStateChange: true) + return "Bridge is Online" + } else { + return "Bridge is Offline" + } + } else if (isOnline(getId(childDevice))) { childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Light is reachable", displayed: false, isStateChange: true) return "Device is Online" } else {