diff --git a/devicetypes/smartthings/hue-white-ambiance-bulb/hue-white-ambiance-bulb.groovy b/devicetypes/smartthings/hue-white-ambiance-bulb.src/hue-white-ambiance-bulb.groovy similarity index 100% rename from devicetypes/smartthings/hue-white-ambiance-bulb/hue-white-ambiance-bulb.groovy rename to devicetypes/smartthings/hue-white-ambiance-bulb.src/hue-white-ambiance-bulb.groovy diff --git a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy index 1e30759..d13dffb 100644 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -403,39 +403,21 @@ def refresh() { if (device.getDataValue("manufacturer") == "SmartThings") { log.debug "Refreshing Values for manufacturer: SmartThings " - refreshCmds = refreshCmds + [ - /* These values of Motion Threshold Multiplier(01) and Motion Threshold (7602) - seem to be giving pretty accurate results for the XYZ co-ordinates for this manufacturer. - Separating these out in a separate if-else because I do not want to touch Centralite part - as of now. - */ - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global write 0xFC02 0 0x20 {01}", "delay 200", - "send 0x${device.deviceNetworkId} 1 1", "delay 400", - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global write 0xFC02 2 0x21 {7602}", "delay 200", - "send 0x${device.deviceNetworkId} 1 1", "delay 400", - ] + /* These values of Motion Threshold Multiplier(0x01) and Motion Threshold (0x0276) + seem to be giving pretty accurate results for the XYZ co-ordinates for this manufacturer. + Separating these out in a separate if-else because I do not want to touch Centralite part + as of now. + */ + refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x01, [mfgCode: manufacturerCode]) + refreshCmds += zigbee.writeAttribute(0xFC02, 0x0002, 0x21, 0x0276, [mfgCode: manufacturerCode]) } else { - refreshCmds = refreshCmds + [ - /* sensitivity - default value (8) */ - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global write 0xFC02 0 0x20 {02}", "delay 200", - "send 0x${device.deviceNetworkId} 1 1", "delay 400", - ] + refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode]) } //Common refresh commands - refreshCmds = refreshCmds + [ - "st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200", - "st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200", - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global read 0xFC02 0x0010", - "send 0x${device.deviceNetworkId} 1 1","delay 400" - ] + refreshCmds += zigbee.readAttribute(0x0402, 0x0000) + + zigbee.readAttribute(0x0001, 0x0020) + + zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode]) return refreshCmds + enrollResponse() } @@ -443,38 +425,15 @@ def refresh() { def configure() { sendEvent(name: "checkInterval", value: 7200, displayed: false) - String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) log.debug "Configuring Reporting" - def configCmds = [ - "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 200", - "zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", "delay 200", //checkin time 6 hrs - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 200", - "zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0xFC02 {${device.zigbeeId}} {}", "delay 200", - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {0100}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {0100}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", - - "zcl mfg-code ${manufacturerCode}", "delay 200", - "zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {0100}", "delay 200", - "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500" - ] + def configCmds = enrollResponse() + + zigbee.batteryConfig() + + zigbee.temperatureConfig() + + zigbee.configureReporting(0xFC02, 0x0010, 0x18, 10, 3600, 0x01, [mfgCode: manufacturerCode]) + + zigbee.configureReporting(0xFC02, 0x0012, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) + + zigbee.configureReporting(0xFC02, 0x0013, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) + + zigbee.configureReporting(0xFC02, 0x0014, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) return configCmds + refresh() } diff --git a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy index 2c020df..6011f7e 100644 --- a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy +++ b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy @@ -29,6 +29,7 @@ metadata { fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82" fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+ fingerprint deviceId: "0x0701", inClusters: "0x5E,0x72,0x5A,0x80,0x73,0x86,0x84,0x85,0x59,0x71,0x70,0x7A,0x98" // Vision door/window + fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98,0x86,0x72,0x5A,0x85,0x59,0x73,0x80,0x71,0x31,0x70,0x84,0x7A" // Vision Motion } // simulator metadata @@ -263,5 +264,9 @@ def retypeBasedOnMSR() { log.debug "Changing device type to Door / Window Sensor Plus (SG)" setDeviceType("Door / Window Sensor Plus (SG)") break + case "0109-2002-0205": // Vision Motion + log.debug "Changing device type to Vision Motion Sensor Plus (SG)" + setDeviceType("Vision Motion Sensor Plus (SG)") + break } } diff --git a/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy b/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy index 7a532e9..014900b 100644 --- a/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy +++ b/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy @@ -21,6 +21,13 @@ metadata { capability "Motion Sensor" capability "Sensor" capability "Battery" + + fingerprint mfr: "011F", prod: "0001", model: "0001", deviceJoinName: "Schlage Motion Sensor" // Schlage motion + fingerprint mfr: "014A", prod: "0001", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion + fingerprint mfr: "014A", prod: "0004", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion + + fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814 + fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02 + fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC } simulator { @@ -125,9 +132,9 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) } if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) { result << response(zwave.batteryV1.batteryGet()) - result << response("delay 1200") + } else { + result << response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } - result << response(zwave.wakeUpV1.wakeUpNoMoreInformation()) result } diff --git a/smartapps/smartthings/hue-connect.src/hue-connect.groovy b/smartapps/smartthings/hue-connect.src/hue-connect.groovy index 0ebf042..d3381f9 100644 --- a/smartapps/smartthings/hue-connect.src/hue-connect.groovy +++ b/smartapps/smartthings/hue-connect.src/hue-connect.groovy @@ -30,6 +30,7 @@ definition( preferences { page(name:"mainPage", title:"Hue Device Setup", content:"mainPage", refreshTimeout:5) page(name:"bridgeDiscovery", title:"Hue Bridge Discovery", content:"bridgeDiscovery", refreshTimeout:5) + page(name:"bridgeDiscoveryFailed", title:"Bridge Discovery Failed", content:"bridgeDiscoveryFailed", refreshTimeout:0) page(name:"bridgeBtnPush", title:"Linking with your Hue", content:"bridgeLinking", refreshTimeout:5) page(name:"bulbDiscovery", title:"Hue Device Setup", content:"bulbDiscovery", refreshTimeout:5) } @@ -53,12 +54,21 @@ def bridgeDiscovery(params=[:]) def options = bridges ?: [] def numFound = options.size() ?: 0 - if (numFound == 0 && state.bridgeRefreshCount > 25) { - log.trace "Cleaning old bridges memory" - state.bridges = [:] - state.bridgeRefreshCount = 0 - app.updateSetting("selectedHue", "") - } + if (numFound == 0) { + if (state.bridgeRefreshCount == 25) { + log.trace "Cleaning old bridges memory" + state.bridges = [:] + app.updateSetting("selectedHue", "") + } else if (state.bridgeRefreshCount > 100) { + // five minutes have passed, give up + // there seems to be a problem going back from discovey failed page in some instances (compared to pressing next) + // however it is probably a SmartThings settings issue + state.bridges = [:] + app.updateSetting("selectedHue", "") + state.bridgeRefreshCount = 0 + return bridgeDiscoveryFailed() + } + } ssdpSubscribe() @@ -79,6 +89,13 @@ def bridgeDiscovery(params=[:]) } } +def bridgeDiscoveryFailed() { + return dynamicPage(name:"bridgeDiscoveryFailed", title: "Bridge Discovery Failed", nextPage: "bridgeDiscovery") { + section("Failed to discover any Hue Bridges. Please confirm that the Hue Bridge is connected to the same network as your SmartThings Hub, and that it has power.") { + } + } +} + def bridgeLinking() { int linkRefreshcount = !state.linkRefreshcount ? 0 : state.linkRefreshcount as int @@ -88,19 +105,15 @@ def bridgeLinking() def nextPage = "" def title = "Linking with your Hue" def paragraphText - def hueimage = null if (selectedHue) { paragraphText = "Press the button on your Hue Bridge to setup a link. " - hueimage = "http://huedisco.mediavibe.nl/wp-content/uploads/2013/09/pair-bridge.png" } else { paragraphText = "You haven't selected a Hue Bridge, please Press \"Done\" and select one before clicking next." - hueimage = null } if (state.username) { //if discovery worked nextPage = "bulbDiscovery" title = "Success!" paragraphText = "Linking to your hub was a success! Please click 'Next'!" - hueimage = null } if((linkRefreshcount % 2) == 0 && !state.username) { @@ -110,8 +123,6 @@ def bridgeLinking() return dynamicPage(name:"bridgeBtnPush", title:title, nextPage:nextPage, refreshInterval:refreshInterval) { section("") { paragraph """${paragraphText}""" - if (hueimage != null) - image "${hueimage}" } } } @@ -135,13 +146,14 @@ def bulbDiscovery() { if((bulbRefreshCount % 5) == 0) { discoverHueBulbs() } + def selectedBridge = state.bridges.find { key, value -> value?.serialNumber?.equalsIgnoreCase(selectedHue) } + def title = selectedBridge?.value?.name ?: "Find bridges" return dynamicPage(name:"bulbDiscovery", title:"Bulb Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) { 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:bulboptions } section { - def title = getBridgeIP() ? "Hue bridge (${getBridgeIP()})" : "Find bridges" href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true] } @@ -348,26 +360,29 @@ def addBulbs() { def newHueBulb if (bulbs instanceof java.util.Map) { newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni } - if (newHueBulb != null) { - d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub) + + if (newHueBulb != null) { + d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub) if (d) { log.debug "created ${d.displayName} with id $dni" + d.completedSetup = true d.refresh() } - } else { - log.debug "$dni in not longer paired to the Hue Bridge or ID changed" - } + } else { + log.debug "$dni in not longer paired to the Hue Bridge or ID changed" + } } else { - //backwards compatable + //backwards compatable newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni } d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub) + d?.completedSetup = true d?.refresh() } } else { log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'" if (bulbs instanceof java.util.Map) { // Update device type if incorrect - def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni } + def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni } upgradeDeviceType(d, newHueBulb?.value?.type) } } @@ -399,6 +414,7 @@ def addBridge() { } if (newbridge) { d = addChildDevice("smartthings", "Hue Bridge", selectedHue, vbridge.value.hub) + d?.completedSetup = true log.debug "created ${d.displayName} with id ${d.deviceNetworkId}" def childDevice = getChildDevice(d.deviceNetworkId) childDevice.sendEvent(name: "serialNumber", value: vbridge.value.serialNumber) @@ -486,7 +502,21 @@ void bridgeDescriptionHandler(physicalgraph.device.HubResponse hubResponse) { def bridges = getHueBridges() def bridge = bridges.find {it?.key?.contains(body?.device?.UDN?.text())} if (bridge) { - bridge.value << [name:body?.device?.friendlyName?.text(), serialNumber:body?.device?.serialNumber?.text(), verified: true] + // serialNumber from API is in format of 0017882413ad (mac address), however on the actual bridge only last six + // characters are printed on the back so using that to identify bridge + def idNumber = body?.device?.serialNumber?.text() + if (idNumber?.size() >= 6) + idNumber = idNumber[-6..-1].toUpperCase() + + // usually in form of bridge name followed by (ip), i.e. defaults to Philips Hue (192.168.1.2) + // replace IP with serial number to make it easier for user to identify + def name = body?.device?.friendlyName?.text() + def index = name?.indexOf('(') + if (index != -1) { + name = name.substring(0,index) + name += " ($idNumber)" + } + bridge.value << [name:name, serialNumber:body?.device?.serialNumber?.text(), verified: true] } else { log.error "/description.xml returned a bridge that didn't exist" }