diff --git a/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy b/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy index 37370bb..f36edde 100644 --- a/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy +++ b/devicetypes/smartthings/hue-bridge.src/hue-bridge.groovy @@ -15,19 +15,27 @@ metadata { // TODO: define status and reply messages here } - tiles { + tiles(scale: 2) { + multiAttributeTile(name:"rich-control"){ + tileAttribute ("", key: "PRIMARY_CONTROL") { + attributeState "default", label: "Hue Bridge", action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#F3C200" + } + tileAttribute ("serialNumber", key: "SECONDARY_CONTROL") { + attributeState "default", label:'SN: ${currentValue}' + } + } standardTile("icon", "icon", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) { state "default", label: "Hue Bridge", action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#FFFFFF" } valueTile("serialNumber", "device.serialNumber", decoration: "flat", height: 1, width: 2, inactiveLabel: false) { state "default", label:'SN: ${currentValue}' } - valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 1, width: 2, inactiveLabel: false) { + valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 2, width: 4, inactiveLabel: false) { state "default", label:'${currentValue}', height: 1, width: 2, inactiveLabel: false } main (["icon"]) - details(["networkAddress","serialNumber"]) + details(["rich-control", "networkAddress"]) } } @@ -36,7 +44,6 @@ def parse(description) { log.debug "Parsing '${description}'" def results = [] def result = parent.parse(this, description) - if (result instanceof physicalgraph.device.HubAction){ log.trace "HUE BRIDGE HubAction received -- DOES THIS EVER HAPPEN?" results << result @@ -44,32 +51,30 @@ def parse(description) { //do nothing log.trace "HUE BRIDGE was updated" } else { - log.trace "HUE BRIDGE, OTHER" def map = description if (description instanceof String) { map = stringToMap(description) } if (map?.name && map?.value) { log.trace "HUE BRIDGE, GENERATING EVENT: $map.name: $map.value" - results << createEvent(name: "${map?.name}", value: "${map?.value}") - } - else { - log.trace "HUE BRIDGE, OTHER" + results << createEvent(name: "${map.name}", value: "${map.value}") + } else { + log.trace "Parsing description" def msg = parseLanMessage(description) if (msg.body) { def contentType = msg.headers["Content-Type"] if (contentType?.contains("json")) { def bulbs = new groovy.json.JsonSlurper().parseText(msg.body) if (bulbs.state) { - log.warn "NOT PROCESSED: $msg.body" - } - else { - log.debug "HUE BRIDGE, GENERATING BULB LIST EVENT: $bulbs" - sendEvent(name: "bulbList", value: device.hub.id, isStateChange: true, data: bulbs, displayed: false) + log.info "Bridge response: $msg.body" + } else { + // Sending Bulbs List to parent" + if (parent.state.inBulbDiscovery) + log.info parent.bulbListHandler(device.hub.id, msg.body) } } else if (contentType?.contains("xml")) { - log.debug "HUE BRIDGE, SWALLOWING BRIDGE DESCRIPTION RESPONSE -- BRIDGE ALREADY PRESENT" + log.debug "HUE BRIDGE ALREADY PRESENT" } } } diff --git a/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy b/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy index 7bf63f3..d93aa75 100644 --- a/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy +++ b/devicetypes/smartthings/hue-bulb.src/hue-bulb.groovy @@ -1,3 +1,4 @@ + /** * Hue Bulb * @@ -49,7 +50,6 @@ metadata { main(["switch"]) details(["switch", "levelSliderControl", "rgbSelector", "refresh", "reset"]) - } // parse events into attributes @@ -68,13 +68,13 @@ def parse(description) { } // handle commands -def on(transition = "4") { - log.trace parent.on(this,transition) +def on() { + log.trace parent.on(this) sendEvent(name: "switch", value: "on") } -def off(transition = "4") { - log.trace parent.off(this,transition) +def off() { + log.trace parent.off(this) sendEvent(name: "switch", value: "off") } @@ -107,9 +107,9 @@ def setHue(percent) { sendEvent(name: "hue", value: percent) } -def setColor(value,alert = "none",transition = 4) { +def setColor(value) { log.debug "setColor: ${value}, $this" - parent.setColor(this, value, alert, transition) + parent.setColor(this, value) if (value.hue) { sendEvent(name: "hue", value: value.hue)} if (value.saturation) { sendEvent(name: "saturation", value: value.saturation)} if (value.hex) { sendEvent(name: "color", value: value.hex)} diff --git a/devicetypes/smartthings/hue-lux-bulb.src/hue-lux-bulb.groovy b/devicetypes/smartthings/hue-lux-bulb.src/hue-lux-bulb.groovy index 5fe1e5f..07b9326 100644 --- a/devicetypes/smartthings/hue-lux-bulb.src/hue-lux-bulb.groovy +++ b/devicetypes/smartthings/hue-lux-bulb.src/hue-lux-bulb.groovy @@ -19,24 +19,41 @@ metadata { simulator { // TODO: define status and reply messages here } + + tiles(scale: 2) { + multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){ + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"switch level.setLevel", range:"(0..100)" + } + tileAttribute ("device.level", key: "SECONDARY_CONTROL") { + attributeState "level", label: 'Level ${currentValue}%' + } + } + + standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { + state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + + controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") { + state "level", action:"switch level.setLevel" + } + + standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } - standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { - state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821" - state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff" - } - standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") { - state "level", action:"switch level.setLevel" - } - valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") { - state "level", label: 'Level ${currentValue}%' - } - - main(["switch"]) - details(["switch", "levelSliderControl", "refresh"]) - + main(["switch"]) + details(["rich-control", "refresh"]) + } } // parse events into attributes diff --git a/smartapps/smartthings/hue-connect.src/hue-connect.groovy b/smartapps/smartthings/hue-connect.src/hue-connect.groovy index 5726108..27b8f9c 100644 --- a/smartapps/smartthings/hue-connect.src/hue-connect.groovy +++ b/smartapps/smartthings/hue-connect.src/hue-connect.groovy @@ -15,7 +15,7 @@ * for the specific language governing permissions and limitations under the License. * */ - + definition( name: "Hue (Connect)", namespace: "smartthings", @@ -64,10 +64,12 @@ def bridgeDiscovery(params=[:]) def options = bridges ?: [] def numFound = options.size() ?: 0 - if(!state.subscribe) { - subscribe(location, null, locationHandler, [filterEvents:false]) - state.subscribe = true - } + if (numFound == 0 && state.bridgeRefreshCount > 5) { + log.trace "Cleaning old bridges memory" + atomicState.bridges = [:] + } + + subscribe(location, null, locationHandler, [filterEvents:false]) //bridge discovery request every 15 //25 seconds if((bridgeRefreshCount % 5) == 0) { @@ -117,7 +119,8 @@ def bulbDiscovery() int bulbRefreshCount = !state.bulbRefreshCount ? 0 : state.bulbRefreshCount as int state.bulbRefreshCount = bulbRefreshCount + 1 def refreshInterval = 3 - + state.inBulbDiscovery = true + state.bridgeRefreshCount = 0 def options = bulbsDiscovered() ?: [] def numFound = options.size() ?: 0 @@ -129,7 +132,7 @@ def bulbDiscovery() section("Please wait while we discover your Hue Bulbs. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") { input "selectedBulbs", "enum", required:false, title:"Select Hue Bulbs (${numFound} found)", multiple:true, options:options } - section { + section { def title = getBridgeIP() ? "Hue bridge (${getBridgeIP()})" : "Find bridges" href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true] @@ -194,29 +197,30 @@ Map bridgesDiscovered() { Map bulbsDiscovered() { def bulbs = getHueBulbs() - def map = [:] + def bulbmap = [:] if (bulbs instanceof java.util.Map) { bulbs.each { - def value = "${it?.value?.name}" - def key = app.id +"/"+ it?.value?.id - map["${key}"] = value + def value = "${it.value.name}" + def key = app.id +"/"+ it.value.id + bulbmap["${key}"] = value } } else { //backwards compatable bulbs.each { - def value = "${it?.name}" - def key = app.id +"/"+ it?.id - map["${key}"] = value + def value = "${it.name}" + def key = app.id +"/"+ it.id + logg += "$value - $key, " + bulbmap["${key}"] = value } } - map + bulbmap } def getHueBulbs() { - state.bulbs = state.bulbs ?: [:] + atomicState.bulbs = atomicState.bulbs ?: [:] } def getHueBridges() { - state.bridges = state.bridges ?: [:] + atomicState.bridges = atomicState.bridges ?: [:] } def getVerifiedHueBridges() { @@ -231,24 +235,16 @@ def installed() { def updated() { log.trace "Updated with settings: ${settings}" unschedule() - unsubscribe() + unsubscribe() initialize() } def initialize() { - log.debug "Initializing" - state.subscribe = false - state.bridgeSelectedOverride = false - def bridge = null - + log.debug "Initializing" + state.inBulbDiscovery = false if (selectedHue) { addBridge() - bridge = getChildDevice(selectedHue) - subscribe(bridge, "bulbList", bulbListHandler) - } - - if (selectedBulbs) { - addBulbs() + addBulbs() doDeviceSync() runEvery5Minutes("doDeviceSync") } @@ -262,23 +258,27 @@ def manualRefresh() { } def uninstalled(){ - state.bridges = [:] - state.subscribe = false + atomicState.bridges = [:] + state.username = null } // Handles events to add new bulbs -def bulbListHandler(evt) { - def bulbs = [:] - log.trace "Adding bulbs to state..." - state.bridgeProcessedLightList = true - evt.jsonData.each { k,v -> - log.trace "$k: $v" - if (v instanceof Map) { - bulbs[k] = [id: k, name: v.name, type: v.type, hub:evt.value] - } - } - state.bulbs = bulbs - log.info "${bulbs.size()} bulbs found" +def bulbListHandler(hub, data) { + def msg = "Bulbs list not processed. Only while in settings menu." + if (state.inBulbDiscovery) { + def bulbs = [:] + 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, hub:hub] + } + atomicState.bulbs = bulbs + msg = "${bulbs.size()} bulbs found. $atomicState.bulbs" + } + return msg } def addBulbs() { @@ -294,7 +294,7 @@ def addBulbs() { } else { d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name]) } - } else { + } else { //backwards compatable newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni } d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name]) @@ -322,7 +322,7 @@ def addBridge() { def d = getChildDevice(selectedHue) if(!d) { // compatibility with old devices - def newbridge = true + def newbridge = true childDevices.each { if (it.getDeviceDataByName("mac")) { def newDNI = "${it.getDeviceDataByName("mac")}" @@ -332,22 +332,27 @@ def addBridge() { it.setDeviceNetworkId("${newDNI}") if (oldDNI == selectedHue) app.updateSetting("selectedHue", newDNI) - newbridge = false + newbridge = false } - } - } + } + } if (newbridge) { d = addChildDevice("smartthings", "Hue Bridge", selectedHue, vbridge.value.hub) log.debug "created ${d.displayName} with id ${d.deviceNetworkId}" def childDevice = getChildDevice(d.deviceNetworkId) childDevice.sendEvent(name: "serialNumber", value: vbridge.value.serialNumber) if (vbridge.value.ip && vbridge.value.port) { - if (vbridge.value.ip.contains(".")) + if (vbridge.value.ip.contains(".")) { childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port) - else - childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port)) - } else + childDevice.updateDataValue("networkAddress", vbridge.value.ip + ":" + vbridge.value.port) + } else { + childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port)) + childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port)) + } + } else { childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress)) + childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress)) + } } } else { log.debug "found ${d.displayName} with id $selectedHue already exists" @@ -357,19 +362,19 @@ def addBridge() { def locationHandler(evt) { - def description = evt.description - log.trace "Location: $description" - + def description = evt.description + log.trace "Location: $description" + def hub = evt?.hubId - def parsedEvent = parseLanMessage(description) + def parsedEvent = parseLanMessage(description) parsedEvent << ["hub":hub] - if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:basic:1")) { + if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:basic:1")) { //SSDP DISCOVERY EVENTS log.trace "SSDP DISCOVERY EVENTS" def bridges = getHueBridges() log.trace bridges.toString() - if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) { + if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) { //bridge does not exist log.trace "Adding bridge ${parsedEvent.ssdpUSN}" bridges << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent] @@ -395,10 +400,13 @@ def locationHandler(evt) { app.updateSetting("selectedHue", newDNI) doDeviceSync() } - } + } } } else { - networkAddress = d.latestState('networkAddress').stringValue + if (d.getDeviceDataByName("networkAddress")) + networkAddress = d.getDeviceDataByName("networkAddress") + else + networkAddress = d.latestState('networkAddress').stringValue log.trace "Host: $host - $networkAddress" if(host != networkAddress) { log.debug "Device's port or ip changed for device $d..." @@ -406,11 +414,12 @@ def locationHandler(evt) { dstate.port = port dstate.name = "Philips hue ($ip)" d.sendEvent(name:"networkAddress", value: host) - } + d.updateDataValue("networkAddress", host) + } } } } - else if (parsedEvent.headers && parsedEvent.body) { + else if (parsedEvent.headers && parsedEvent.body) { log.trace "HUE BRIDGE RESPONSES" def headerString = parsedEvent.headers.toString() if (headerString?.contains("xml")) { @@ -430,22 +439,13 @@ def locationHandler(evt) { def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body) if (body.success != null) { if (body.success[0] != null) { - if (body.success[0].username) + if (body.success[0].username) state.username = body.success[0].username } } else if (body.error != null) { //TODO: handle retries... log.error "ERROR: application/json ${body.error}" - } 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, hub:parsedEvent.hub] - } - } - } + } } } else { log.trace "NON-HUE EVENT $evt.description" @@ -454,17 +454,13 @@ def locationHandler(evt) { def doDeviceSync(){ log.trace "Doing Hue Device Sync!" - - //shrink the large bulb lists convertBulbListToMap() - poll() - - if(!state.subscribe) { + try { subscribe(location, null, locationHandler, [filterEvents:false]) - state.subscribe = true - } - + } catch (all) { + log.trace "Subscription already exist" + } discoverBridges() } @@ -473,44 +469,49 @@ def doDeviceSync(){ ///////////////////////////////////// def parse(childDevice, description) { - def parsedEvent = parseLanMessage(description) + def parsedEvent = parseLanMessage(description) if (parsedEvent.headers && parsedEvent.body) { def headerString = parsedEvent.headers.toString() - if (headerString?.contains("json")) { - def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body) - if (body instanceof java.util.HashMap) - { //poll response + def bodyString = parsedEvent.body.toString() + if (headerString?.contains("json")) { + def body + try { + body = new groovy.json.JsonSlurper().parseText(bodyString) + } catch (all) { + log.warn "Parsing Body failed - trying again..." + poll() + } + if (body instanceof java.util.HashMap) { + //poll response def bulbs = getChildDevices() - //for each bulb for (bulb in body) { - def d = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"} + def d = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"} if (d) { if (bulb.value.state?.reachable) { - sendEvent(d.deviceNetworkId, [name: "switch", value: bulb.value?.state?.on ? "on" : "off"]) - sendEvent(d.deviceNetworkId, [name: "level", value: Math.round(bulb.value.state.bri * 100 / 255)]) - if (bulb.value.state.sat) { - def hue = Math.min(Math.round(bulb.value.state.hue * 100 / 65535), 65535) as int - def sat = Math.round(bulb.value.state.sat * 100 / 255) as int - def hex = colorUtil.hslToHex(hue, sat) - sendEvent(d.deviceNetworkId, [name: "color", value: hex]) - sendEvent(d.deviceNetworkId, [name: "hue", value: hue]) - sendEvent(d.deviceNetworkId, [name: "saturation", value: sat]) - } - } else { - sendEvent(d.deviceNetworkId, [name: "switch", value: "off"]) - sendEvent(d.deviceNetworkId, [name: "level", value: 100]) - if (bulb.value.state.sat) { - def hue = 23 - def sat = 56 - def hex = colorUtil.hslToHex(23, 56) - sendEvent(d.deviceNetworkId, [name: "color", value: hex]) - sendEvent(d.deviceNetworkId, [name: "hue", value: hue]) - sendEvent(d.deviceNetworkId, [name: "saturation", value: sat]) - } - } + sendEvent(d.deviceNetworkId, [name: "switch", value: bulb.value?.state?.on ? "on" : "off"]) + sendEvent(d.deviceNetworkId, [name: "level", value: Math.round(bulb.value.state.bri * 100 / 255)]) + if (bulb.value.state.sat) { + def hue = Math.min(Math.round(bulb.value.state.hue * 100 / 65535), 65535) as int + def sat = Math.round(bulb.value.state.sat * 100 / 255) as int + def hex = colorUtil.hslToHex(hue, sat) + sendEvent(d.deviceNetworkId, [name: "color", value: hex]) + sendEvent(d.deviceNetworkId, [name: "hue", value: hue]) + sendEvent(d.deviceNetworkId, [name: "saturation", value: sat]) + } + } else { + sendEvent(d.deviceNetworkId, [name: "switch", value: "off"]) + sendEvent(d.deviceNetworkId, [name: "level", value: 100]) + if (bulb.value.state.sat) { + def hue = 23 + def sat = 56 + def hex = colorUtil.hslToHex(23, 56) + sendEvent(d.deviceNetworkId, [name: "color", value: hex]) + sendEvent(d.deviceNetworkId, [name: "hue", value: hue]) + sendEvent(d.deviceNetworkId, [name: "saturation", value: sat]) + } + } } - - } + } } else { //put response @@ -559,25 +560,25 @@ def parse(childDevice, description) { } } - } + } } else { log.debug "parse - got something other than headers,body..." return [] } } -def on(childDevice, transition = 4) { +def on(childDevice, transition_deprecated = 0) { log.debug "Executing 'on'" - // Assume bulb is off if no current state is found for level to avoid bulbs getting stuck in off after initial discovery - def percent = childDevice.device?.currentValue("level") as Integer ?: 0 + def percent = childDevice.device?.currentValue("level") as Integer def level = Math.min(Math.round(percent * 255 / 100), 255) - put("lights/${getId(childDevice)}/state", [bri: level, on: true, transitiontime: transition]) + put("lights/${getId(childDevice)}/state", [bri: level, on: true]) return "level: $percent" } -def off(childDevice, transition = 4) { +def off(childDevice, transition_deprecated = 0) { log.debug "Executing 'off'" - put("lights/${getId(childDevice)}/state", [on: false, transitiontime: transition]) + put("lights/${getId(childDevice)}/state", [on: false]) + return "level: 0" } def setLevel(childDevice, percent) { @@ -598,19 +599,21 @@ def setHue(childDevice, percent) { put("lights/${getId(childDevice)}/state", [hue: level]) } -def setColor(childDevice, color, alert = "none", transition = 4) { - log.debug "Executing 'setColor($color)'" - def hue = Math.min(Math.round(color.hue * 65535 / 100), 65535) - def sat = Math.min(Math.round(color.saturation * 255 / 100), 255) +def setColor(childDevice, huesettings, alert_deprecated = "", transition_deprecated = 0) { + log.debug "Executing 'setColor($huesettings)'" + def hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535) + def sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255) + def alert = huesettings.alert ? huesettings.alert : "none" + def transition = huesettings.transition ? huesettings.transition : 4 def value = [sat: sat, hue: hue, alert: alert, transitiontime: transition] - if (color.level != null) { - value.bri = Math.min(Math.round(color.level * 255 / 100), 255) + if (huesettings.level != null) { + value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255) value.on = value.bri > 0 } - if (color.switch) { - value.on = color.switch == "on" + if (huesettings.switch) { + value.on = huesettings.switch == "on" } log.debug "sending command $value" @@ -640,15 +643,19 @@ private getId(childDevice) { private poll() { def host = getBridgeIP() def uri = "/api/${state.username}/lights/" - log.debug "GET: $host$uri" - sendHubCommand(new physicalgraph.device.HubAction("""GET ${uri} HTTP/1.1 + try { + sendHubCommand(new physicalgraph.device.HubAction("""GET ${uri} HTTP/1.1 HOST: ${host} """, physicalgraph.device.Protocol.LAN, selectedHue)) + } catch (all) { + log.warn "Parsing Body failed - trying again..." + doDeviceSync() + } } private put(path, body) { - def host = getBridgeIP() + def host = getBridgeIP() def uri = "/api/${state.username}/$path" def bodyJSON = new groovy.json.JsonBuilder(body).toString() def length = bodyJSON.getBytes().size().toString() @@ -668,9 +675,13 @@ ${bodyJSON} private getBridgeIP() { def host = null if (selectedHue) { - def d = getChildDevice(dni) - if (d) - host = d.latestState('networkAddress').stringValue + def d = getChildDevice(selectedHue) + if (d) { + if (d.getDeviceDataByName("networkAddress")) + host = d.getDeviceDataByName("networkAddress") + else + host = d.latestState('networkAddress').stringValue + } if (host == null || host == "") { def serialNumber = selectedHue def bridge = getHueBridges().find { it?.value?.serialNumber?.equalsIgnoreCase(serialNumber) }?.value @@ -681,9 +692,9 @@ private getBridgeIP() { host = "${convertHexToIP(bridge?.ip)}:${convertHexToInt(bridge?.port)}" } else if (bridge?.networkAddress && bridge?.deviceAddress) host = "${convertHexToIP(bridge?.networkAddress)}:${convertHexToInt(bridge?.deviceAddress)}" - } + } log.trace "Bridge: $selectedHue - Host: $host" - } + } return host } diff --git a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy index 123f8a9..aefd723 100644 --- a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy +++ b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy @@ -38,7 +38,7 @@ definition( name: "Logitech Harmony (Connect)", namespace: "smartthings", - author: "Juan Pablo Risso", + author: "SmartThings", description: "Allows you to integrate your Logitech Harmony account with SmartThings.", category: "SmartThings Labs", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/harmony.png", @@ -394,7 +394,9 @@ def discovery() { } catch (java.net.SocketTimeoutException e) { log.warn "Connection to the hub timed out. Please restart the hub and try again." state.resethub = true - } + } catch (e) { + log.warn "Hostname in certificate didn't match. Please try again later." + } return null } @@ -459,7 +461,9 @@ def activity(dni,mode) { msg = ex state.aux = 0 } - } + } catch(Exception ex) { + msg = ex + } runIn(10, "poll", [overwrite: true]) return msg } @@ -517,7 +521,9 @@ def poll() { state.remove("HarmonyAccessToken") return "Harmony Access token has expired" } - } + } catch(Exception e) { + log.trace e + } } } @@ -550,7 +556,9 @@ def getActivityList() { log.trace e } catch (java.net.SocketTimeoutException e) { log.trace e - } + } catch(Exception e) { + log.trace e + } } return activity } @@ -565,9 +573,9 @@ def getActivityName(activity,hubId) { httpGet(uri: url, headers: ["Accept": "application/json"]) {response -> actname = response.data.data.activities[activity].name } - } catch (groovyx.net.http.HttpResponseException e) { + } catch(Exception e) { log.trace e - } + } } return actname } @@ -585,9 +593,9 @@ def getActivityId(activity,hubId) { actid = it.key } } - } catch (groovyx.net.http.HttpResponseException e) { + } catch(Exception e) { log.trace e - } + } } return actid } @@ -602,9 +610,9 @@ def getHubName(hubId) { httpGet(uri: url, headers: ["Accept": "application/json"]) {response -> hubname = response.data.data.name } - } catch (groovyx.net.http.HttpResponseException e) { + } catch(Exception e) { log.trace e - } + } } return hubname }