From ef21fd42572f34ef6ae0ba9d200611434454e416 Mon Sep 17 00:00:00 2001 From: Warodom Khamphanchai Date: Tue, 20 Oct 2015 01:01:17 -0700 Subject: [PATCH 1/2] DVCSMP-668 The following changes has been made to the original Aeon Multisensor device type handler to improve and modernize it: 1. Add "powerSupply" attribute to be able to tell power source (USB Cable/Battery) 2. Add preference page for user to customize "motion delay time", "motion sensitivity", and "sensor report interval" 3. Add color backgroud of "illuminance" value tile 4. Add tile for "ultravioletIndex" 5. Add tile for "powerSupply" 6. Modify updated() to be able to send configuration commands to sensor whether it is powered by USB cable or battery 7. When battery operated, send command to get update battery level if it hasn't been reported for a while 8. Report MSR of the sensor 9. Add handle for ConfigurationReport command class to update the "powerSupply" tile and change opetion mode of the sensor accordingly 10. Update configure() to configure parameters changed by user in preference page 11. Take out the "Configure" tile and instead send the configuration commands on every wakeup (sensor is battey powered) --- .../aeon-multisensor-6.groovy | 206 ++++++++++++++---- 1 file changed, 164 insertions(+), 42 deletions(-) diff --git a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy index 744879d..a453abf 100644 --- a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy +++ b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy @@ -24,6 +24,7 @@ metadata { capability "Battery" attribute "tamper", "enum", ["detected", "clear"] + attribute "powerSupply", "enum", ["USB Cable", "Battery"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A" } @@ -63,6 +64,19 @@ metadata { status "wake up" : "command: 8407, payload: " } + preferences { + input description: "Please consult AEOTEC MULTISENSOR 6 operating manual for advanced setting options. You can skip this configuration to use default settings", + title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph" + + input "motionDelayTime", "enum", title: "Motion Sensor Delay Time", + options: ["20 seconds", "40 seconds", "1 minute", "2 minutes", "3 minutes", "4 minutes"], defaultValue: "${motionDelayTime}", displayDuringSetup: true + + input "motionSensitivity", "enum", title: "Motion Sensor Sensitivity", options: ["normal","maximum","minimum"], defaultValue: "${motionSensitivity}", displayDuringSetup: true + + input "reportInterval", "enum", title: "Sensors Report Interval", + options: ["8 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${reportInterval}", displayDuringSetup: true + } + tiles(scale: 2) { multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { @@ -85,53 +99,89 @@ metadata { valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) { state "humidity", label:'${currentValue}% humidity', unit:"" } + valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) { - state "luminosity", label:'${currentValue} ${unit}', unit:"lux" + state "illuminance", label:'${currentValue} ${unit}', unit:"lux", + backgroundColors:[ + [value: 0, color: "#000000"], + [value: 1, color: "#060053"], + [value: 3, color: "#3E3900"], + [value: 12, color: "#8E8400"], + [value: 24, color: "#C5C08B"], + [value: 36, color: "#DAD7B6"], + [value: 128, color: "#F3F2E9"], + [value: 1000, color: "#FFFFFF"] + ] } + + valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) { + state "ultravioletIndex", label:'${currentValue} UV index', unit:"" + } + valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } - main(["motion", "temperature", "humidity", "illuminance"]) - details(["motion", "temperature", "humidity", "illuminance", "battery"]) + valueTile("powerSupply", "device.powerSupply", height: 2, width: 2, decoration: "flat") { + state "powerSupply", label:'${currentValue} powered', backgroundColor:"#ffffff" + } + + main(["motion", "temperature", "humidity", "illuminance", "ultravioletIndex"]) + details(["motion", "temperature", "humidity", "illuminance", "ultravioletIndex", "battery", "powerSupply"]) } } -def updated() -{ - if (state.sec && !isConfigured()) { - // in case we miss the SCSR +def updated() { + log.debug "Updated with settings: ${settings}" + + log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}" + + if (device.latestValue("powerSupply") == "USB Cable") { //case1: USB powered response(configure()) + } else if (device.latestValue("powerSupply") == "Battery") { //case2: battery powered + // setConfigured("false") is used by WakeUpNotification + setConfigured("false") //wait until the next time device wakeup to send configure command after user change preference + } else { //case3: power source is not identified, ask user to properly pair the sensor again + sendEvent( name: "powerSupply", value: "failed", isStateChange: true, displayed: true, + descriptionText: "This sensor failed to update it's power supply source. Unplug and plug-in the USB cable again or reinsert batteries to the sensor") } } -def parse(String description) -{ +def parse(String description) { + log.debug "parse() >> description: $description" def result = null if (description.startsWith("Err 106")) { - state.sec = 0 + log.debug "parse() >> Err 106" result = createEvent( name: "secureInclusion", value: "failed", isStateChange: true, - descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.") + descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.") } else if (description != "updated") { + log.debug "parse() >> zwave.parse(description)" def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } - log.debug "Parsed '${description}' to ${result.inspect()}" + log.debug "After zwaveEvent(cmd) >> Parsed '${description}' to ${result.inspect()}" return result } -def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) -{ +//this notification will be sent only when device is battery powered +def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] - + def cmds = [] if (!isConfigured()) { - // we're still in the process of configuring a newly joined device log.debug("late configure") - result += response(configure()) + result << response(configure()) } else { - result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) + //Only ask for battery if we haven't had a BatteryReport in a while + if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) { + log.debug("Device has been configured sending >> batteryGet()") + cmds << zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format() + cmds << "delay 1200" + } + log.debug("Device has been configured sending >> wakeUpNoMoreInformation()") + cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() + result << response(cmds) } result } @@ -149,7 +199,25 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { - response(configure()) + log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd" + state.sec = 1 +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.NetworkKeyVerify cmd) { + state.sec = 1 + log.info "Executing zwaveEvent 98 (SecurityV1): 07 (NetworkKeyVerify) with cmd: $cmd (node is securely included)" + def result = [createEvent(name:"secureInclusion", value:"success", descriptionText:"Secure inclusion was successful", isStateChange: true)] + result +} + +def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { + log.info "Executing zwaveEvent 72 (ManufacturerSpecificV2) : 05 (ManufacturerSpecificReport) with cmd: $cmd" + log.debug "manufacturerId: ${cmd.manufacturerId}" + log.debug "manufacturerName: ${cmd.manufacturerName}" + log.debug "productId: ${cmd.productId}" + log.debug "productTypeId: ${cmd.productTypeId}" + def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) + updateDataValue("MSR", msr) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { @@ -165,8 +233,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { createEvent(map) } -def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) -{ +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){ def map = [:] switch (cmd.sensorType) { case 1: @@ -208,7 +275,6 @@ def motionEvent(value) { } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { - setConfigured() motionEvent(cmd.sensorValue) } @@ -225,47 +291,102 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm result << createEvent(name: "tamper", value: "clear", displayed: false) break case 3: - result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was moved") + result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was tampered") break case 7: result << motionEvent(1) break } } else { + log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}" result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def result = [] + def value + if (cmd.configurationValue[0] == 0) { + value = "USB Cable" + if (!isConfigured()) { + log.debug("ConfigurationReport: configuring device") + result << response(configure()) + } + } + if (cmd.configurationValue[0] == 1) {value = "Battery"} + result << createEvent(name: "powerSupply", value: value, displayed: false) + result +} + def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "General zwaveEvent cmd: ${cmd}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configure() { // This sensor joins as a secure device if you double-click the button to include it - if (device.device.rawDescription =~ /98/ && !state.sec) { - log.debug "Multi 6 not sending configure until secure" + if (!state.sec) { + log.debug "${device.displayName} not sending configure until secure" return [] + } else { + log.debug "${device.displayName} is configuring its settings" + def request = [] + + //1. automatic report flags + // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 2 ultraviolet sensor, 1 battery sensor -> send command 227 to get all reports + request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 227) + + //2. no-motion report x seconds after motion stops (default 20 secs) + request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 20) + + //3. motionSensitivity 3 levels: 64-normal (default), 127-maximum, 0-minimum + request << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, + scaledConfigurationValue: + motionSensitivity == "normal" ? 64 : + motionSensitivity == "maximum" ? 127 : + motionSensitivity == "minimum" ? 0 : 64) + + //4. report every x minutes (threshold reports don't work on battery power, default 8 mins) + request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) + + //5. report automatically on threshold change + request << zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: 1) + + //6. query sensor data + request << zwave.batteryV1.batteryGet() + request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x1B) //ultravioletIndex + + setConfigured("true") + + commands(request) + ["delay 10000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } - log.debug "Multi 6 configure()" - def request = [ - // send no-motion report 20 seconds after motion stops - zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 20), - - // report every 8 minutes (threshold reports don't work on battery power) - zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60), - - // report automatically on threshold change - zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: 1), - - zwave.batteryV1.batteryGet(), - zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C), - ] - commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } -private setConfigured() { - updateDataValue("configured", "true") +private def getTimeOptionValueMap() { [ + "20 seconds" : 20, + "40 seconds" : 40, + "1 minute" : 60, + "2 minutes" : 2*60, + "3 minutes" : 3*60, + "4 minutes" : 4*60, + "5 minutes" : 5*60, + "8 minutes" : 8*60, + "15 minutes" : 15*60, + "30 minutes" : 30*60, + "1 hours" : 1*60*60, + "6 hours" : 6*60*60, + "12 hours" : 12*60*60, + "18 hours" : 6*60*60, + "24 hours" : 24*60*60, +]} + +private setConfigured(configure) { + updateDataValue("configured", configure) } private isConfigured() { @@ -281,5 +402,6 @@ private command(physicalgraph.zwave.Command cmd) { } private commands(commands, delay=200) { + log.info "sending commands: ${commands}" delayBetween(commands.collect{ command(it) }, delay) } From 794ff6b68aba4d2c48f753e8a9f7900e72cf2b74 Mon Sep 17 00:00:00 2001 From: Warodom Khamphanchai Date: Wed, 21 Oct 2015 15:33:51 -0700 Subject: [PATCH 2/2] DVCSMP-668 - Show batteryStatus tile insteady of battery tile to be able to display both when sensor is USB powered or battery powered - Remove background for illuminance. This can be added when we have best practice of showing colors for lux. - Instead of using powerSupply:failed, configurationGet cmd is sent and then the configure() is triggered by configurationReport to determine powerSupply (USB Cable/Battery) - Instead of querying battery level on wake up, battery report is put in association group 2 that is configured to report every 6 hours by default - Update configure() to send both unsecure and secure configuration commands when sensor is joined normally or securely --- .../aeon-multisensor-6.groovy | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy index a453abf..108a72a 100644 --- a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy +++ b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy @@ -24,6 +24,7 @@ metadata { capability "Battery" attribute "tamper", "enum", ["detected", "clear"] + attribute "batteryStatus", "string" attribute "powerSupply", "enum", ["USB Cable", "Battery"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A" @@ -101,17 +102,7 @@ metadata { } valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) { - state "illuminance", label:'${currentValue} ${unit}', unit:"lux", - backgroundColors:[ - [value: 0, color: "#000000"], - [value: 1, color: "#060053"], - [value: 3, color: "#3E3900"], - [value: 12, color: "#8E8400"], - [value: 24, color: "#C5C08B"], - [value: 36, color: "#DAD7B6"], - [value: 128, color: "#F3F2E9"], - [value: 1000, color: "#FFFFFF"] - ] + state "illuminance", label:'${currentValue} ${unit}', unit:"lux" } valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) { @@ -122,18 +113,21 @@ metadata { state "battery", label:'${currentValue}% battery', unit:"" } + valueTile("batteryStatus", "device.batteryStatus", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "batteryStatus", label:'${currentValue}', unit:"" + } + valueTile("powerSupply", "device.powerSupply", height: 2, width: 2, decoration: "flat") { state "powerSupply", label:'${currentValue} powered', backgroundColor:"#ffffff" } main(["motion", "temperature", "humidity", "illuminance", "ultravioletIndex"]) - details(["motion", "temperature", "humidity", "illuminance", "ultravioletIndex", "battery", "powerSupply"]) + details(["motion", "temperature", "humidity", "illuminance", "ultravioletIndex", "batteryStatus"]) } } def updated() { log.debug "Updated with settings: ${settings}" - log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}" if (device.latestValue("powerSupply") == "USB Cable") { //case1: USB powered @@ -142,8 +136,10 @@ def updated() { // setConfigured("false") is used by WakeUpNotification setConfigured("false") //wait until the next time device wakeup to send configure command after user change preference } else { //case3: power source is not identified, ask user to properly pair the sensor again - sendEvent( name: "powerSupply", value: "failed", isStateChange: true, displayed: true, - descriptionText: "This sensor failed to update it's power supply source. Unplug and plug-in the USB cable again or reinsert batteries to the sensor") + log.warn "power source is not identified, check it sensor is powered by USB, if so > configure()" + def request = [] + request << zwave.configurationV1.configurationGet(parameterNumber: 101) + response(commands(request)) } } @@ -173,12 +169,6 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { log.debug("late configure") result << response(configure()) } else { - //Only ask for battery if we haven't had a BatteryReport in a while - if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) { - log.debug("Device has been configured sending >> batteryGet()") - cmds << zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format() - cmds << "delay 1200" - } log.debug("Device has been configured sending >> wakeUpNoMoreInformation()") cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() result << response(cmds) @@ -221,6 +211,7 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def result = [] def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 @@ -230,7 +221,11 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { map.value = cmd.batteryLevel } state.lastbatt = now() - createEvent(map) + result << createEvent(map) + if (device.latestValue("powerSupply") != "USB Cable"){ + result << createEvent(name: "batteryStatus", value: "${map.value} % battery", displayed: false) + } + result } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){ @@ -305,17 +300,23 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + log.debug "ConfigurationReport: $cmd" def result = [] def value - if (cmd.configurationValue[0] == 0) { + if (cmd.parameterNumber == 9 && cmd.configurationValue[0] == 0) { value = "USB Cable" if (!isConfigured()) { log.debug("ConfigurationReport: configuring device") result << response(configure()) } + result << createEvent(name: "batteryStatus", value: value, displayed: false) + result << createEvent(name: "powerSupply", value: value, displayed: false) + }else if (cmd.parameterNumber == 9 && cmd.configurationValue[0] == 1) { + value = "Battery" + result << createEvent(name: "powerSupply", value: value, displayed: false) + } else if (cmd.parameterNumber == 101){ + result << response(configure()) } - if (cmd.configurationValue[0] == 1) {value = "Battery"} - result << createEvent(name: "powerSupply", value: value, displayed: false) result } @@ -326,45 +327,49 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { def configure() { // This sensor joins as a secure device if you double-click the button to include it - if (!state.sec) { - log.debug "${device.displayName} not sending configure until secure" - return [] - } else { - log.debug "${device.displayName} is configuring its settings" - def request = [] + log.debug "${device.displayName} is configuring its settings" + def request = [] - //1. automatic report flags - // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 2 ultraviolet sensor, 1 battery sensor -> send command 227 to get all reports - request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 227) + //1. set association groups for hub + request << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId) - //2. no-motion report x seconds after motion stops (default 20 secs) - request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 20) + request << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) - //3. motionSensitivity 3 levels: 64-normal (default), 127-maximum, 0-minimum - request << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, - scaledConfigurationValue: - motionSensitivity == "normal" ? 64 : - motionSensitivity == "maximum" ? 127 : - motionSensitivity == "minimum" ? 0 : 64) + //2. automatic report flags + // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 2 ultraviolet sensor, 1 battery sensor -> send command 227 to get all reports + request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 226) //association group 1 - //4. report every x minutes (threshold reports don't work on battery power, default 8 mins) - request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) + request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1) //association group 2 - //5. report automatically on threshold change - request << zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: 1) + //3. no-motion report x seconds after motion stops (default 20 secs) + request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 20) - //6. query sensor data - request << zwave.batteryV1.batteryGet() - request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion - request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature - request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance - request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity - request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x1B) //ultravioletIndex + //4. motionSensitivity 3 levels: 64-normal (default), 127-maximum, 0-minimum + request << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, + scaledConfigurationValue: + motionSensitivity == "normal" ? 64 : + motionSensitivity == "maximum" ? 127 : + motionSensitivity == "minimum" ? 0 : 64) - setConfigured("true") + //5. report every x minutes (threshold reports don't work on battery power, default 8 mins) + request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) //association group 1 - commands(request) + ["delay 10000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] - } + request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 6*60*60) //association group 2 + + //6. report automatically on threshold change + request << zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: 1) + + //7. query sensor data + request << zwave.batteryV1.batteryGet() + request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x1B) //ultravioletIndex + + setConfigured("true") + + commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private def getTimeOptionValueMap() { [