diff --git a/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy b/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy index d13faa016c1..26ed7d77b2a 100644 --- a/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy +++ b/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy @@ -31,7 +31,6 @@ metadata { fingerprint mfr: "0258", prod: "0003", model: "008D", deviceJoinName: "NEO Coolcam Motion/Light Sensor" //zw:S type:0701 mfr:0258 prod:0003 model:108D ver:3.80 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,31,71,30,70,85,59,84 role:06 ff:8C07 ui:8C07 EU version fingerprint mfr: "0258", prod: "0003", model: "108D", deviceJoinName: "NEO Coolcam Motion/Light Sensor" - fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Outdoor Floodlight", mmnm: "SmartThings", vid: "generic-motion-light-sensor" } simulator { @@ -90,10 +89,6 @@ def updated() { def configure() { // Device wakes up every deviceCheckInterval hours, this interval allows us to miss one wakeup notification before marking offline sendEvent(name: "checkInterval", value: 2 * deviceWakeUpInterval * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - - if (isEverspringFloodlight()) { - response(zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 600)) //enables illuminance report every 10 minutes - } } def getDeviceWakeUpInterval() { @@ -126,7 +121,7 @@ private getCommandClassVersions() { def parse(String description) { def results = [] if (description.startsWith("Err")) { - results += createEvent(descriptionText: description, displayed: true) + results << createEvent(descriptionText: description, displayed: true) } else { def cmd = zwave.parse(description, commandClassVersions) if (cmd) { @@ -149,9 +144,9 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm def results = [] if (cmd.notificationType == 0x07) { // Burglar if (cmd.event == 0x08) { // detected - results += sensorMotionEvent(1) + results << sensorMotionEvent(1) } else if (cmd.event == 0x00) { // inactive - results += sensorMotionEvent(0) + results << sensorMotionEvent(0) } } return results @@ -167,7 +162,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { } else { map.value = cmd.batteryLevel } - results += createEvent(map) + results << createEvent(map) return results } @@ -184,21 +179,21 @@ def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelR default: map.descriptionText = cmd.toString() } - results += createEvent(map) + results << createEvent(map) return results } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def results = [] - results += createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) - results += response(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1).format()) + results << createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) + results << response(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1).format()) if (!state.lastbatt || (now() - state.lastbatt) >= 10 * 60 * 60 * 1000) { - results += response(["delay 1000", + results << response(["delay 1000", zwave.batteryV1.batteryGet().format(), "delay 2000" ]) } - results += response(zwave.wakeUpV2.wakeUpNoMoreInformation().format()) + results << response(zwave.wakeUpV2.wakeUpNoMoreInformation().format()) return results } @@ -211,13 +206,9 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { def sensorMotionEvent(value) { def result = [] if (value) { - result += createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion") + result << createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion") } else { - result += createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped") + result << createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped") } return result } - -private isEverspringFloodlight() { - zwaveInfo.mfr == "0060" && zwaveInfo.model == "0001" -} diff --git a/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy b/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy new file mode 100644 index 00000000000..a493d983363 --- /dev/null +++ b/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy @@ -0,0 +1,173 @@ +/** + * Copyright 2018 SmartThings + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ + +metadata { + definition(name: "Z-Wave Motion Light", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", mmnm: "SmartThings", vid: "generic-motion-light") { + capability "Switch" + capability "Motion Sensor" + capability "Illuminance Measurement" + capability "Sensor" + capability "Health Check" + capability "Configuration" + + fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Outdoor Floodlight" + } + + tiles(scale: 2) { + multiAttributeTile(name:"switch", type: "lighting", width: 1, height: 1, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState("on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", 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:"#00a0dc", nextState:"turningOff") + attributeState("turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn") + } + } + valueTile("motion", "device.motion", decoration: "flat", width: 2, height: 2) { + state("active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC") + state("inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#CCCCCC") + } + valueTile("illuminance", "device.illuminance", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "illuminance", label: '${currentValue} lux', backgroundColors: [ + [value: 40, color: "#999900"], + [value: 100, color: "#CCCC00"], + [value: 300, color: "#FFFF00"], + [value: 500, color: "#FFFF33"], + [value: 1000, color: "#FFFF66"], + [value: 2000, color: "#FFFF99"], + [value: 10000, color: "#FFFFCC"] + ] + } + + main "switch" + details(["switch", "motion", "illuminance"]) + } +} + +def initialize() { + sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 24 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "motion", value: "inactive", displayed: false) +} + +def installed() { + initialize() +} + +def updated() { + initialize() +} + +def configure() { + def cmds = [ + secure(zwave.notificationV3.notificationGet(notificationType: 0x07)), + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03)), + secure(zwave.switchBinaryV1.switchBinaryGet()) + ] + if (isEverspringFloodlight()) { + cmds += secure(zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 10)) //enables illuminance report every 10 minutes + } + cmds +} + +def ping() { + response(secure(zwave.switchBinaryV1.switchBinaryGet())) +} + +def parse(String description) { + def result = [] + if (description.startsWith("Err")) { + result = createEvent(descriptionText:description, isStateChange:true) + } else { + def cmd = zwave.parse(description) + if (cmd) { + result += zwaveEvent(cmd) + } + } + log.debug "Parse returned: ${result}" + result +} + +def on() { + [ + secure(zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF)), + "delay 500", + secure(zwave.switchBinaryV1.switchBinaryGet()) + ] +} + +def off() { + [ + secure(zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00)), + "delay 500", + secure(zwave.switchBinaryV1.switchBinaryGet()) + ] +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + def map = [name: "switch"] + map.value = cmd.value ? "on" : "off" + map.descriptionText = "${device.displayName} light has been turned ${map.value}" + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationType == 0x07) { + if (cmd.event == 0x08) { // detected + createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion") + } else if (cmd.event == 0x00) { // inactive + createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped") + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + switch (cmd.sensorType) { + case 3: + map.name = "illuminance" + map.value = cmd.scaledSensorValue.toInteger().toString() + map.unit = "lux" + map.isStateChange = true + break + default: + map.descriptionText = cmd.toString() + } + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Unhandled command: ${cmd}" + [:] +} + +private secure(cmd) { + if(zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} + +private isEverspringFloodlight() { + zwaveInfo.mfr == "0060" && zwaveInfo.prod == "0012" +} \ No newline at end of file