Repository: robertvandervoort/SmartThings Branch: master Commit: fd0e7fd4fa09 Files: 41 Total size: 606.3 KB Directory structure: gitextract_nx5lanog/ ├── .gitattributes ├── .gitignore ├── .idea/ │ └── misc.xml ├── Aeon Door and Window Sensor DSB04100-ZWUS/ │ └── Aeon_Door_and_Window_Sensor-DSB04100-ZWUS.groovy ├── Aeon Doorbell/ │ ├── aeon-doorbell-v04.groovy │ ├── device_type-aeon-doorbell-v0.1 │ ├── device_type-aeon-doorbell-v0.2 │ └── device_type-aeon-doorbell-v0.3 ├── Aeon Garage Door/ │ └── device_type-aeon-garage-door-v0.1 ├── Aeon Multisensor 6/ │ ├── device_type-aeon-multisensor6-v1.1 │ ├── device_type-aeon-multisensor6-v1.2 │ ├── device_type-aeon-multisensor6-v1.3 │ ├── device_type-aeon-multisensor6-v1.4 │ ├── device_type-aeon-multisensor6-v1.5 │ ├── device_type-aeon-multisensor6-v2.0 │ ├── device_type-aeon-multisensor6-v2.1 │ ├── device_type-aeon-multisensor6-v2.2 │ ├── device_type-aeon-multisensor6-v2.3 │ └── device_type-aeon-multisensor6-v2.3.1 ├── Aeon SmartDimmer 6/ │ ├── device_type-aeon-smartdimmer6-v0.1 │ ├── device_type-aeon-smartdimmer6-v0.1-ANDROID │ └── device_type-aeon-smartdimmer6-v0.2.groovy ├── Aeon SmartSwitch 6/ │ ├── device_type-aeon-smartswitch6-v0.1 │ ├── device_type-aeon-smartswitch6-v0.2 │ ├── device_type-aeon-smartswitch6-v0.4 │ └── device_type-aeon-smartswitch6-v0.4-ANDROID ├── GE Z-Wave Switch - Improved/ │ └── device_type-GE-Z-Wave-Switch-Improved ├── zooZ-4-in-1-Sensor-ZSE40/ │ ├── device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2 │ └── device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2_motion_primary ├── zooZ-Indoor-Siren-ZSE01/ │ ├── device_type-zooZ-indoor-siren-v1 │ ├── device_type-zooZ-indoor-siren-v1.1 │ └── device_type-zooZ-indoor-siren-v1.2 ├── zooZ-MiniPlug-ZEN07/ │ ├── device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2.groovy │ ├── device_type-zooZ-MiniPlug-ZEN07-v1.1.groovy │ ├── device_type-zooZ-MiniPlug-ZEN07-v1.2.groovy │ ├── device_type-zooZ-MiniPlug-ZEN07-v1.3.groovy │ └── device_type-zooZ-MiniPlug-ZEN07-v1.4.groovy ├── zooZ-Motion-Sensor-ZSE02/ │ ├── device_type-zooZ-Motion-Sensor-ZSE02_v1 │ ├── device_type-zooZ-Motion-Sensor-ZSE02_v1.1 │ └── device_type-zooZ-Motion-Sensor-ZSE02_v1.2 └── zooZ-Strip-ZEN20/ └── device_type-zooZ-strip-ZEN20_v1.0 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ Aeon Doorbell/device_type-aeon-doorbell-v0.4 zooZ-MiniPlug-ZEN07/device_type-zooZ-MiniPlug-ZEN07.groovy ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: Aeon Door and Window Sensor DSB04100-ZWUS/Aeon_Door_and_Window_Sensor-DSB04100-ZWUS.groovy ================================================ /** * Copyright 2015 SmartThings and 2016 Robert Vandervoort * * 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. * * Aeon Labs DSB04100-ZWUS - Z-Wave Door & Window Sensor * * Author: SmartThings and Robert Vandervoort * Date: 7-17-2016 */ metadata { definition (name: "Aeon Labs DSB04100-ZWUS - Z-Wave Door & Window Sensor - RV", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Contact Sensor" capability "Tamper Alert" capability "Sensor" capability "Battery" capability "Configuration" // RAW ID 0 0 0x0701 0 0 0 f 0x5E 0x86 0x72 0x85 0x59 0x73 0x71 0x84 0x30 0x80 0x70 0x98 0x7A 0xEF 0x5A fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x85,0x59,0x73,0x71,0x84,0x30,0x80,0x70,0x98,0x7A,0xEF,0x5A" } simulator { // status messages status "open": "command: 2001, payload: FF" status "closed": "command: 2001, payload: 00" status "wake up": "command: 8407, payload: " status "detected": "command: 7105, payload: 000000FF07030000" status "clear": "command: 7105, payload: 000000FF07000000" } tiles { standardTile("contact", "device.contact", width: 2, height: 2) { state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e" state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821" } standardTile("tamper", "device.tamper", width: 2, height: 2) { state "detected", label: '${currentValue}', icon: "st.motion.acceleration.active", backgroundColor: "#ff0000" state "clear", label: '${currentValue}', icon: "st.motion.acceleration.inactive", backgroundColor: "#00ff00" } valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } main "contact" details(["contact", "tamper", "battery"]) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { if (state.sec) { log.debug description } else { result = createEvent( 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.", eventType: "ALERT", name: "secureInclusion", value: "failed", isStateChange: true, ) } } else if (description != "updated") { def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "parsed '$description' to $result" return result } def updated() { def cmds = [] if (!state.MSR) { cmds = [ command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()), "delay 1200", zwave.wakeUpV1.wakeUpNoMoreInformation().format() ] } else if (!state.lastbat) { cmds = [] } else { cmds = [zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } response(cmds) } def configure() { commands([ zwave.manufacturerSpecificV2.manufacturerSpecificGet(), zwave.batteryV1.batteryGet() ], 6000) } def sensorValueEvent(value) { if (value) { createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open") } else { createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed") } result } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { sensorValueEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { sensorValueEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 0x07) { if (cmd.event == 0x03) { result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was removed.", isStateChange: true) if(!state.MSR) result << response(command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())) } else if (cmd.event == 0x00) { result << createEvent(name: "tamper", value: "clear", descriptionText: "$device.displayName was replaced.", isStateChange: true) if(!state.MSR) result << response(command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())) } else if (cmd.notificationType == 0x06 && cmd.event == 0x16) { result << sensorValueEvent(1) } else if (cmd.notificationType == 0x06 && cmd.event == 0x17) { result << sensorValueEvent(0) } result } result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def event = createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false) def cmds = [] if (!state.MSR) { cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) cmds << "delay 1200" } if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) { cmds << command(zwave.batteryV1.batteryGet()) } else { cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() } [event, response(cmds)] } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} has a low battery" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbat = now() [createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())] } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { def result = [] def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) log.debug "msr: $msr" updateDataValue("MSR", msr) result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false) } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1]) // log.debug "encapsulated: $encapsulatedCommand" if (encapsulatedCommand) { state.sec = 1 zwaveEvent(encapsulatedCommand) } } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: "$device.displayName: $cmd", displayed: false) } private command(physicalgraph.zwave.Command cmd) { if (state.sec == 1) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=200) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Doorbell/aeon-doorbell-v04.groovy ================================================ /* * V 0.4 of Aeon Doorbell code 10/4/2017 * 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. * * Changelog: * v 0.1 - initial push of device type, ability to change ring tone, volume and number of rings, basic set reporting * for use as a switch to trigger stuff, and ability to trigger as an alarm * v 0.2 - added separate preference for alarm triggering so a different ringtone can be used for alarm VS doorbell. created * separate test buttons for doorbell and alarm * v 0.3 - added firmware version and checksum reporting as part of the config command, modifed the way the battery check works, may need to redress it later * v 0.4 - added motion activation capability when doorbell or alerm is rung. you can use this to trigger smart home monitor by adding the doorbell as a motion * sensor and have this trigger a siren or another doorbell's alrm tone for multi doorbell houses */ metadata { definition (name: "Aeon Doorbell - RV v0.4", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Configuration" capability "Refresh" capability "Music Player" capability "Motion Sensor" command "atest" command "btest" command "getbatt" command "setRingtone" fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98" } // simulator metadata simulator { /*status "battery good": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 0 ) ).incomingMessage() status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 255 ) ).incomingMessage() */ reply "9881002001FF,9881002002": "command: 9881, payload: 002003FF" reply "988100200100,9881002002": "command: 9881, payload: 00200300" reply "9881002001FF,delay 3000,988100200100,9881002002": "command: 9881, payload: 00200300" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true, canChangeBackground: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'alarm.on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'RINGING', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("btest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'bell', action:"btest", icon:"st.Electronics.electronics14" } standardTile("atest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'alarm', action:"atest", icon:"st.Electronics.electronics14" } standardTile("off", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'Battery', action:"getbatt", backgroundColors:[ [value: 0, color: "#FF0000"], [value: 100, color: "#00FF00"] ] } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } valueTile("testSoundLabel", "device.battery", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { state "battery", label:'Test Sound:', unit:"" } controlTile("testSoundSlider", "device.playTrack", "slider", width: 4, height: 2, inactiveLabel: false, range:"(1..99)") { state "testSound", action:"playTrack", backgroundColor: "#1e9cbb" } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } main "alarm" details(["alarm","btest","atest","off","testSoundLabel","testSoundSlider","battery","setRingtone","setVolume","refresh","motion","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "prefRingtone", "integer", title: "Doorbell tone:", description: "Pick the ringtone, 1-100", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true input "prefAlarmtone", "integer", title: "Alarm tone:", description: "Pick the alarm tone, 1-100", defaultValue: 6, range: "1..100", required: false, displayduringSetup: true input "prefVolume", "integer", title: "Doorbell volume:", description: "Set the volume of the doorbell", defaultValue: 10, range: "0..10", required: false, displayduringSetup: true input "prefNumrings", "integer", title: "Ring repetitions:", description: "How many times to ring per push of the doorbell", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true input "motionEnabled", "boolean", title: "Motion event on ring?", description: "Generate motion for triggering other doorbells or alarm", defaultValue: false, required: false, displayduringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x7A: 2, 0x82: 1, 0x85: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x7A: 2, 0x82: 1, 0x85: 2, 0x86: 1]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.firmwareupdatemdv2.FirmwareMdReport cmd) { if (state.debug) log.debug "---FIRMWARE MD REPORT V2--- ${device.displayName} has Checksum of ${cmd.checksum} firmwareId: ${cmd.firmwareId}, manufacturerId: ${cmd.firmwareId}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" def map = [ name: "battery", value: 100] if (cmd.parameterNumber == 42) { if (cmd.configurationValue == [255]) { map.value = 0 map.descriptionText = "${device.displayName} remote battery is low" if (state.debug) log.debug "${device.displayName} remote battery is low" map.isStateChange = true } else { map.value = 100 map.descriptionText = "${device.displayName} remote battery is good" if (state.debug) log.debug "${device.displayName} remote battery is good" map.isStateChange = true } } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "AssociationReport: '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "Hail received: ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "doorbell value:${cmd.value}"; sendEvent(name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true, descriptiontext: "doorbell"); sendEvent(name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true); if (motionEnabled == "true") { if (cmd.value == 255) { sendEvent(name: "motion", value: "active", displayed: true, isStateChange: true) } else { sendEvent(name: "motion", value: "inactive", displayed: true, isStateChange: true) } } } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug cmd createEvent(name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true) } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug cmd createEvent(name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true) } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug cmd createEvent(name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true) } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def getbatt() { if (state.debug) log.debug "Getting battery level for remote control on ${device.displayName}" def request = [ zwave.configurationV1.configurationGet(parameterNumber: 42) ] commands(request) } def btest() { if (state.debug) log.debug "Testing doorbell ring ${prefRingtone} on ${device.displayName}" on() } def atest() { if (state.debug) log.debug "Testing alarm sound ${prefAlarmtone} on ${device.displayName}" both() } def playTrack(track) { disableNotifications() def request = [ zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: track.toInteger()) ] commands(request) } def disableNotifications() { state.notification = false } def setRingtone(track) { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: track) ] commands(request) } def strobe() { if (state.debug) log.debug "Strobe command received" on() } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Alarm test command received" def request = [ zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: prefAlarmtone.toInteger()) ] commands(request) } def on() { if (state.debug) log.debug "Ringing ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF) ] commands(request) if (state.notification) { sendEvent(name: "switch", value: "on", type: "physical", displayed: true, isStateChange: true) if (state.debug) log.debug "${device.displayName} has been rung from button." } else { if (state.debug) log.debug "${device.displayName} has been rung from playTrack." } } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) if (state.notification) sendEvent(name: "switch", value: "off", type: "physical", displayed: true, isStateChange: true) state.notification = true } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def configure() { if (state.debug) { log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } if (!state.prefRingtone) state.prefRingtone = 1 if (!state.prefAlarmtone) state.prefAlarmtone = 6 if (!state.prefVolume) state.prefVolume = 10 if (!state.prefNumrings) state.prefNumrings = 1 log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ //associate with group 1 and remove any group 2 association //zwave.associationV1.associationRemove(groupingIdentifier:2, nodeId:zwaveHubNodeId), //zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId), zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // Enable to send notifications to associated devices (Group 1) (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, scaledConfigurationValue: 2), zwave.configurationV1.configurationGet(parameterNumber: 80), // send low battery notifications zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 81), // Set the repetitions for playing doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: prefNumrings.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 2), // Set the default doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: prefRingtone.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 5), // Set the volume of ringtone zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: prefVolume.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 8), // define +- button function zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 10), zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 11), // Get last known remote battery health zwave.configurationV1.configurationGet(parameterNumber: 42) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Doorbell/device_type-aeon-doorbell-v0.1 ================================================ /* * V 0.1 of Aeon Doorbell code 11/24/2015 * 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: "Aeon Doorbell - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Switch" capability "Configuration" capability "Refresh" command "test" fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98" } // simulator metadata simulator { for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() reply "9881002001FF,9881002002": "command: 9881, payload: 002003FF" reply "988100200100,9881002002": "command: 9881, payload: 00200300" reply "9881002001FF,delay 3000,988100200100,9881002002": "command: 9881, payload: 00200300" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'off', action:'alarm.siren', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'alarm!', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("test", "device.alarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"test", icon:"st.secondary.test" } standardTile("off", "device.alarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "alarm" details(["alarm","test","off","battery","setRingtone","setVolume","refresh","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "prefRingtone", "integer", title: "Doorbell tone:", description: "Pick the ringtone, 1-100", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true input "prefVolume", "integer", title: "Doorbell volume:", description: "Set the volume of the doorbell", defaultValue: 10, range: "1..10", required: false, displayduringSetup: true input "prefNumrings", "integer", title: "Ring repetitions:", description: "How many times to ring per push of the doorbell", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "AssociationReport: '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) [:] } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "Hail received: ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "doorbell value:${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def test() { if (state.debug) log.debug "Ringing ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet() ] commands(request) } def strobe() { if (state.debug) log.debug "Strobe command received" on() } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Both command received" on() } def on() { if (state.debug) log.debug "Ringing ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet() ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } if (!state.prefRingtone) state.prefRingtone = 1 if (!state.prefVolume) state.prefVolume = 10 if (!state.prefNumrings) state.prefNumrings = 1 log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ //associate with group 1 and remove any group 2 association zwave.associationV1.associationRemove(groupingIdentifier:2, nodeId:zwaveHubNodeId), zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId), zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Enable to send notifications to associated devices (Group 1) (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, scaledConfigurationValue: 2), zwave.configurationV1.configurationGet(parameterNumber: 80), // send low battery notifications zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 81), // Set the repetitions for playing doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: prefNumrings.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 2), // Set the default doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: prefRingtone.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 5), // Set the volume of ringtone zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: prefVolume.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 8), // define +- button function zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 10), zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 11) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Doorbell/device_type-aeon-doorbell-v0.2 ================================================ /* * V 0.2 of Aeon Doorbell code 11/24/2015 * 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. * * Changelog: * v 0.1 - initial push of device type, ability to change ring tone, volume and number of rings, basic set reporting * for use as a switch to trigger stuff, and ability to trigger as an alarm * v 0.2 - added separate preference for alarm triggering so a different ringtone can be used for alarm VS doorbell. created * separate test buttons for doorbell and alarm, battery tile now gets last known remote battery state and displays red or green for bad / good */ metadata { definition (name: "Aeon Doorbell - RV v0.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Configuration" capability "Refresh" command "atest" command "btest" command "getbatt" fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98" } // simulator metadata simulator { /*status "battery good": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 0 ) ).incomingMessage() status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 255 ) ).incomingMessage() */ reply "9881002001FF,9881002002": "command: 9881, payload: 002003FF" reply "988100200100,9881002002": "command: 9881, payload: 00200300" reply "9881002001FF,delay 3000,988100200100,9881002002": "command: 9881, payload: 00200300" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true, canChangeBackground: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'alarm.on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'RINGING', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("btest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'bell', action:"btest", icon:"st.Electronics.electronics14" } standardTile("atest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'alarm', action:"atest", icon:"st.Electronics.electronics14" } standardTile("off", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'Battery', action:"getbatt", backgroundColors:[ [value: 0, color: "#FF0000"], [value: 100, color: "#00FF00"] ] } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "alarm" details(["alarm","btest","atest","off","battery","setRingtone","setVolume","refresh","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "prefRingtone", "integer", title: "Doorbell tone:", description: "Pick the ringtone, 1-100", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true input "prefAlarmtone", "integer", title: "Alarm tone:", description: "Pick the alarm tone, 1-100", defaultValue: 6, range: "1..100", required: false, displayduringSetup: true input "prefVolume", "integer", title: "Doorbell volume:", description: "Set the volume of the doorbell", defaultValue: 10, range: "1..10", required: false, displayduringSetup: true input "prefNumrings", "integer", title: "Ring repetitions:", description: "How many times to ring per push of the doorbell", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" def map = [ name: "battery"] if (cmd.parameterNumber == 42 && cmd.configurationValue == 0xFF) { map.value = 0 map.descriptionText = "${device.displayName} remote battery is low" if (state.debug) log.debug "${device.displayName} remote battery is low" map.isStateChange = true } else { map.value = 100 map.descriptionText = "${device.displayName} remote battery is good" if (state.debug) log.debug "${device.displayName} remote battery is good" map.isStateChange = true } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "AssociationReport: '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) [:] } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "Hail received: ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "doorbell value:${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def getbatt() { if (state.debug) log.debug "Getting battery level for remote control on ${device.displayName}" def request = [ zwave.configurationV1.configurationGet(parameterNumber: 42) ] commands(request) } def btest() { if (state.debug) log.debug "Testing doorbell ring ${prefRingtone} on ${device.displayName}" on() } def atest() { if (state.debug) log.debug "Testing alarm sound ${prefAlarmtone} on ${device.displayName}" both() } def strobe() { if (state.debug) log.debug "Strobe command received" on() } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Alarm test command received" def request = [ zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: prefAlarmtone.toInteger()) ] commands(request) } def on() { if (state.debug) log.debug "Ringing ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF) ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } if (!state.prefRingtone) state.prefRingtone = 1 if (!state.prefRingtone) state.prefAlarmtone = 1 if (!state.prefVolume) state.prefVolume = 10 if (!state.prefNumrings) state.prefNumrings = 1 log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ //associate with group 1 and remove any group 2 association //zwave.associationV1.associationRemove(groupingIdentifier:2, nodeId:zwaveHubNodeId), //zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId), zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Enable to send notifications to associated devices (Group 1) (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, scaledConfigurationValue: 2), zwave.configurationV1.configurationGet(parameterNumber: 80), // send low battery notifications zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 81), // Set the repetitions for playing doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: prefNumrings.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 2), // Set the default doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: prefRingtone.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 5), // Set the volume of ringtone zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: prefVolume.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 8), // define +- button function zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 10), zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 11) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Doorbell/device_type-aeon-doorbell-v0.3 ================================================ /* * V 0.3 of Aeon Doorbell code 11/24/2015 * 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. * * Changelog: * v 0.1 - initial push of device type, ability to change ring tone, volume and number of rings, basic set reporting * for use as a switch to trigger stuff, and ability to trigger as an alarm * v 0.2 - added separate preference for alarm triggering so a different ringtone can be used for alarm VS doorbell. created * separate test buttons for doorbell and alarm * v 0.3 - added firmware version and checksum reporting as part of the config command, modifed the way the battery check works, may need to redress it later */ metadata { definition (name: "Aeon Doorbell - RV v0.3", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Configuration" capability "Refresh" command "atest" command "btest" command "getbatt" fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98" } // simulator metadata simulator { /*status "battery good": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 0 ) ).incomingMessage() status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( zwave.configurationV1.configurationReport( parameterNumber: 42, configurationValue: 255 ) ).incomingMessage() */ reply "9881002001FF,9881002002": "command: 9881, payload: 002003FF" reply "988100200100,9881002002": "command: 9881, payload: 00200300" reply "9881002001FF,delay 3000,988100200100,9881002002": "command: 9881, payload: 00200300" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true, canChangeBackground: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'alarm.on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'RINGING', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("btest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'bell', action:"btest", icon:"st.Electronics.electronics14" } standardTile("atest", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'alarm', action:"atest", icon:"st.Electronics.electronics14" } standardTile("off", "device.alarm", inactiveLabel: false, width: 2, height: 2) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'Battery', action:"getbatt", backgroundColors:[ [value: 0, color: "#FF0000"], [value: 100, color: "#00FF00"] ] } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "alarm" details(["alarm","btest","atest","off","battery","setRingtone","setVolume","refresh","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "prefRingtone", "integer", title: "Doorbell tone:", description: "Pick the ringtone, 1-100", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true input "prefAlarmtone", "integer", title: "Alarm tone:", description: "Pick the alarm tone, 1-100", defaultValue: 6, range: "1..100", required: false, displayduringSetup: true input "prefVolume", "integer", title: "Doorbell volume:", description: "Set the volume of the doorbell", defaultValue: 10, range: "1..10", required: false, displayduringSetup: true input "prefNumrings", "integer", title: "Ring repetitions:", description: "How many times to ring per push of the doorbell", defaultValue: 1, range: "1..100", required: false, displayduringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x7A: 2, 0x82: 1, 0x85: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x7A: 2, 0x82: 1, 0x85: 2, 0x86: 1]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.firmwareupdatemdv2.FirmwareMdReport cmd) { if (state.debug) log.debug "---FIRMWARE MD REPORT V2--- ${device.displayName} has Checksum of ${cmd.checksum} firmwareId: ${cmd.firmwareId}, manufacturerId: ${cmd.firmwareId}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" def map = [ name: "battery"] if (cmd.parameterNumber == 42) { if (cmd.configurationValue == [255]) { map.value = 0 map.descriptionText = "${device.displayName} remote battery is low" if (state.debug) log.debug "${device.displayName} remote battery is low" map.isStateChange = true } else { map.value = 100 map.descriptionText = "${device.displayName} remote battery is good" if (state.debug) log.debug "${device.displayName} remote battery is good" map.isStateChange = true } } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "AssociationReport: '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "Hail received: ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "doorbell value:${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug cmd [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def getbatt() { if (state.debug) log.debug "Getting battery level for remote control on ${device.displayName}" def request = [ zwave.configurationV1.configurationGet(parameterNumber: 42) ] commands(request) } def btest() { if (state.debug) log.debug "Testing doorbell ring ${prefRingtone} on ${device.displayName}" on() } def atest() { if (state.debug) log.debug "Testing alarm sound ${prefAlarmtone} on ${device.displayName}" both() } def strobe() { if (state.debug) log.debug "Strobe command received" on() } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Alarm test command received" def request = [ zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: prefAlarmtone.toInteger()) ] commands(request) } def on() { if (state.debug) log.debug "Ringing ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF) ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } if (!state.prefRingtone) state.prefRingtone = 1 if (!state.prefRingtone) state.prefAlarmtone = 1 if (!state.prefVolume) state.prefVolume = 10 if (!state.prefNumrings) state.prefNumrings = 1 log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ //associate with group 1 and remove any group 2 association //zwave.associationV1.associationRemove(groupingIdentifier:2, nodeId:zwaveHubNodeId), //zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId), zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // Enable to send notifications to associated devices (Group 1) (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, scaledConfigurationValue: 2), zwave.configurationV1.configurationGet(parameterNumber: 80), // send low battery notifications zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 81), // Set the repetitions for playing doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: prefNumrings.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 2), // Set the default doorbell ringtone zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: prefRingtone.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 5), // Set the volume of ringtone zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: prefVolume.toInteger()), zwave.configurationV1.configurationGet(parameterNumber: 8), // define +- button function zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 10), zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 11), // Get last known remote battery health zwave.configurationV1.configurationGet(parameterNumber: 42) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Garage Door/device_type-aeon-garage-door-v0.1 ================================================ /* * V 0.1 of Aeon Garage Door code 12/15/2015 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * * change log: * v 0.1 */ metadata { definition (name: "Aeon Garage Door - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Alarm" // 0x71 Notification v4 capability "Battery" capability "Switch" // 0x25 Switch Binary v1 capability "Configuration" // 0x70 Configuration v1 capability "Actuator" capability "Door Control" capability "Garage Door Control" capability "Contact Sensor" capability "Refresh" capability "Sensor" command "calibrate" /* 0x22 Application Status v1 0x5E Zwave Gen 5 v2 0x85 Association v2 0x59 Association Grp Info v1 0x72 Manufacturer Specific v2 0x86 Version v1 0x7A Firmware Update Md v2 0x73 Powerlevel v1 0x98 Security v1 0x66 BARRIER_OPERATOR v1 0xEF Mark v1 0x5A Device Reset Locally v1 0x82 Hail v1 */ // Raw description // 0 0 0x4007 0 0 0 10 0x5E 0x25 0x70 0x85 0x59 0x72 0x86 0x7A 0x73 0x98 0x66 0xEF 0x22 0x5A 0x82 fingerprint deviceId: "0x10", inClusters: "0x98" fingerprint inClusters: "0x5E, 0x25, 0x70, 0x85, 0x59, 0x72, 0x86, 0x7A, 0x73, 0x98, 0x66, 0x71, 0xEF, 0x22, 0x5A", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.door", key: "PRIMARY_CONTROL") { attributeState "unknown", label:'${name}', action:"refresh.refresh", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e" attributeState "closed", label:'${name}', action:"door control.open", icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821", nextState:"opening" attributeState "open", label:'${name}', action:"door control.close", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e", nextState:"closing" attributeState "opening", label:'${name}', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e" attributeState "closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e" } } standardTile("open", "device.door", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'open', action:"door control.open", icon:"st.doors.garage.garage-opening" } standardTile("close", "device.door", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'close', action:"door control.close", icon:"st.doors.garage.garage-closing" } standardTile("configure", "device.door", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.door", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh", icon:"st.secondary.refresh" } main "main" details(["main","open","close","refresh","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } import physicalgraph.zwave.commands.barrieroperatorv1.* def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x5E: 2, 0x25: 1, 0x70: 1, 0x85: 2, 0x59: 1, 0x72: 2, 0x86: 1, 0x7A: 2, 0x73: 1, 0x98: 1, 0x66: 1, 0x71: 4, 0xEF: 1, 0x22: 1, 0x5A: 1]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x5E: 2, 0x25: 1, 0x70: 1, 0x85: 2, 0x59: 1, 0x72: 2, 0x86: 1, 0x7A: 2, 0x73: 1, 0x98: 1, 0x66: 1, 0x71: 4, 0xEF: 1, 0x22: 1, 0x5A: 1]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.firmwareupdatemdv2.FirmwareMdReport cmd) { if (state.debug) log.debug "---FIRMWARE MD REPORT V2--- ${device.displayName} has Checksum of ${cmd.checksum} firmwareId: ${cmd.firmwareId}, manufacturerId: ${cmd.firmwareId}" } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "AssociationReport: '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "Hail received: ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { def result = [] def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) log.debug "msr: $msr" updateDataValue("MSR", msr) result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false) result } def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationBusy cmd) { def msg = cmd.status == 0 ? "try again later" : cmd.status == 1 ? "try again in $cmd.waitTime seconds" : cmd.status == 2 ? "request queued" : "sorry" createEvent(displayed: true, descriptionText: "$device.displayName is busy, $msg") } def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationRejectedRequest cmd) { createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(BarrierOperatorReport cmd) { def result = [] def map = [ name: "door" ] switch (cmd.barrierState) { case BarrierOperatorReport.BARRIER_STATE_CLOSED: map.descriptionText = "$device.displayName door is closed" map.value = "closed" result << createEvent(name: "contact", value: "closed", displayed: false) break case BarrierOperatorReport.BARRIER_STATE_UNKNOWN_POSITION_MOVING_TO_CLOSE: map.descriptionText = "$device.displayName door is closing" map.value = "closing" break case BarrierOperatorReport.BARRIER_STATE_UNKNOWN_POSITION_STOPPED: map.descriptionText = "$device.displayName door state is unknown" map.value = "unknown" break case BarrierOperatorReport.BARRIER_STATE_UNKNOWN_POSITION_MOVING_TO_OPEN: map.descriptionText = "$device.displayName door is opening" map.value = "opening" result << createEvent(name: "contact", value: "open", displayed: false) break case BarrierOperatorReport.BARRIER_STATE_OPEN: map.descriptionText = "$device.displayName door is open" map.value = "open" result << createEvent(name: "contact", value: "open", displayed: false) break } if (state.debug) log.debug "---BARRIER OPERATOR REPORT--- ${map.descriptionText}" result + createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] def map = [:] if (cmd.notificationType == 6) { map.displayed = true switch(cmd.event) { case 0x40: if (cmd.eventParameter[0]) { map.descriptionText = "$device.displayName performing initialization process" } else { map.descriptionText = "$device.displayName initialization process complete" } break case 0x41: map.descriptionText = "$device.displayName door operation force has been exceeded" break case 0x42: map.descriptionText = "$device.displayName motor has exceeded operational time limit" break case 0x43: map.descriptionText = "$device.displayName has exceeded physical mechanical limits" break case 0x44: map.descriptionText = "$device.displayName unable to perform requested operation (UL requirement)" break case 0x45: map.descriptionText = "$device.displayName remote operation disabled (UL requirement)" break case 0x46: map.descriptionText = "$device.displayName failed to perform operation due to device malfunction" break case 0x47: if (cmd.eventParameter[0]) { map.descriptionText = "$device.displayName vacation mode enabled" } else { map.descriptionText = "$device.displayName vacation mode disabled" } break case 0x48: if (cmd.eventParameter[0]) { map.descriptionText = "$device.displayName safety beam obstructed" } else { map.descriptionText = "$device.displayName safety beam obstruction cleared" } break case 0x49: if (cmd.eventParameter[0]) { map.descriptionText = "$device.displayName door sensor ${cmd.eventParameter[0]} not detected" } else { map.descriptionText = "$device.displayName door sensor not detected" } break case 0x4A: if (cmd.eventParameter[0]) { map.descriptionText = "$device.displayName door sensor ${cmd.eventParameter[0]} has a low battery" } else { map.descriptionText = "$device.displayName door sensor has a low battery" } result << createEvent(name: "battery", value: 1, unit: "%", descriptionText: map.descriptionText) break case 0x4B: map.descriptionText = "$device.displayName detected a short in wall station wires" break case 0x4C: map.descriptionText = "$device.displayName is associated with non-Z-Wave remote control" break default: map.descriptionText = "$device.displayName: access control alarm $cmd.event" map.displayed = false break } } else if (cmd.notificationType == 7) { switch (cmd.event) { case 1: case 2: map.descriptionText = "$device.displayName detected intrusion" break case 3: map.descriptionText = "$device.displayName tampering detected: product cover removed" break case 4: map.descriptionText = "$device.displayName tampering detected: incorrect code" break case 7: case 8: map.descriptionText = "$device.displayName detected motion" break default: map.descriptionText = "$device.displayName: security alarm $cmd.event" map.displayed = false } } else if (cmd.notificationType){ map.descriptionText = "$device.displayName: alarm type $cmd.notificationType event $cmd.event" } else { map.descriptionText = "$device.displayName: alarm $cmd.v1AlarmType is ${cmd.v1AlarmLevel == 255 ? 'active' : cmd.v1AlarmLevel ?: 'inactive'}" } result ? [createEvent(map), *result] : createEvent(map) if (state.debug) log.debug result } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def open() { def request = [ zwave.barrierOperatorV1.barrierOperatorSet(requestedBarrierState: BarrierOperatorSet.REQUESTED_BARRIER_STATE_OPEN) ] commands(request) } def close() { def request = [ zwave.barrierOperatorV1.barrierOperatorSet(requestedBarrierState: BarrierOperatorSet.REQUESTED_BARRIER_STATE_CLOSE) ] commands(request) } def refresh() { def request = [ // get battery state zwave.configurationV1.configurationGet(parameterNumber: 42), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.barrierOperatorV1.barrierOperatorGet() ] commands(request) } def configure() { if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}, zwaveHubNodeId: ${zwaveHubNodeId}}" def request = [ //associate with group 1 and 2 //zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId), //zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId), zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), zwave.configurationV1.configurationGet(parameterNumber: 80), //set startup tone zwave.configurationV1.configurationSet(parameterNumber: 32, size: 1, configurationValue: [1]), zwave.configurationV1.configurationGet(parameterNumber: 32), //get number of alarm tone zwave.configurationV1.configurationGet(parameterNumber: 36), // Set blink, sound, volume of opening action zwave.configurationV1.configurationSet(parameterNumber: 37, size: 4, configurationValue: [5,1,1,1]), zwave.configurationV1.configurationGet(parameterNumber: 37), // set blink, sound, volume of closing action zwave.configurationV1.configurationSet(parameterNumber: 38, size: 4, configurationValue: [10,2,1,1]), zwave.configurationV1.configurationGet(parameterNumber: 38), // set blink, sound, volume of unknown state zwave.configurationV1.configurationSet(parameterNumber: 39, size: 4, configurationValue: [1,3,1,0]), zwave.configurationV1.configurationGet(parameterNumber: 39), // set blink, sound, volume of CLOSED state zwave.configurationV1.configurationSet(parameterNumber: 40, size: 4, configurationValue: [1,3,1,0]), zwave.configurationV1.configurationGet(parameterNumber: 40), // get battery state zwave.configurationV1.configurationGet(parameterNumber: 42), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v1.1 ================================================ /** * V 1.1 of Multisensor 6 code * known issues : preferences do not seem to affect configuration, secure pairing is the most tested method at the moment. when clicking the action button on * the sensor, click two times quickly to pair secured. Still not seeing anything other than 0 for ultraviolet. Also, temp and humidity seem to be off about 6 * degrees warmer and 7 percent humidity lower than actual, though your sensor may vary. * Original code for gen5 Copyright 2015 SmartThings, modified for use on gen 6 by Robert Vandervoort * * 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: "Aeon Multisensor 6", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Configuration" capability "Sensor" capability "Battery" fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "no vibration" : " command: 9881, payload: 0071050000000007030000" status "vibration" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 20, 89, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultraviolet ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles { standardTile("motion","device.motion") { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature",inactiveLabel: false) { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "humidity","device.humidity",inactiveLabel: false) { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile( "illuminance","device.illuminance",inactiveLabel: false) { state "luminosity",label:'${currentValue} ${unit}',unit:"lux" } valueTile( "ultraviolet","device.ultraviolet",inactiveLabel: false) { state "ultraviolet",label:'UV ${currentValue} ${unit}',unit:"" } standardTile( "vibration","device.vibration") { state "active",label:'vibration',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "inactive",label:'calm',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", inactiveLabel: false, decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configureAfterSecure","device.configure",inactiveLabel: false,decoration: "flat") { state "configure",label:'',action:"configureAfterSecure",icon:"st.secondary.configure" } main([ "motion","temperature","humidity","illuminance","ultraviolet" ]) details([ "motion","temperature","humidity","illuminance","ultraviolet","battery","configureAfterSecure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-127 low to high sensitivity", defaultValue: 64, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data every X seconds", description: "A value in seconds, default is 60 / 8 minutes", defaultValue: 4, required: true, displayDuringSetup: true } } def parse(String description) { def result = null if (description == "updated") { result = null } else { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("not sending wakeUpNoMoreInformation yet") result += response(configureAfterSecure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { log.debug "Received SecurityCommandsSupportedReport" response(configureAfterSecure()) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = new Date().time createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultraviolet" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value == 255) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def vibrationEvent(value) { def map = [name: "vibration"] if (value == 255) { map.value = "active" map.descriptionText = "$device.displayName detected vibration" } else { log.debug "-------------Vibration inactive------------------" map.value = "inactive" map.descriptionText = "$device.displayName vibration has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { log.debug "Basic Set 255 triggered motion event" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (cmd.notificationType == 7 && cmd.event == 8) { log.debug "notification type 7 event 8 triggered motion event" motionEvent(cmd.notificationStatus) } else if (cmd.notificationType == 7 && cmd.event == 0) { log.debug "notification type 7 event 0 motion and vibration cleared" motionEvent(cmd.notificationStatus) vibrationEvent(cmd.notificationStatus) } else if (cmd.notificationType == 7 && cmd.event == 3) { log.debug "notification type 7 event 3 triggered vibration event" vibrationEvent(cmd.notificationStatus) } else { createEvent(descriptionText: cmd.toString(), isStateChange: false) } } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configureAfterSecure() { log.debug "configureAfterSecure()" //log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 64 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 4 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset.toInteger() } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset.toInteger() } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset.toInteger() } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset.toInteger() } //log.debug "PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // send temperature, humidity, illuminance, ultraviolet and battery zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16|1), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // configure PIR sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x06,size: 1, scaledConfigurationValue: PIRsens), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 60 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 60), // enable motion sensor zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: 0), // send binary sensor report instead of basic set for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of vibration sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: ultravioletoff), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] setConfigured() //log.debug request secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } def configure() { //["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet()) log.debug "configure()" def reportIntervalSecs = 4; if (reportInterval) { reportIntervalSecs = reportInterval.toInteger() } delayBetween([ // send temperature, humidity, illuminance, ultraviolet and battery every 8 minutes or as defined by preference zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16|1).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x6F, size: 4, scaledConfigurationValue: reportIntervalSecs).format(), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60).format(), // send no-motion report 60 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 60).format(), // enable motion sensor zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: 0).format(), // send binary sensor report instead of basic set for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2).format(), // configure PIR sensitivity for multisensor 6 min to max 0-127 default 64 zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: 64).format(), // Enable the function of vibration sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1).format(), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0).format(), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: 20).format(), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: 20).format(), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: 0).format(), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: 5).format(), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ]) setConfigured() zwave.wakeUpV1.wakeUpNoMoreInformation().format() } def setConfigured() { device.updateDataValue("configured", "true") } def isConfigured() { Boolean configured = device.getDataValue(["configured"]) as Boolean return configured } private secure(physicalgraph.zwave.Command cmd) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } private secureSequence(commands, delay=200) { delayBetween(commands.collect{ secure(it) }, delay) } def updated() { log.debug "updated()" log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" configureAfterSecure() } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v1.2 ================================================ /** * V 1.2 of Multisensor 6 code * known issues : preferences do not seem to affect configuration, * Not seeing anything other than 0 for ultraviolet. * temp and humidity seem to be off about 6 * degrees warmer and 7 percent humidity lower than actual * FIXED: battery tile added, vibration tile removed and touch capability and tile added and status updates are working, thanks TIM YUHL for the code review and sanity check! * Original code for gen5 Copyright 2015 SmartThings, modified for use on gen 6 by Robert Vandervoort * * 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: "Aeon Multisensor 6", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Touch Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "no touch" : " command: 9881, payload: 0071050000000007030000" status "touch" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 20, 89, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultraviolet ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles { standardTile("motion","device.motion") { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature",inactiveLabel: false) { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "humidity","device.humidity",inactiveLabel: false) { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile( "illuminance","device.illuminance",inactiveLabel: false) { state "luminosity",label:'${currentValue} ${unit}', unit:"lux", backgroundColors:[ [value: 0, color: "#000000"], [value: 47, color: "#1A1A0A"], [value: 94, color: "#333314"], [value: 141, color: "#4C4C1F"], [value: 188, color: "#666629"], [value: 235, color: "#808033"], [value: 282, color: "#99993D"], [value: 329, color: "#B2B247"], [value: 376, color: "#CCCC52"], [value: 423, color: "#E6E65C"], [value: 470, color: "#FFFF66"], [value: 517, color: "#FFFF75"], [value: 564, color: "#FFFF85"], [value: 611, color: "#FFFF94"], [value: 658, color: "#FFFFA3"], [value: 705, color: "#FFFFB2"], [value: 752, color: "#FFFFC2"], [value: 799, color: "#FFFFD1"], [value: 846, color: "#FFFFE0"], [value: 900, color: "#FFFFF0"], [value: 1000, color: "#FFFFFF"] ] } valueTile( "ultraviolet","device.ultraviolet",inactiveLabel: false) { state "ultraviolet",label:'${currentValue} UV',unit:"UV" } standardTile( "touch","device.touch") { state "touched",label:'touched',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "inactive",label:'calm',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", inactiveLabel: false, decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configure","device.configure",inactiveLabel: false,decoration: "flat") { state "configure",label:'',action:"configure",icon:"st.secondary.configure" } main([ "motion","touch","temperature","humidity","illuminance","ultraviolet" ]) details([ "motion","touch","temperature","humidity","illuminance","ultraviolet","battery","configureAfterSecure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", defaultValue: 1, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds for mains power, you can't go shorter than 3600 on battery power.", defaultValue: 60, required: true, displayDuringSetup: true } } def parse(String description) { def result = null if (description == "updated") { result = null } else { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("not sending wakeUpNoMoreInformation yet") result += response(configureAfterSecure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { log.debug "Received SecurityCommandsSupportedReport" response(configureAfterSecure()) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = new Date().time createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultraviolet" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value == 255) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def touchEvent(value) { def map = [name: "touch"] if (value == 255) { log.debug "-------------touched------------------" map.value = "touched" map.descriptionText = "$device.displayName detected touch" } else { log.debug "-------------touch inactive-----------" map.value = "inactive" map.descriptionText = "$device.displayName touch has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { log.debug "Basic Set 255 triggered motion event" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (cmd.notificationType == 7 && cmd.event == 8) { log.debug "notification type 7 event 8 triggered motion event" motionEvent(cmd.notificationStatus) } else if (cmd.notificationType == 7 && cmd.event == 0) { log.debug "notification type 7 event 0 motion and touch cleared" motionEvent(0) touchEvent(0) } else if (cmd.notificationType == 7 && cmd.event == 3) { log.debug "notification type 7 event 3 triggered touch event" touchEvent(cmd.notificationStatus) } else { createEvent(descriptionText: cmd.toString(), isStateChange: false) } } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configureAfterSecure() { log.debug "configureAfterSecure()" //log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 60 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { if(tempoffset < 0) { tempoff=(255-tempoffset.tointeger()) } if(tempoffset > 0) { tempoff=(0+tempoffset.tointeger()) } } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset.toInteger() } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset.toInteger() } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset.toInteger() } //log.debug "PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // send temperature, humidity, illuminance, ultraviolet and battery zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 20), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor // zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: ultravioletoff), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] setConfigured() //log.debug request secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } def configure() { //["delay 20000"] + secure(zwave.securityV1.securityCommandsSupportedGet()) log.debug "configure()" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 60 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { if(tempoffset < 0) { tempoff=(255-tempoffset.tointeger()) } if(tempoffset > 0) { tempoff=(0+tempoffset.tointeger()) } } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset.toInteger() } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset.toInteger() } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset.toInteger() } log.debug "PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" delayBetween([ // send temperature, humidity, illuminance, ultraviolet and battery every 60 minutes or seconds depending on power state zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x6F, size: 4, scaledConfigurationValue: ReportingInt).format(), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60).format(), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 20).format(), // enable motion sensor and set min sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens).format(), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2).format(), // Enable the function of touch sensor //zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1).format(), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0).format(), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: tempoff).format(), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: humidityoff).format(), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff).format(), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: ultravioletoff).format(), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ]) setConfigured() zwave.wakeUpV1.wakeUpNoMoreInformation().format() } def setConfigured() { device.updateDataValue("configured", "true") } def isConfigured() { Boolean configured = device.getDataValue(["configured"]) as Boolean return configured } private secure(physicalgraph.zwave.Command cmd) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } private secureSequence(commands, delay=200) { delayBetween(commands.collect{ secure(it) }, delay) } def updated() { log.debug "updated()" log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" configure() } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v1.3 ================================================ /** * V 1.3 of Multisensor 6 code 9/14/2015 * Original code for gen5 Copyright 2015 SmartThings, modified for use on Multisensor 6 by Robert Vandervoort 6/19/2015 * * 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: "rv Aeon Multisensor 6", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Touch Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" attribute "tamper", "enum", ["detected", "clear"] // CC supported 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 20, 89, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles { standardTile("motion","device.motion") { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature",inactiveLabel: false) { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "humidity","device.humidity",inactiveLabel: false) { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile( "illuminance","device.illuminance",inactiveLabel: false) { state "luminosity",label:'${currentValue} ${unit}', unit:"lux", backgroundColors:[ [value: 0, color: "#000000"], [value: 47, color: "#1A1A0A"], [value: 94, color: "#333314"], [value: 141, color: "#4C4C1F"], [value: 188, color: "#666629"], [value: 235, color: "#808033"], [value: 282, color: "#99993D"], [value: 329, color: "#B2B247"], [value: 376, color: "#CCCC52"], [value: 423, color: "#E6E65C"], [value: 470, color: "#FFFF66"], [value: 517, color: "#FFFF75"], [value: 564, color: "#FFFF85"], [value: 611, color: "#FFFF94"], [value: 658, color: "#FFFFA3"], [value: 705, color: "#FFFFB2"], [value: 752, color: "#FFFFC2"], [value: 799, color: "#FFFFD1"], [value: 846, color: "#FFFFE0"], [value: 900, color: "#FFFFF0"], [value: 1000, color: "#FFFFFF"] ] } valueTile( "ultravioletIndex","device.ultravioletIndex",inactiveLabel: false) { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile( "tamper","device.tamper") { state "tamper",label:'tamper',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "clear",label:'clear',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", inactiveLabel: false, decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configure","device.configure",inactiveLabel: false, decoration: "flat") { state "configure", label:'insecure config', action:"configure", icon:"st.secondary.tools" } standardTile( "configureAfterSecure", "device.configure", inactiveLabel: false, decoration: "flat") { state "configure", label:'secure config', action:"configureAfterSecure", icon:"st.secondary.tools" } main([ "motion","tamper","temperature","humidity","illuminance","ultravioletIndex" ]) details([ "motion","tamper","temperature","humidity","illuminance","ultravioletIndex","battery","configure","configureAfterSecure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", defaultValue: 1, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def parse(String description) { def result = null if (description == "updated") { result = null } else { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("have not sent config yet - not sending wakeUpNoMoreInformation yet") result += response(configureAfterSecure()) result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { log.debug "Received SecurityCommandsSupportedReport" // response(configureAfterSecure()) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = new Date().time createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { // setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "tamper", value: "clear", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configureAfterSecure() { log.debug "configureAfterSecure" log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { if(tempoffset < 0) { tempoff=(255-tempoffset) } if(tempoffset > 0) { tempoff=(0+tempoffset) } } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset.toInteger() } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset.toInteger() } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset.toInteger() } //log.debug "PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 20), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor // zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: ultravioletoff), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] //log.debug request secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] setConfigured() } def configure() { //["delay 20000"] + secure(zwave.securityV1.securityCommandsSupportedGet()) log.debug "configure" log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { if(tempoffset < 0) { tempoff=(255-tempoffset) } if(tempoffset > 0) { tempoff=(0+tempoffset) } } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset.toInteger() } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset.toInteger() } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset.toInteger() } log.debug "PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" delayBetween([ // set wakeup interval to 5 minutes zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId).format(), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x6F, size: 4, scaledConfigurationValue: ReportingInt).format(), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1).format(), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60).format(), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 20).format(), // enable motion sensor and set min sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens).format(), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2).format(), // Enable the function of touch sensor //zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1).format(), // disable notification-style motion events zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0).format(), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 2, scaledConfigurationValue: tempoff).format(), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 2, scaledConfigurationValue: humidityoff).format(), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff).format(), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 2, scaledConfigurationValue: ultravioletoff).format(), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ]) zwave.wakeUpV1.wakeUpNoMoreInformation().format() setConfigured() } def setConfigured() { device.updateDataValue("configured", "true") } def isConfigured() { Boolean configured = device.getDataValue(["configured"]) as Boolean return configured } private secure(physicalgraph.zwave.Command cmd) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } private secureSequence(commands, delay=200) { delayBetween(commands.collect{ secure(it) }, delay) } def updated() { log.debug "updated()" log.debug "PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" //configure() } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v1.4 ================================================ /* * V 1.4 of Multisensor 6 code 9/14/2015 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * Robert Vandervoort 6/19/2015 - 9/20/2015 * * 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. * * INSTRUCTIONS: Pair device to SmartThings by double tapping the inclusion button. Allow it to join with SmartThings device type. After * adding, go to device entry in the website, edit it, change type to Aeon Multisensor 6 - RV, open device in SmartThings app, edit * edit preferences to your liking but do not save yet, short press action button on sensor one time and the light should go blue, hit save * in the app, a couple seconds later the light should go out (you can verify in live logging that it says it woke up and settings were sent * over).. Now on device screen, short press the action button one more time and hit secure configure button on the app screen... Your sensor * should now follow your polling interval, but will go no lower than 5 minute intervals unless a large enough change happens to warrant it. * motion activates immediately and clears after 20 seconds. tamper activates immediately and also clears after 20 seconds. Currently tamper * is just used for logging and as an indicator on the screen. If requests for functionality outside of that are required please message me. */ metadata { definition (name: "Aeon Multisensor 6 - RV", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles { standardTile("motion","device.motion") { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature") { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "humidity","device.humidity") { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile( "illuminance","device.illuminance") { state "luminosity",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") { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile( "tamper","device.tamper") { state "tamper",label:'tamper',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "clear",label:'clear',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configure","device.configure", decoration: "flat") { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main([ "temperature","humidity","illuminance","motion","tamper","ultravioletIndex" ]) details([ "temperature","humidity","illuminance","motion","tamper","ultravioletIndex","battery","configure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "..", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", defaultValue: 1, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) state.sec = 1 log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "tamper", value: "clear", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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" // return [] //} log.debug "--Sending configuration command to Multisensor 6--" //log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { if(tempoffset < 0) { tempoff=(255-tempoffset) } if(tempoffset > 0) { tempoff=(0+tempoffset) } } def humidityoff = 0 if (humidityoffset) { if(humidityoffset < 0) { humidityoff=(255-humidityoffset) } if(humidityoffset > 0) { humidityoff=(0+humidityoffset) } } def luminanceoff = 0 if (luminanceoffset) { if(luminanceoffset < 0) { luminanceoff=(255-luminanceoffset) } if(luminanceoffset > 0) { luminanceoff=(0+luminanceoffset) } } def ultravioletoff = 0 if (ultravioletoffset) { if(ultravioletoffset < 0) { ultravioletoff=(255-ultravioletoffset) } if(ultravioletoffset > 0) { ultravioletoff=(0 + ultravioletoffset) } } //log.debug "Setting - PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: 20), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=200) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v1.5 ================================================ /* * V 1.5 of Multisensor 6 code 9/14/2015 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * Robert Vandervoort 6/19/2015 - 9/20/2015 * * 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. * * INSTRUCTIONS: Pair device to SmartThings by double tapping the inclusion button. Allow it to join with SmartThings device type. After * adding, go to device entry in the website, edit it, change type to Aeon Multisensor 6 - RV, open device in SmartThings app, edit * edit preferences to your liking but do not save yet, short press action button on sensor one time and the light should go blue, hit save * in the app, a couple seconds later the light should go out (you can verify in live logging that it says it woke up and settings were sent * over).. Now on device screen, short press the action button one more time and hit secure configure button on the app screen... Your sensor * should now follow your polling interval, but will go no lower than 5 minute intervals unless a large enough change happens to warrant it. * motion activates immediately and clears after 20 seconds. tamper activates immediately and also clears after 20 seconds. Currently tamper * is just used for logging and as an indicator on the screen. If requests for functionality outside of that are required please message me. */ metadata { definition (name: "Aeon Multisensor 6 - RV 1.5", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles { standardTile("motion","device.motion") { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature") { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "humidity","device.humidity") { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile( "illuminance","device.illuminance") { state "luminosity",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") { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile( "tamper","device.tamper") { state "tamper",label:'tamper',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "clear",label:'clear',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", decoration: "flat") { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configure","device.configure", decoration: "flat") { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main([ "temperature","humidity","illuminance","motion","tamper","ultravioletIndex" ]) details([ "temperature","humidity","illuminance","motion","tamper","ultravioletIndex","battery","configure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: true, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) state.sec = 1 log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "tamper", value: "clear", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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" // return [] //} log.debug "--Sending configuration command to Multisensor 6--" log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } log.debug "Setting - PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x28), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=200) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v2.0 ================================================ /* * V 2.0 of Multisensor 6 code 9/14/2015 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * 2.0 brings about the new style look with multiattribute tile for temp and humidity * Robert Vandervoort 6/19/2015 - 11/5/2015 * * 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. * * INSTRUCTIONS: Pair device to SmartThings by double tapping the inclusion button. Allow it to join with SmartThings device type. After * adding, go to device entry in the website, edit it, change type to Aeon Multisensor 6 - RV, open device in SmartThings app, edit * edit preferences to your liking but do not save yet, short press action button on sensor one time and the light should go blue, hit save * in the app, a couple seconds later the light should go out (you can verify in live logging that it says it woke up and settings were sent * over).. Now on device screen, short press the action button one more time and hit secure configure button on the app screen... Your sensor * should now follow your polling interval, but will go no lower than 5 minute intervals unless a large enough change happens to warrant it. * motion activates immediately and clears after 20 seconds. tamper activates immediately and also clears after 20 seconds. Currently tamper * is just used for logging and as an indicator on the screen. If requests for functionality outside of that are required please message me. */ metadata { definition (name: "Aeon Multisensor 6 - RV 2.0", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue} %',unit:"" } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("temperature","device.temperature", width: 2, height: 2) { state "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile( "illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",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", width: 2, height: 2) { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile( "tamper","device.tamper", width: 2, height: 2) { state "tamper",label:'tamper',icon:"st.motion.motion.active",backgroundColor:"#ff0000" state "clear",label:'clear',icon:"st.motion.motion.inactive",backgroundColor:"#00ff00" } valueTile( "battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile( "configure","device.configure", decoration: "flat", width: 2, height: 2) { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main([ "main" ]) details([ "main","illuminance","ultravioletIndex","motion","tamper","battery","configure" ]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: true, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) state.sec = 1 log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "tamper", value: "clear", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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" // return [] //} log.debug "--Sending configuration command to Multisensor 6--" log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } log.debug "Setting - PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x28), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=200) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v2.1 ================================================ /* * V 2.1 of Multisensor 6 code 10/10/2015 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * 2.0 brings about the new style look with multiattribute tile for temp and humidity and all adjustments working * 2.1 provides vibration sensor output to smartthings in the form of the acceleration capability for use in the home security section. You can create push notifications, SMS, and trigger cameras and the like if you sensor is tampered with or it detects a significant enough vibration, like a door slamming close by. * Robert Vandervoort 6/19/2015 - 11/10/2015 * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: *- Log in to the IDE and add my device type "from code" copy pasting the raw code from github and save it *- Open the live logging view in a new tab *- With the sensor plugged in via usb, note the light color. It should cycle through many different colors continually. If it does not, it was previously joined. The sensor may come this way from wherever you ordered it. To reset, perform the following: Hold the action button for about 25 seconds until the light blinks red quickly and then the colors cycle. It is now reset. *- Put smart things into inclusion mode by doing the add device procedure on the app. *- Quickly double tap the action button. The light on the sensor should blink blue several times quickly. Please read the rest before continuing! *- Before you do anything else and when you see the device smartthings found on the screen, go to your devices in the IDE, select the newly added sensor and edit it. Change the device type to my device type and save it. *- Back on your app, click the device on the screen to add it. Walk through the next few steps setting preferences and smart app stuff if you like. After you save the preferences the device should update and send the configuration. You can see this on the live logging view in the debug comments. It may help to select just the newly added sensor from the available items to see past the other noise in the view. When in doubt, hit the configure tile and watch.. *- That's it. */ metadata { definition (name: "Aeon Multisensor 6 - RV 2.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue} %',unit:"" } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue} %',unit:"" } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",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", width: 2, height: 2) { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile("configure","device.configure", decoration: "flat", width: 2, height: 2) { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main(["main"]) details(["main","humidity","illuminance","ultravioletIndex","motion","acceleration","battery","configure"]) } preferences { input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: true, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1]) if (cmd) { result = zwaveEvent(cmd) } } log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1]) state.sec = 1 log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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" // return [] //} log.debug "--Sending configuration command to Multisensor 6--" log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } log.debug "Setting - PIRsens: $PIRsens, ReportingInt: $ReportingInt, Tempoffset: $tempoff, Humidityoff: $humidityoff, Luminanceoff: $luminanceoff, UVoff: $ultravioletoff" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x28), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v2.2 ================================================ /* * V 2.2 of Multisensor 6 code 10/10/2015 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * 2.0 brings about the new style look with multiattribute tile for temp and humidity and all adjustments working * 2.1 provides vibration sensor output to smartthings in the form of the acceleration capability for use in the home security section. You can create push notifications, SMS, and trigger cameras and the like if you sensor is tampered with or it detects a significant enough vibration, like a door slamming close by. * Robert Vandervoort 6/19/2015 - 11/10/2015 * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: *- Log in to the IDE and add my device type "from code" copy pasting the raw code from github and save it *- Open the live logging view in a new tab *- With the sensor plugged in via usb, note the light color. It should cycle through many different colors continually. If it does not, it was previously joined. The sensor may come this way from wherever you ordered it. To reset, perform the following: Hold the action button for about 25 seconds until the light blinks red quickly and then the colors cycle. It is now reset. *- Put smart things into inclusion mode by doing the add device procedure on the app. *- Quickly double tap the action button. The light on the sensor should blink blue several times quickly. Please read the rest before continuing! *- Before you do anything else and when you see the device smartthings found on the screen, go to your devices in the IDE, select the newly added sensor and edit it. Change the device type to my device type and save it. *- Back on your app, click the device on the screen to add it. Walk through the next few steps setting preferences and smart app stuff if you like. After you save the preferences the device should update and send the configuration. You can see this on the live logging view in the debug comments. It may help to select just the newly added sensor from the available items to see past the other noise in the view. When in doubt, hit the configure tile and watch.. *- That's it. */ metadata { definition (name: "Aeon Multisensor 6 - RV 2.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}°',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue}%',icon:" " } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%',unit:"${unit}" } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'${currentValue}', unit:"${unit}", 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", width: 2, height: 2) { state "ultravioletIndex",label:'${currentValue} UV INDEX',unit:"" } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile("configure","device.configure", decoration: "flat", width: 2, height: 2) { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main(["main"]) details(["main","humidity","illuminance","ultravioletIndex","motion","acceleration","battery","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: true, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } //if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) state.sec = 1 //if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue.toInteger() map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() map.unit = "" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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) { // if (state.debug) log.debug "Multi 6 not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration command to Multisensor 6--" if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v2.3 ================================================ /* * V 2.3 of Multisensor 6 code 5/18/2016 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * 2.0 brings about the new style look with multiattribute tile for temp and humidity and all adjustments working * 2.1 provides vibration sensor output to smartthings in the form of the acceleration capability for use in the home security section. You can create push notifications, SMS, and trigger cameras and the like if you sensor is tampered with or it detects a significant enough vibration, like a door slamming close by. * Robert Vandervoort 6/19/2015 - 5/18/2016 * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: *- Log in to the IDE and add my device type "from code" copy pasting the raw code from github and save it *- Open the live logging view in a new tab *- With the sensor plugged in via usb, note the light color. It should cycle through many different colors continually. If it does not, it was previously joined. The sensor may come this way from wherever you ordered it. To reset, perform the following: Hold the action button for about 25 seconds until the light blinks red quickly and then the colors cycle. It is now reset. *- Put smart things into inclusion mode by doing the add device procedure on the app. *- Quickly double tap the action button. The light on the sensor should blink blue several times quickly. Please read the rest before continuing! *- Before you do anything else and when you see the device smartthings found on the screen, go to your devices in the IDE, select the newly added sensor and edit it. Change the device type to my device type and save it. *- Back on your app, click the device on the screen to add it. Walk through the next few steps setting preferences and smart app stuff if you like. After you save the preferences the device should update and send the configuration. You can see this on the live logging view in the debug comments. It may help to select just the newly added sensor from the available items to see past the other noise in the view. When in doubt, hit the configure tile and watch.. *- That's it. */ metadata { definition (name: "Aeon Multisensor 6 - RV 2.3", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue}%',precision:2,icon:" " } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%', precision:2 } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'${currentValue} lx', precision:2, 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", width: 2, height: 2) { state "ultravioletIndex",label:'${currentValue} UV INDEX' } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile("configure","device.configure", decoration: "flat", width: 2, height: 2) { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main(["main"]) details(["main","humidity","illuminance","ultravioletIndex","motion","acceleration","battery","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: true, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: true, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: true, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } //if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) state.sec = 1 //if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { if (state.debug) log.debug "---BATTERY V1 REPORT--- ${device.displayName} reports battery level of ${cmd.batteryLevel}" def result = [] def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel map.descriptionText = "${device.displayName} battery is at ${cmd.batteryLevel}" map.isStateChange = true } state.lastbatt = now() result << createEvent(map) result } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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) { // if (state.debug) log.debug "Multi 6 not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration command to Multisensor 6--" if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon Multisensor 6/device_type-aeon-multisensor6-v2.3.1 ================================================ /* * V 2.3 of Multisensor 6 code 5/18/2016 * Uses some original code from @Duncan Aeon Multisensor 6 code for secure configuration, Copyright 2015 SmartThings, modified for setting * preferences around configuration and the reporting of tampering and ultraviolet index, and reconfiguration after pairing. * 2.0 brings about the new style look with multiattribute tile for temp and humidity and all adjustments working * 2.1 provides vibration sensor output to smartthings in the form of the acceleration capability for use in the home security section. You can create push notifications, SMS, and trigger cameras and the like if you sensor is tampered with or it detects a significant enough vibration, like a door slamming close by. * Robert Vandervoort 6/19/2015 - 5/18/2016 * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: *- Log in to the IDE and add my device type "from code" copy pasting the raw code from github and save it *- Open the live logging view in a new tab *- With the sensor plugged in via usb, note the light color. It should cycle through many different colors continually. If it does not, it was previously joined. The sensor may come this way from wherever you ordered it. To reset, perform the following: Hold the action button for about 25 seconds until the light blinks red quickly and then the colors cycle. It is now reset. *- Put smart things into inclusion mode by doing the add device procedure on the app. *- Quickly double tap the action button. The light on the sensor should blink blue several times quickly. Please read the rest before continuing! *- Before you do anything else and when you see the device smartthings found on the screen, go to your devices in the IDE, select the newly added sensor and edit it. Change the device type to my device type and save it. *- Back on your app, click the device on the screen to add it. Walk through the next few steps setting preferences and smart app stuff if you like. After you save the preferences the device should update and send the configuration. You can see this on the live logging view in the debug comments. It may help to select just the newly added sensor from the available items to see past the other noise in the view. When in doubt, hit the configure tile and watch.. *- That's it. */ metadata { definition (name: "Aeon Multisensor 6 - RV 2.3", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Ultraviolet Index" capability "Configuration" capability "Sensor" capability "Battery" // CCs supported - 94, 134, 114, 132, 89, 133, 115, 113, 128, 48, 49, 112, 152, 122 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0xEF,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i} lux": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i = 0; i <= 11; i += 1) { status "ultravioletultravioletIndex ${i}": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 27 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}',backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue}%',precision:2,icon:" " } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%', precision:2 } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'${currentValue} lx', precision:2, 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", width: 2, height: 2) { state "ultravioletIndex",label:'${currentValue} UV INDEX' } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } standardTile("configure","device.configure", decoration: "flat", width: 2, height: 2) { state "configure", label:'config', action:"configure", icon:"st.secondary.tools" } main(["main"]) details(["main","humidity","illuminance","ultravioletIndex","motion","acceleration","battery","configure"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "tempoffset", "number", title: "Temperature offset", description: "negative values reduce the monitored value positive ones add to it", range: "-11..11", defaultValue: 0, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Humidity offset", description: "negative values reduce the monitored value positive ones add to it", range: "-50..50", defaultValue: 0, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Luminance offset", description: "negative values reduce the monitored value positive ones add to it", range: "-1000..1000", defaultValue: 0, required: false, displayDuringSetup: false input "ultravioletoffset", "number", title: "Ultraviolet offset", description: "negative values reduce the monitored value positive ones add to it", range: "-10..10", defaultValue: 0, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 0-5, from disabled to high sensitivity", range: "0..5", defaultValue: 1, required: false, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of seconds to wait to report motion cleared after a motion event if there is no motion detected.", defaultValue: 20, required: false, displayDuringSetup: true input "ReportingInterval", "number", title: "Report data interval", description: "A value in seconds.", defaultValue: 300, required: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } //if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x7A: 2, 0x84: 1, 0x86: 1]) state.sec = 1 //if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { if (state.debug) log.debug "---BATTERY V1 REPORT--- ${device.displayName} reports battery level of ${cmd.batteryLevel}" def result = [] def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel map.descriptionText = "${device.displayName} battery is at ${cmd.batteryLevel}" map.isStateChange = true } state.lastbatt = now() result << createEvent(map) result } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue map.unit = "lux" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue.toInteger() map.unit = "%" break; case 27: map.name = "ultravioletIndex" map.value = cmd.scaledSensorValue.toInteger() break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { setConfigured() motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def result = [] if (cmd.notificationType == 7) { switch (cmd.event) { case 0: result << motionEvent(0) result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName tamper cleared") break case 3: result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName was moved") break case 7: result << motionEvent(1) break } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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) { // if (state.debug) log.debug "Multi 6 not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration command to Multisensor 6--" if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Reporting Interval: $ReportingInterval, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset, UV offset: $ultravioletoffset" def PIRsens = 1 if (PIRsensitivity) { PIRsens=PIRsensitivity.toInteger() } def MotionRst = 20 if (MotionReset) { MotionRst=MotionReset.toInteger() } def ReportingInt = 300 if (ReportingInterval) { ReportingInt=ReportingInterval.toInteger() } def tempoff = 0 if (tempoffset) { tempoff=tempoffset*10 } def humidityoff = 0 if (humidityoffset) { humidityoff=humidityoffset } def luminanceoff = 0 if (luminanceoffset) { luminanceoff=luminanceoffset } def ultravioletoff = 0 if (ultravioletoffset) { ultravioletoff=ultravioletoffset } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" def request = [ // set wakeup interval to 5 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // send temperature, humidity, illuminance, ultraviolet based on reporting interval preference default 5 mins zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 4, scaledConfigurationValue: 128|64|32|16), // configure frequency of reporting zwave.configurationV1.configurationSet(parameterNumber: 0x6F,size: 4, scaledConfigurationValue: ReportingInt), zwave.configurationV1.configurationGet(parameterNumber: 0x6F), // send battery every 20 hours zwave.configurationV1.configurationSet(parameterNumber: 0x66, size: 4, scaledConfigurationValue: 1), zwave.configurationV1.configurationSet(parameterNumber: 0x70, size: 4, scaledConfigurationValue: 20*60*60), // send no-motion report 20 seconds after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 2, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // enable motion sensor and set sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send binary sensor report for motion zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 2), // Enable the function of touch sensor zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // disable notification-style motion events // zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0), // configure temp offset zwave.configurationV1.configurationSet(parameterNumber: 0xC9, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0xC9), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0xCA, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCA), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0xCB, size: 2, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCB), // configure ultraviolet offset zwave.configurationV1.configurationSet(parameterNumber: 0xCC, size: 1, scaledConfigurationValue: ultravioletoff), zwave.configurationV1.configurationGet(parameterNumber: 0xCC), zwave.batteryV1.batteryGet(), zwave.sensorBinaryV2.sensorBinaryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartDimmer 6/device_type-aeon-smartdimmer6-v0.1 ================================================ /* * V 0.1 of Aeon Smart Dimmer 6 code 10/6/2015 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * */ metadata { definition (name: "Aeon Smart Dimmer 6 - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Switch Level" capability "Color Control" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" /* Capability notes 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL 2 0x27 COMMAND_CLASS_SWITCH_ALL 1 0x32 COMMAND_CLASS_METER 3 0x33 COMMAND_CLASS_COLOR_SWITCH 3 0x59 COMMAND_CLASS_ASSOCIATION_GRP_INFO 1 0x5A COMMAND_CLASS_DEVICE_RESET_LOCALLY 1 0x5E COMMAND_CLASS_ZWAVE_PLUS_INFO 2 0x60 Multi Channel Command Class (V3) 0x70 COMMAND_CLASS_CONFIGURATION 1 0x72 COMMAND_CLASS_MANUFACTURER_SPECIFIC 2 0x73 COMMAND_CLASS_POWERLEVEL 1 0x7A COMMAND_CLASS_FIRMWARE_UPDATE_MD 2 0x81 COMMAND_CLASS_CLOCK 1 0x82 COMMAND_CLASS_HAIL 1 0x8E COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION 2 0x85 COMMAND_CLASS_ASSOCIATION 2 0x86 COMMAND_CLASS_VERSION 2 0xEF COMMAND_CLASS_MARK 1 */ fingerprint deviceId: "0x1101", inClusters: "0x98" fingerprint inClusters: "0x26,0x27,0x32,0x33,0x59,0x5A,0x5E,0x60,0x70,0x72,0x73,0x7A,0x81,0x8E,0x85,0x86,0xEF", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2603, payload: FF" status "off": "command: 2603, payload: 00" status "09%": "command: 2603, payload: 09" status "10%": "command: 2603, payload: 0A" status "33%": "command: 2603, payload: 21" status "66%": "command: 2603, payload: 42" status "99%": "command: 2603, payload: 63" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages ["FF", "00", "09", "0A", "21", "42", "63"].each { val -> reply "2001$val,delay 100,2602": "command: 2603, payload: $val" } } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"lighting", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } controlTile("rgbSelector", "device.color", "color", height: 2, width: 2, inactiveLabel: false) { state "color", action:"setColor" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","rgbSelector","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true, range: "0..2" input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, range: "1..4294967295‬", required: false, displayDuringSetup: true input "ledBrightness", "integer", title: "LED Brightness", description: "Set the % brightness of indicator LEDs", defaultValue: 50, range: "0..100", required: false, displayduringSetup: true input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor previousValue = device.currentValue("powerFactor") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) { [name: "level", value: cmd.value, type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { if (state.debug) log.debug "turning on ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value) { if (state.debug) log.debug "setting level to ${value} on ${device.displayName}" def valueaux = value as Integer def level = Math.min(valueaux, 99) def request = [ zwave.basicV1.basicSet(value: level), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value, duration) { def valueaux = value as Integer def level = Math.min(valueaux, 99) def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60) def request = [ zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration) ] commands(request) } def setColor(value) { def result = [] if (state.debug) log.debug "setColor: ${value}" if (value.hex) { def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } result << zwave.configurationV1.configurationSet(parameterNumber: 83, size: 3, configurationValue: [c[0], c[1], c[2]]) } if(value.hex) sendEvent(name: "color", value: value.hex) commands(result) } def poll() { if (state.debug) log.debug "poll request sent to ${device.displayName}" def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { if (state.debug) log.debug "reset request sent to ${device.displayName}" def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } def ledBright = 50 if (ledBrightness) { ledBright=ledBrightness.toInteger() } if (state.debug) log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Set LED brightness zwave.configurationV1.configurationSet(parameterNumber: 84, size: 3, configurationValue: [ledBright,ledBright,ledBright]), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get notification behavior zwave.configurationV1.configurationGet(parameterNumber: 80), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartDimmer 6/device_type-aeon-smartdimmer6-v0.1-ANDROID ================================================ /* * V 0.1 of Aeon Smart Dimmer 6 code 10/6/2015 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * * ANDROID - Thanks Jeff_Pollock and RBoy for pointing out the Range values bug in Android helping to get this workign on Android OS */ metadata { definition (name: "Aeon Smart Dimmer 6 - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Switch Level" capability "Color Control" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" /* Capability notes 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL 2 0x27 COMMAND_CLASS_SWITCH_ALL 1 0x32 COMMAND_CLASS_METER 3 0x33 COMMAND_CLASS_COLOR_SWITCH 3 0x59 COMMAND_CLASS_ASSOCIATION_GRP_INFO 1 0x5A COMMAND_CLASS_DEVICE_RESET_LOCALLY 1 0x5E COMMAND_CLASS_ZWAVE_PLUS_INFO 2 0x60 Multi Channel Command Class (V3) 0x70 COMMAND_CLASS_CONFIGURATION 1 0x72 COMMAND_CLASS_MANUFACTURER_SPECIFIC 2 0x73 COMMAND_CLASS_POWERLEVEL 1 0x7A COMMAND_CLASS_FIRMWARE_UPDATE_MD 2 0x81 COMMAND_CLASS_CLOCK 1 0x82 COMMAND_CLASS_HAIL 1 0x8E COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION 2 0x85 COMMAND_CLASS_ASSOCIATION 2 0x86 COMMAND_CLASS_VERSION 2 0xEF COMMAND_CLASS_MARK 1 */ fingerprint deviceId: "0x1101", inClusters: "0x98" fingerprint inClusters: "0x26,0x27,0x32,0x33,0x59,0x5A,0x5E,0x60,0x70,0x72,0x73,0x7A,0x81,0x8E,0x85,0x86,0xEF", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2603, payload: FF" status "off": "command: 2603, payload: 00" status "09%": "command: 2603, payload: 09" status "10%": "command: 2603, payload: 0A" status "33%": "command: 2603, payload: 21" status "66%": "command: 2603, payload: 42" status "99%": "command: 2603, payload: 63" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages ["FF", "00", "09", "0A", "21", "42", "63"].each { val -> reply "2001$val,delay 100,2602": "command: 2603, payload: $val" } } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"lighting", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } controlTile("rgbSelector", "device.color", "color", height: 2, width: 2, inactiveLabel: false) { state "color", action:"setColor" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","rgbSelector","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, required: false, displayDuringSetup: true input "ledBrightness", "integer", title: "LED Brightness", description: "Set the % brightness of indicator LEDs", defaultValue: 50, required: false, displayduringSetup: true input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor previousValue = device.currentValue("powerFactor") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) { [name: "level", value: cmd.value, type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { if (state.debug) log.debug "turning on ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value) { if (state.debug) log.debug "setting level to ${value} on ${device.displayName}" def valueaux = value as Integer def level = Math.min(valueaux, 99) def request = [ zwave.basicV1.basicSet(value: level), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value, duration) { def valueaux = value as Integer def level = Math.min(valueaux, 99) def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60) def request = [ zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration) ] commands(request) } def setColor(value) { def result = [] if (state.debug) log.debug "setColor: ${value}" if (value.hex) { def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } result << zwave.configurationV1.configurationSet(parameterNumber: 83, size: 3, configurationValue: [c[0], c[1], c[2]]) } if(value.hex) sendEvent(name: "color", value: value.hex) commands(result) } def poll() { if (state.debug) log.debug "poll request sent to ${device.displayName}" def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { if (state.debug) log.debug "reset request sent to ${device.displayName}" def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } def ledBright = 50 if (ledBrightness) { ledBright=ledBrightness.toInteger() } if (state.debug) log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Set LED brightness zwave.configurationV1.configurationSet(parameterNumber: 84, size: 3, configurationValue: [ledBright,ledBright,ledBright]), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get notification behavior zwave.configurationV1.configurationGet(parameterNumber: 80), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartDimmer 6/device_type-aeon-smartdimmer6-v0.2.groovy ================================================ /* * V 0.2 of Aeon Smart Dimmer 6 code 9/24/2017 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * */ metadata { definition (name: "Aeon Smart Dimmer 6 - RV v0.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Switch Level" capability "Color Control" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" /* Capability notes 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL 2 0x27 COMMAND_CLASS_SWITCH_ALL 1 0x32 COMMAND_CLASS_METER 3 0x33 COMMAND_CLASS_COLOR_SWITCH 3 0x59 COMMAND_CLASS_ASSOCIATION_GRP_INFO 1 0x5A COMMAND_CLASS_DEVICE_RESET_LOCALLY 1 0x5E COMMAND_CLASS_ZWAVE_PLUS_INFO 2 0x60 Multi Channel Command Class (V3) 0x70 COMMAND_CLASS_CONFIGURATION 1 0x72 COMMAND_CLASS_MANUFACTURER_SPECIFIC 2 0x73 COMMAND_CLASS_POWERLEVEL 1 0x7A COMMAND_CLASS_FIRMWARE_UPDATE_MD 2 0x81 COMMAND_CLASS_CLOCK 1 0x82 COMMAND_CLASS_HAIL 1 0x8E COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION 2 0x85 COMMAND_CLASS_ASSOCIATION 2 0x86 COMMAND_CLASS_VERSION 2 0xEF COMMAND_CLASS_MARK 1 */ fingerprint mfr: "0086", prod: "0103", model: "0063" } // simulator metadata simulator { status "on": "command: 2603, payload: FF" status "off": "command: 2603, payload: 00" status "09%": "command: 2603, payload: 09" status "10%": "command: 2603, payload: 0A" status "33%": "command: 2603, payload: 21" status "66%": "command: 2603, payload: 42" status "99%": "command: 2603, payload: 63" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages ["FF", "00", "09", "0A", "21", "42", "63"].each { val -> reply "2001$val,delay 100,2602": "command: 2603, payload: $val" } } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"lighting", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } controlTile("rgbSelector", "device.color", "color", height: 2, width: 2, inactiveLabel: false) { state "color", action:"setColor" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","rgbSelector","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true, range: "0..2" input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, range: "1..4294967295‬", required: false, displayDuringSetup: true input "ledBrightness", "integer", title: "LED Brightness", description: "Set the % brightness of indicator LEDs", defaultValue: 50, range: "0..100", required: false, displayduringSetup: true input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { state.debug = ("true" == debugOutput) if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { if (state.debug) log.debug cmd def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: true] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor previousValue = device.currentValue("powerFactor") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) return map } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def result; result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true); return result; } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { def result; result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true); return result; } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def result; result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true); return result; } def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) { def result; result = createEvent(name: "level", value: cmd.value, type: "digital", displayed: true, isStateChange: true); return result; } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { def result; result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true); return result; } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { if (state.debug) log.debug "turning on ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def off() { if (state.debug) log.debug "turning off ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value) { if (state.debug) log.debug "setting level to ${value} on ${device.displayName}" def valueaux = value as Integer def level = Math.min(valueaux, 99) def request = [ zwave.basicV1.basicSet(value: level), zwave.switchMultilevelV1.switchMultilevelGet() ] commands(request) } def setLevel(value, duration) { def valueaux = value as Integer def level = Math.min(valueaux, 99) def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60) def request = [ zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration) ] commands(request) } def setColor(value) { def result = [] if (state.debug) log.debug "setColor: ${value}" if (value.hex) { def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } result << zwave.configurationV1.configurationSet(parameterNumber: 83, size: 3, configurationValue: [c[0], c[1], c[2]]) } if(value.hex) sendEvent(name: "color", value: value.hex) commands(result) } def poll() { if (state.debug) log.debug "poll request sent to ${device.displayName}" def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { if (state.debug) log.debug "refresh request sent to ${device.displayName}" def request = [ zwave.basicV1.basicGet(), zwave.switchMultilevelV1.switchMultilevelGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { if (state.debug) log.debug "reset request sent to ${device.displayName}" def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { if (state.debug) { if (state.sec) { log.debug "secure configuration being sent to ${device.displayName}" } else if (state.debug) log.debug "configuration being sent to ${device.displayName}" } def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } def ledBright = 50 if (ledBrightness) { ledBright=ledBrightness.toInteger() } if (state.debug) log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Set LED brightness zwave.configurationV1.configurationSet(parameterNumber: 84, size: 3, configurationValue: [ledBright,ledBright,ledBright]), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartSwitch 6/device_type-aeon-smartswitch6-v0.1 ================================================ /* * V 0.1 of Aeon Smart Switch 6 code 10/5/2015 * 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: "Aeon Smart Switch 6 - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" /* find homes for these 0x2C COMMAND_CLASS_SCENE_ACTUATOR_CONF 0x2B COMMAND_CLASS_SCENE_ACTIVATION 0x7A COMMAND_CLASS_FIRMWARE_UPDATE_MD 2 0xEF COMMAND_CLASS_MARK 1 0x5A ? 0x5E ? 0x25: 1 0x26: 1 0x27: 1 0x32: 3 0x33: 3 0x56: 0x59: 1 0x70: 1 0x72: 2 0x73: 1 0x82: 1 0x85: 2 0x86: 2 0x25 COMMAND_CLASS_SWITCH_BINARY 1 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL 1 0x27 COMMAND_CLASS_SWITCH_ALL 1 0x32 COMMAND_CLASS_METER 3 0x33 COMMAND_CLASS_COLOR_SWITCH 3 0x56 ? 0x59 COMMAND_CLASS_ASSOCIATION_GRP_INFO 1 0x70 COMMAND_CLASS_CONFIGURATION 1 0x72 COMMAND_CLASS_MANUFACTURER_SPECIFIC 2 0x73 COMMAND_CLASS_POWERLEVEL 1 0x81 COMMAND_CLASS_CLOCK 1 0x82 COMMAND_CLASS_HAIL 1 0x85 COMMAND_CLASS_ASSOCIATION 2 0x86 COMMAND_CLASS_VERSION 2 */ fingerprint deviceId: "0x1001", inClusters: "0x25,0x26,0x27,0x32,0x2C,0x2B,0x33,0x85,0x56,0x59,0x5A,0x5E,0x70,0x72,0x73,0x85,0x86", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } /*standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" }*/ valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","reset","refresh","configure"]) } preferences { input "ledBehavior", "number", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true, range: "0..2" input "monitorInterval", "number", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, range: "1..4294967295‬", required: false, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { delayBetween([ zwave.basicV1.basicSet(value: 0xFF).format(), zwave.basicV1.basicGet().format(), zwave.switchBinaryV1.switchBinaryGet().format() ], 2) } def off() { delayBetween([ zwave.basicV1.basicSet(value: 0x00).format(), zwave.basicV1.basicGet().format(), zwave.switchBinaryV1.switchBinaryGet().format() ], 2) } def poll() { delayBetween([ zwave.switchBinaryV1.switchBinaryGet().format(), zwave.basicV1.basicGet().format(), zwave.meterV3.meterGet(scale: 0).format(), //kWh zwave.meterV3.meterGet(scale: 1).format(), //kVAh zwave.meterV3.meterGet(scale: 2).format(), //Wattage zwave.meterV3.meterGet(scale: 4).format(), //Volts zwave.meterV3.meterGet(scale: 5).format(), //Amps zwave.meterV3.meterGet(scale: 6).format() //Power Factor ], 500) } def refresh() { delayBetween([ zwave.basicV1.basicGet().format(), zwave.switchBinaryV1.switchBinaryGet().format() ], 2) } def reset() { return [ zwave.meterV3.meterReset().format(), zwave.meterV3.meterGet(scale: 0).format(), //kWh zwave.meterV3.meterGet(scale: 2).format() //Wattage ] } def configure() { log.debug "Sending configure commands" def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior } def request = [ // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 15), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 0), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 600), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 600), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartSwitch 6/device_type-aeon-smartswitch6-v0.2 ================================================ /* * V 0.2 of Aeon Smart Switch 6 code 10/5/2015 * 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. * * change log: * v 0.2 - added support for secure inclusion and command encapsulation */ metadata { definition (name: "Aeon Smart Switch 6 - RV v0.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" /* Capability notes 37, 38, 51, 112, 39, 50, 129, 133, 89, 122, 115 0x2C COMMAND_CLASS_SCENE_ACTUATOR_CONF 0x2B COMMAND_CLASS_SCENE_ACTIVATION 0x7A COMMAND_CLASS_FIRMWARE_UPDATE_MD 2 0xEF COMMAND_CLASS_MARK 1 0x5A ? 0x5E ? 0x25: 1 0x26: 1 0x27: 1 0x32: 3 0x33: 3 0x56: 0x59: 1 0x70: 1 0x72: 2 0x73: 1 0x82: 1 0x85: 2 0x86: 2 0x25 COMMAND_CLASS_SWITCH_BINARY 1 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL 1 0x27 COMMAND_CLASS_SWITCH_ALL 1 0x32 COMMAND_CLASS_METER 3 0x33 COMMAND_CLASS_COLOR_SWITCH 3 0x56 ? 0x59 COMMAND_CLASS_ASSOCIATION_GRP_INFO 1 0x70 COMMAND_CLASS_CONFIGURATION 1 0x72 COMMAND_CLASS_MANUFACTURER_SPECIFIC 2 0x73 COMMAND_CLASS_POWERLEVEL 1 0x81 COMMAND_CLASS_CLOCK 1 0x82 COMMAND_CLASS_HAIL 1 0x85 COMMAND_CLASS_ASSOCIATION 2 0x86 COMMAND_CLASS_VERSION 2 */ fingerprint deviceId: "0x1001", inClusters: "0x25,0x26,0x27,0x32,0x2C,0x2B,0x33,0x85,0x56,0x59,0x5A,0x5E,0x70,0x72,0x73,0x85,0x86", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true, range: "0..2" input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, range: "1..4294967295‬", required: false, displayDuringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 // log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartSwitch 6/device_type-aeon-smartswitch6-v0.4 ================================================ /* * V 0.4 of Aeon Smart Switch 6 code 10/5/2015 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * * change log: * v 0.2 - added support for secure inclusion and command encapsulation * v 0.3 - added brightness control and zwave power level node report reporting support (6 second button press) * v 0.4 - added color control for the night light behavior */ metadata { definition (name: "Aeon Smart Switch 6 - RV v0.4", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Color Control" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" fingerprint deviceId: "0x1001", inClusters: "0x98" fingerprint inClusters: "0x25,0x26,0x27,0x32,0x2C,0x2B,0x33,0x85,0x56,0x59,0x5A,0x5E,0x70,0x72,0x73,0x85,0x86", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } controlTile("rgbSelector", "device.color", "color", height: 2, width: 2, inactiveLabel: false) { state "color", action:"setColor" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","rgbSelector","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true, range: "0..2" input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, range: "1..4294967295‬", required: false, displayDuringSetup: true input "ledBrightness", "integer", title: "LED Brightness", description: "Set the % brightness of indicator LEDs", defaultValue: 50, range: "0..100", required: false, displayduringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 // log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def setColor(value) { def result = [] log.debug "setColor: ${value}" if (value.hex) { def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } result << zwave.configurationV1.configurationSet(parameterNumber: 83, size: 3, configurationValue: [c[0], c[1], c[2]]) } if(value.hex) sendEvent(name: "color", value: value.hex) commands(result) } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } def ledBright = 50 if (ledBrightness) { ledBright=ledBrightness.toInteger() } log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Set LED brightness zwave.configurationV1.configurationSet(parameterNumber: 84, size: 3, configurationValue: [ledBright,ledBright,ledBright]), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: Aeon SmartSwitch 6/device_type-aeon-smartswitch6-v0.4-ANDROID ================================================ /* * V 0.4 of Aeon Smart Switch 6 code 10/5/2015 * 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. * * some code used from various SmartThings device type and metering code from ElasticDev * * change log: * v 0.2 - added support for secure inclusion and command encapsulation * v 0.3 - added brightness control and zwave power level node report reporting support (6 second button press) * v 0.4 - added color control for the night light behavior * ANDROID - Thanks Jeff_Pollock and RBoy for pointing out the Range values bug in Android helping to get this workign on Android OS */ metadata { definition (name: "Aeon Smart Switch 6 - RV v0.4", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Color Control" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" fingerprint deviceId: "0x1001", inClusters: "0x98" fingerprint inClusters: "0x25,0x26,0x27,0x32,0x2C,0x2B,0x33,0x85,0x56,0x59,0x5A,0x5E,0x70,0x72,0x73,0x85,0x86", outClusters: "0x82" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } tileAttribute("device.power", key: "SECONDARY_CONTROL") { attributeState "default",label:'${currentValue} W' } } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"poll" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"poll" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"poll" } controlTile("rgbSelector", "device.color", "color", height: 2, width: 2, inactiveLabel: false) { state "color", action:"setColor" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "main","energy","current","voltage" details(["main","energy","current","voltage","rgbSelector","reset","refresh","configure"]) } preferences { input "ledBehavior", "integer", title: "LED Behavior", description: "0=energy tracking, 1=momentary status, 2=night light", defaultValue: 0, displayDuringSetup: true input "monitorInterval", "integer", title: "Monitoring Interval", description: "The time interval in seconds for sending device reports", defaultValue: 60, required: false, displayDuringSetup: true input "ledBrightness", "integer", title: "LED Brightness", description: "Set the % brightness of indicator LEDs", defaultValue: 50, required: false, displayduringSetup: true } } def updated() { if (state.sec && !isConfigured()) { // in case we miss the SCSR response(configure()) } } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } // log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x25: 1, 0x26: 1, 0x27: 1, 0x32: 3, 0x33: 3, 0x59: 1, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2]) state.sec = 1 // log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = Math.round(cmd.scaledMeterValue) break; case 3: //pulses map.value = Math.round(cmd.scaledMeterValue) break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 6: //Power Factor case 7: //Unknown map.value = cmd.scaledMeterValue break; default: break; } //Check if the value has changed by more than 5%, if so mark as a stateChange //map.isStateChange = ((cmd.scaledMeterValue - previousValue).abs() > (cmd.scaledMeterValue * 0.05)) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def setColor(value) { def result = [] log.debug "setColor: ${value}" if (value.hex) { def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } result << zwave.configurationV1.configurationSet(parameterNumber: 83, size: 3, configurationValue: [c[0], c[1], c[2]]) } if(value.hex) sendEvent(name: "color", value: value.hex) commands(result) } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def configure() { def monitorInt = 60 if (monitorInterval) { monitorInt=monitorInterval.toInteger() } def ledBehave = 0 if (ledBehavior) { ledBehave=ledBehavior.toInteger() } def ledBright = 50 if (ledBrightness) { ledBright=ledBrightness.toInteger() } log.debug "Sending configure commands - monitorInterval '${monitorInt}', ledBehavior '${ledBehave}'" def request = [ // Reset switch configuration to defaults // zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1), // Enable to send notifications to associated devices (Group 1) when the state of Micro Switch’s load changed (0=nothing, 1=hail CC, 2=basic CC report) zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, configurationValue: [2]), // set LED behavior 0 energy mode 1 momentary display 2 night light zwave.configurationV1.configurationSet(parameterNumber: 81, size: 1, scaledConfigurationValue: ledBehave), // Set LED brightness zwave.configurationV1.configurationSet(parameterNumber: 84, size: 3, configurationValue: [ledBright,ledBright,ledBright]), // Which reports need to send in Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4|2|1), // Which reports need to send in Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8), // Which reports need to send in Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0), // Interval to send Report group 1 zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt), // Interval to send Report group 2 zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 60), // Interval to send Report group 3 zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0), // get LED behavior zwave.configurationV1.configurationGet(parameterNumber: 81), // get night light RGB value zwave.configurationV1.configurationGet(parameterNumber: 83), // get Energy Mode/momentary indicate LED brightness value zwave.configurationV1.configurationGet(parameterNumber: 84), // Which reports need to send in Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 101), // Which reports need to send in Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 102), // Which reports need to send in Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 103), // Interval to send Report group 1 zwave.configurationV1.configurationGet(parameterNumber: 111), // Interval to send Report group 2 zwave.configurationV1.configurationGet(parameterNumber: 112), // Interval to send Report group 3 zwave.configurationV1.configurationGet(parameterNumber: 113), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=500) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: GE Z-Wave Switch - Improved/device_type-GE-Z-Wave-Switch-Improved ================================================ /** * Created from code Copyright 2015 SmartThings * modified by Robert Vandervoort 6/12/2016 * * 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: "GE/Jasco Z-Wave Switch", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Indicator" capability "Switch" capability "Polling" capability "Refresh" capability "Sensor" capability "Configuration" fingerprint inClusters: "0x25" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles(scale: 2) { multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } } standardTile("indicator", "device.indicatorStatus", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { state "when off", action:"indicator.indicatorWhenOn", icon:"st.indicators.lit-when-off" state "when on", action:"indicator.indicatorNever", icon:"st.indicators.lit-when-on" state "never", action:"indicator.indicatorWhenOff", icon:"st.indicators.never-lit" } standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main "switch" details(["switch","refresh","indicator"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "switchInvert", "boolean", title: "Switch inverted?", defaultValue: false, displayDuringSetup: false } } def updated() { state.debug = ("true" == debugOutput) response(configure()) } def parse(String description) { def result = null def cmd = zwave.parse(description, [0x20: 1, 0x70: 1]) if (cmd) { result = createEvent(zwaveEvent(cmd)) } if (result?.name == 'hail' && hubFirmwareLessThan("000.011.00602")) { result = [result, response(zwave.basicV1.basicGet())] log.debug "Was hailed: requesting state update" } else { log.debug "Parse returned ${result?.descriptionText}" } return result } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical"] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "physical"] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { [name: "switch", value: cmd.value ? "on" : "off", type: "digital"] } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" def value = "when off" if (cmd.configurationValue[0] == 1) {value = "when on"} if (cmd.configurationValue[0] == 2) {value = "never"} [name: "indicatorStatus", value: value, display: true] } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { [name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false] } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { if (state.debug) log.debug "manufacturerId: ${cmd.manufacturerId}" if (state.debug) log.debug "manufacturerName: ${cmd.manufacturerName}" if (state.debug) log.debug "productId: ${cmd.productId}" if (state.debug) log.debug "productTypeId: ${cmd.productTypeId}" def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) updateDataValue("MSR", msr) updateDataValue("manufacturer", cmd.manufacturerName) createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false]) } def zwaveEvent(physicalgraph.zwave.Command cmd) { // Handles all Z-Wave commands we aren't interested in if (state.debug) log.debug cmd } def on() { delayBetween([ zwave.basicV1.basicSet(value: 0xFF).format(), zwave.switchBinaryV1.switchBinaryGet().format() ]) } def off() { delayBetween([ zwave.basicV1.basicSet(value: 0x00).format(), zwave.switchBinaryV1.switchBinaryGet().format() ]) } def poll() { delayBetween([ zwave.switchBinaryV1.switchBinaryGet().format(), zwave.manufacturerSpecificV1.manufacturerSpecificGet().format() ]) } def refresh() { delayBetween([ zwave.switchBinaryV1.switchBinaryGet().format(), zwave.manufacturerSpecificV1.manufacturerSpecificGet().format() ]) } def indicatorWhenOn() { sendEvent(name: "indicatorStatus", value: "when on", display: false) zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format() } def indicatorWhenOff() { sendEvent(name: "indicatorStatus", value: "when off", display: false) zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format() } def indicatorNever() { sendEvent(name: "indicatorStatus", value: "never", display: false) zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format() } def configure() { if (state.debug) log.debug "sending configuration to ${device.displayName}" def invertSwitch = 0 if (switchInvert == true) {invertSwitch = 1} if (switchInvert == false) {invertSwitch = 0} delayBetween([ zwave.configurationV1.configurationSet(scaledConfigurationValue: invertSwitch, parameterNumber: 4, size: 1).format(), zwave.configurationV1.configurationGet(parameterNumber: 0x00).format(), zwave.configurationV1.configurationGet(parameterNumber: 0x04).format() ]) } ================================================ FILE: zooZ-4-in-1-Sensor-ZSE40/device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2 ================================================ /* * V 1.2 of zooZ 4-in-1 sensor code 6/12/2016 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. On the bottom of the zooZ 4-in-1 you will see several small holes. There is a series of four holes and a hole all by itself. You'll need a paperclip or something similar that fits into the hole. While holding the sensor a foot or so from the hub, and with SmartThings in inclusion mode, gently depress the button inside the single hole twice rapidly. The light should blink. Please wait a few moments (usually 10 seconds or so) and you should see "zooZ 4-in-1 sensor - RV 1.0" appear in the found devices area. * Touch the "zooZ 4-in-1 sensor - RV 1.0" to configure. Here we will set your temperature scale preferecne and motion preferences. After you make your choices, touch done in the app. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * In order to get the configuration sent and initial sensor data, we need to wake the sensor up. Press the button on the device one time while holding it close to the hub. If you pressed the button the sensor should blink yellow once. Wait about 30 seconds, then refresh (drag the screen down) and you should see data on the screen for temp, humidity, illuminance, and battery. ** If you do not, please wait a minute or so and refresh the screen again by sliding it down. * If you still do not see anything after refreshing, touch the gear icon to enter the device preferences screen (make any adjustments or not) and then touch done. This will reset the configuration state so the device can be configured again and polled for data. Once you're back at the device screen, while holding the sensor close to the hub, press the small button we pressed earlier one time, making sure that the sensor blinks (if it doesn't, press the button again) and wait a minute or so, then refresh the device screen in the app again. You should see data on the screen now. *** IF YOU STILL ARE NOT GETTING DATA, go back to the preferences screen and enable debug logging, and touch done. You do not need to press the button on the sensor again at this point. Go into the SmartThings IDE and choose "live logging" from the top menu. While on the live logging screen and close to your hub with the sensor, press the button on the sensor, making sure it blinks, and watch the screen for results. You should see several lines of data come in slowly. This should tell you all your settings and what the configuration on the sensor is actually set to. It will then poll the sensors for data. If you do not ever see any data coming from the sensor, please post to the community or message me via github or the SmartThings community. */ metadata { definition (name: "zooZ 4-in-1 sensor - RV 1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Configuration" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 e 0x5E 0x98 0x86 0x72 0x5A 0x85 0x59 0x73 0x80 0x71 0x31 0x70 0x84 0x7A attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x31,0x70,0x5A,0x98,0x7A" } /* simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 2, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } */ tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}°', precision:2, backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue} %', precision:2 } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%', precision:2 } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'LIGHT ${currentValue}%', precision:2 } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery' } main(["main"]) details(["main","humidity","illuminance","motion","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "LEDbehavior", "enum", title: "LED Behavior", options: ["LED Off", "Breathing", "Quick Blink on Temp/PIR"], defaultValue: "Quick Blink on Temp/PIR", required: false, displayDuringSetup: false input "tempoffset", "number", title: "Reporting threshold for temp", description: "Enter a value 1-50 changing reporting threshold for temp. Represents 0.1 degree increments.", range: "1..50", defaultValue: 50, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Reporting threshold for humidity", description: "Report when change occurs from 1%-50% RH)", range: "1..50", defaultValue: 1, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Reporting threshold for Luminance", description: "valid values from 5% to 50%", range: "5..50", defaultValue: 5, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 1-7, from high to low sensitivity (1 is highest)", range: "1..7", defaultValue: 4, required: false, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of minutes to wait to report motion cleared after a motion event if there is no motion detected.", range: "1..255", defaultValue: 5, required: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(checkBattery()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x7A: 2, 0x81: 1, 0x84: 2]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { if (state.debug) log.debug "---SECURITY COMMANDS SUPPORTED REPORT V1--- ${device.displayName} sent commandClassControl: ${cmd.commandClassControl}, commandClassSupport: ${cmd.commandClassSupport}, reportsToFollow: ${cmd.reportsToFollow}" response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true createEvent(map) } else { map.value = cmd.batteryLevel createEvent(map) } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { if (state.debug) log.debug "---SENSOR MULTILEVEL v5 REPORT--- ${device.displayName} sent sensorType: ${cmd.sensorType} value: ${cmd.sensorValue} scale: ${cmd.scale} scaledSensorValue: ${cmd.scaledSensorValue}" def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue map.unit = "%" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue map.unit = "%" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x00 && cmd.eventParameter == 0x08) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } private checkBattery() { def request = [ zwave.batteryV1.batteryGet(), zwave.wakeUpV1.wakeUpNoMoreInformation() ] commands(request) } 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) { // if (state.debug) log.debug "4-in-1 sensor not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration commands to zooZ 4-in-1 sensor--" //if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset" def LEDbehav = 3 if (LEDbehavior == "LED Off") { LEDbehav=1 } else if (LEDbehavior == "Breathing") { LEDbehav=2 } else { LEDbehav=3 } def PIRsens = 4 if (PIRsensitivity) { PIRsens=PIRsensitivity } else { PIRsens = 4 } def MotionRst = 3 if (MotionReset) { MotionRst=MotionReset } else { MotionRst = 3 } def tempoff = 1 if (tempoffset) { tempoff=tempoffset } else { tempoff = 1 } def humidityoff = 10 if (humidityoffset) { humidityoff=humidityoffset } else { humidityoff = 10 } def luminanceoff = 10 if (luminanceoffset) { luminanceoff=luminanceoffset } else { luminanceoff = 10 } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:3600, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // configure temp scale to celcius or fahrenheight and set offset zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0x02), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send no-motion report x minutes after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x05), // set motion sensor sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x06), // set LED behavior zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: LEDbehav), zwave.configurationV1.configurationGet(parameterNumber: 0x07), // get updated battery and sensor data zwave.batteryV1.batteryGet(), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:0), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5, scale:0), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-4-in-1-Sensor-ZSE40/device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2_motion_primary ================================================ /* * V 1.2 of zooZ 4-in-1 sensor code 6/12/2016 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. On the bottom of the zooZ 4-in-1 you will see several small holes. There is a series of four holes and a hole all by itself. You'll need a paperclip or something similar that fits into the hole. While holding the sensor a foot or so from the hub, and with SmartThings in inclusion mode, gently depress the button inside the single hole twice rapidly. The light should blink. Please wait a few moments (usually 10 seconds or so) and you should see "zooZ 4-in-1 sensor - RV 1.0" appear in the found devices area. * Touch the "zooZ 4-in-1 sensor - RV 1.0" to configure. Here we will set your temperature scale preferecne and motion preferences. After you make your choices, touch done in the app. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * In order to get the configuration sent and initial sensor data, we need to wake the sensor up. Press the button on the device one time while holding it close to the hub. If you pressed the button the sensor should blink yellow once. Wait about 30 seconds, then refresh (drag the screen down) and you should see data on the screen for temp, humidity, illuminance, and battery. ** If you do not, please wait a minute or so and refresh the screen again by sliding it down. * If you still do not see anything after refreshing, touch the gear icon to enter the device preferences screen (make any adjustments or not) and then touch done. This will reset the configuration state so the device can be configured again and polled for data. Once you're back at the device screen, while holding the sensor close to the hub, press the small button we pressed earlier one time, making sure that the sensor blinks (if it doesn't, press the button again) and wait a minute or so, then refresh the device screen in the app again. You should see data on the screen now. *** IF YOU STILL ARE NOT GETTING DATA, go back to the preferences screen and enable debug logging, and touch done. You do not need to press the button on the sensor again at this point. Go into the SmartThings IDE and choose "live logging" from the top menu. While on the live logging screen and close to your hub with the sensor, press the button on the sensor, making sure it blinks, and watch the screen for results. You should see several lines of data come in slowly. This should tell you all your settings and what the configuration on the sensor is actually set to. It will then poll the sensors for data. If you do not ever see any data coming from the sensor, please post to the community or message me via github or the SmartThings community. */ metadata { definition (name: "zooZ 4-in-1 sensor - RV 1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Configuration" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 e 0x5E 0x98 0x86 0x72 0x5A 0x85 0x59 0x73 0x80 0x71 0x31 0x70 0x84 0x7A attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x31,0x70,0x5A,0x98,0x7A" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type: "generic", width: 6, height: 4){ tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff" } } valueTile("temperature","device.temperature", width: 2, height: 2) { state "temperature",label:'${currentValue}°', unit:"${unit}", precision:2, backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%', precision:2 } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'LIGHT ${currentValue}%',precision:2 } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery' } main(["main"]) details(["main","temperature","humidity","illuminance","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "LEDbehavior", "enum", title: "LED Behavior", options: ["LED Off", "Breathing", "Quick Blink on Temp/PIR"], defaultValue: "Quick Blink on Temp/PIR", required: false, displayDuringSetup: false input "tempoffset", "number", title: "Reporting threshold for temp", description: "Enter a value 1-50 changing reporting threshold for temp. Represents 0.1 degree increments.", range: "1..50", defaultValue: 50, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Reporting threshold for humidity", description: "Report when change occurs from 1%-50% RH)", range: "1..50", defaultValue: 1, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Reporting threshold for Luminance", description: "valid values from 5% to 50%", range: "5..50", defaultValue: 5, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 1-7, from high to low sensitivity (1 is highest)", range: "1..7", defaultValue: 4, required: false, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of minutes to wait to report motion cleared after a motion event if there is no motion detected.", range: "1..255", defaultValue: 5, required: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(checkBattery()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x7A: 2, 0x81: 1, 0x84: 2]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { if (state.debug) log.debug "---SECURITY COMMANDS SUPPORTED REPORT V1--- ${device.displayName} sent commandClassControl: ${cmd.commandClassControl}, commandClassSupport: ${cmd.commandClassSupport}, reportsToFollow: ${cmd.reportsToFollow}" response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true createEvent(map) } else { map.value = cmd.batteryLevel createEvent(map) } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { if (state.debug) log.debug "---SENSOR MULTILEVEL v5 REPORT--- ${device.displayName} sent sensorType: ${cmd.sensorType} value: ${cmd.sensorValue} scale: ${cmd.scale} scaledSensorValue: ${cmd.scaledSensorValue}" def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue map.unit = "%" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue map.unit = "%" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x00 && cmd.eventParameter == 0x08) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } private checkBattery() { def request = [ zwave.batteryV1.batteryGet(), zwave.wakeUpV1.wakeUpNoMoreInformation() ] commands(request) } 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) { // if (state.debug) log.debug "4-in-1 sensor not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration commands to zooZ 4-in-1 sensor--" //if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset" def LEDbehav = 3 if (LEDbehavior == "LED Off") { LEDbehav=1 } else if (LEDbehavior == "Breathing") { LEDbehav=2 } else { LEDbehav=3 } def PIRsens = 4 if (PIRsensitivity) { PIRsens=PIRsensitivity } else { PIRsens = 4 } def MotionRst = 3 if (MotionReset) { MotionRst=MotionReset } else { MotionRst = 3 } def tempoff = 1 if (tempoffset) { tempoff=tempoffset } else { tempoff = 1 } def humidityoff = 10 if (humidityoffset) { humidityoff=humidityoffset } else { humidityoff = 10 } def luminanceoff = 10 if (luminanceoffset) { luminanceoff=luminanceoffset } else { luminanceoff = 10 } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:3600, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // configure temp scale to celcius or fahrenheight and set offset zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0x02), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send no-motion report x minutes after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x05), // set motion sensor sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x06), // set LED behavior zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: LEDbehav), zwave.configurationV1.configurationGet(parameterNumber: 0x07), // get updated battery and sensor data zwave.batteryV1.batteryGet(), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:0), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5, scale:0), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Indoor-Siren-ZSE01/device_type-zooZ-indoor-siren-v1 ================================================ /* * V 1.0 of zooZ Indoor Siren ZSE01 * 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: "zooZ Indoor Siren ZSE01 - RV v1.0", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Sensor" capability "Polling" capability "Refresh" command "reset" // RAW DESCRIPTION: 0 0 0x1005 0 0 0 9 0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27 fingerprint deviceId: "0x1005", inClusters: "0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27", manufacturer: "zooZ", model: "ZSE01" } // simulator metadata // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'ALARM!', action:'off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("off", "device.alarm", inactiveLabel: false, width: 3, height: 3) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 3, height: 3) { state "battery", label:'${currentValue}% battery', unit:"" } main "alarm" details(["alarm","off","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: false, required: false } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { if (state.debug) log.debug "---DEVICE RESET LOCALLY V1--- ${device.displayName} ${cmd}" createEvent(descriptionText: cmd.toString(), isStateChange: true, displayed: true) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "---ASSOCIATION REPORT--- '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "---HAIL RECEIVED--- ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "---BASIC REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug "---SWITCH BINARY REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug "---SWITCH BINARY SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Siren and Strobe commands received" on() } def on() { if (state.debug) log.debug "Sounding Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF) ] commands(request) } def off() { if (state.debug) log.debug "Cancelling Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def configure() { if (state.debug) log.debug "--Sending configuration commands to zooZ indoor siren--" if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:1200, nodeid:zwaveHubNodeId), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: // zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId), //Get association zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // get updated battery and sensor data zwave.batteryV1.batteryGet(), ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Indoor-Siren-ZSE01/device_type-zooZ-indoor-siren-v1.1 ================================================ /* * V 1.1 of zooZ Indoor Siren ZSE01 * 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: "zooZ Indoor Siren ZSE01 - RV v1.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Sensor" capability "Polling" capability "Refresh" command "reset" command "getbatt" // RAW DESCRIPTION: 0 0 0x1005 0 0 0 9 0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27 fingerprint deviceId: "0x1005", inClusters: "0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27", manufacturer: "zooZ", model: "ZSE01" } // simulator metadata // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'ALARM!', action:'off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("off", "device.alarm", inactiveLabel: false, width: 3, height: 3) { state "default", label:'', action:"off", icon:"st.secondary.off" } valueTile("battery", "device.battery", decoration: "flat", width: 3, height: 3) { state "battery", label:'${currentValue}% battery', unit:"" } main "alarm" details(["alarm","off","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: false, required: false } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { if (state.debug) log.debug "---DEVICE RESET LOCALLY V1--- ${device.displayName} ${cmd}" createEvent(descriptionText: cmd.toString(), isStateChange: true, displayed: true) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "---ASSOCIATION REPORT--- '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { if (state.debug) log.debug "---HAIL RECEIVED--- ${cmd}" } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "---BASIC REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug "---SWITCH BINARY REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug "---SWITCH BINARY SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Siren and Strobe commands received" on() } def on() { if (state.debug) log.debug "Sounding Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF) ] commands(request) } def off() { if (state.debug) log.debug "Cancelling Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def configure() { if (state.debug) log.debug "--Sending configuration commands to zooZ indoor siren--" if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:1200, nodeid:zwaveHubNodeId), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: // zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId), //Get association zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // get updated battery and sensor data zwave.batteryV1.batteryGet(), ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Indoor-Siren-ZSE01/device_type-zooZ-indoor-siren-v1.2 ================================================ /* * V 1.2 of zooZ Indoor Siren ZSE01 * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. * Tap the button on the siren a few times (turning siren on and off) and you should see it appear on the app screen. * tap the discovered device on the app screen to continue. * Now go to your devices list in the SmartThings app and open up the newly added siren. * The configuration will get sent by pressing the button to activate the siren, then tapping again to cancel. * That's it. Remember this is a USB powered device and the batteries are for BACKUP ONLY. There is no battery level indicator by design. */ metadata { definition (name: "zooZ Indoor Siren ZSE01 - RV v1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Actuator" capability "Alarm" capability "Battery" capability "Switch" capability "Sensor" capability "Polling" capability "Refresh" command "reset" // RAW DESCRIPTION: 0 0 0x1005 0 0 0 9 0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27 fingerprint deviceId: "0x1005", inClusters: "0x5E 0x86 0x72 0x73 0x85 0x59 0x25 0x20 0x27", manufacturer: "zooZ", model: "ZSE01" } // simulator metadata // tile definitions tiles (scale: 2) { multiAttributeTile(name:"alarm", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { attributeState "off", label:'OFF', action:'on', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff" attributeState "on", label:'ALARM!', action:'off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13" } } standardTile("off", "device.alarm", inactiveLabel: false, width: 6, height: 4) { state "default", label:'', action:"off", icon:"st.secondary.off" } main "alarm" details(["alarm","off"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: false, required: false } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) def result = createEvent(descriptionText: "${device.displayName} was updated", displayed: true) configure() } def parse(String description) { def result = null if (description != "updated") { def cmd = zwave.parse(description, [0x25: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { if (state.debug) log.debug "---DEVICE RESET LOCALLY V1--- ${device.displayName} ${cmd}" createEvent(descriptionText: cmd.toString(), isStateChange: true, displayed: true) } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { if (state.debug) log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { cmd.nodeId.each({log.debug "---ASSOCIATION REPORT--- '${cmd}', hub: '$zwaveHubNodeId' reports nodeId: '$it' is associated in group: '${cmd.groupingIdentifier}'"}) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { if (state.debug) log.debug "---BASIC REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [ createEvent([name: "switch", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]), createEvent([name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true]) ] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { if (state.debug) log.debug "---SWITCH BINARY REPORT V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "physical", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinarySet cmd) { if (state.debug) log.debug "---SWITCH BINARY SET V1--- ${device.displayName} sent value: ${cmd.value}" [name: "alarm", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true] } def zwaveEvent(physicalgraph.zwave.Command cmd) { if (state.debug) log.debug "Unhandled: $cmd sent to ${device.displayName}" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def siren() { if (state.debug) log.debug "Siren command received" on() } def both() { if (state.debug) log.debug "Siren and Strobe commands received" on() } def on() { if (state.debug) log.debug "Sounding Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet() ] commands(request) } def off() { if (state.debug) log.debug "Cancelling Alarm : ${device.displayName}" def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet() ] commands(request) } def configure() { if (state.debug) log.debug "--Sending configuration commands to zooZ indoor siren--" if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ //Get association zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), ] commands(request) } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-MiniPlug-ZEN07/device_type-zooZ-4-in-1-Sensor-ZSE40_v1.2.groovy ================================================ /* * V 1.2 of zooZ 4-in-1 sensor code 6/12/2016 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. On the bottom of the zooZ 4-in-1 you will see several small holes. There is a series of four holes and a hole all by itself. You'll need a paperclip or something similar that fits into the hole. While holding the sensor a foot or so from the hub, and with SmartThings in inclusion mode, gently depress the button inside the single hole twice rapidly. The light should blink. Please wait a few moments (usually 10 seconds or so) and you should see "zooZ 4-in-1 sensor - RV 1.0" appear in the found devices area. * Touch the "zooZ 4-in-1 sensor - RV 1.0" to configure. Here we will set your temperature scale preferecne and motion preferences. After you make your choices, touch done in the app. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * In order to get the configuration sent and initial sensor data, we need to wake the sensor up. Press the button on the device one time while holding it close to the hub. If you pressed the button the sensor should blink yellow once. Wait about 30 seconds, then refresh (drag the screen down) and you should see data on the screen for temp, humidity, illuminance, and battery. ** If you do not, please wait a minute or so and refresh the screen again by sliding it down. * If you still do not see anything after refreshing, touch the gear icon to enter the device preferences screen (make any adjustments or not) and then touch done. This will reset the configuration state so the device can be configured again and polled for data. Once you're back at the device screen, while holding the sensor close to the hub, press the small button we pressed earlier one time, making sure that the sensor blinks (if it doesn't, press the button again) and wait a minute or so, then refresh the device screen in the app again. You should see data on the screen now. *** IF YOU STILL ARE NOT GETTING DATA, go back to the preferences screen and enable debug logging, and touch done. You do not need to press the button on the sensor again at this point. Go into the SmartThings IDE and choose "live logging" from the top menu. While on the live logging screen and close to your hub with the sensor, press the button on the sensor, making sure it blinks, and watch the screen for results. You should see several lines of data come in slowly. This should tell you all your settings and what the configuration on the sensor is actually set to. It will then poll the sensors for data. If you do not ever see any data coming from the sensor, please post to the community or message me via github or the SmartThings community. */ metadata { definition (name: "zooZ 4-in-1 sensor - RV 1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Illuminance Measurement" capability "Configuration" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 e 0x5E 0x98 0x86 0x72 0x5A 0x85 0x59 0x73 0x80 0x71 0x31 0x70 0x84 0x7A attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x31,0x70,0x5A,0x98,0x7A" } /* simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i = 0; i <= 100; i += 20) { status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, precision: 2, sensorType: 1, scale: 1 ) ).incomingMessage() } for (int i = 0; i <= 100; i += 20) { status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 5 ) ).incomingMessage() } for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) { status "illuminance ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport( scaledSensorValue: i, sensorType: 3 ) ).incomingMessage() } for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } */ tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState "temperature",label:'${currentValue}°', precision:2, backgroundColors:[ [value: 32, color: "#153591"], [value: 44, color: "#1e9cbb"], [value: 59, color: "#90d2a7"], [value: 74, color: "#44b621"], [value: 84, color: "#f1d801"], [value: 92, color: "#d04e00"], [value: 98, color: "#bc2323"] ] } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState "humidity",label:'RH ${currentValue} %', precision:2 } } standardTile("motion","device.motion", width: 2, height: 2) { state "active",label:'motion',icon:"st.motion.motion.active",backgroundColor:"#53a7c0" state "inactive",label:'no motion',icon:"st.motion.motion.inactive",backgroundColor:"#ffffff" } valueTile("humidity","device.humidity", width: 2, height: 2) { state "humidity",label:'RH ${currentValue}%', precision:2 } valueTile("illuminance","device.illuminance", width: 2, height: 2) { state "luminosity",label:'LIGHT ${currentValue}%', precision:2 } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery' } main(["main"]) details(["main","humidity","illuminance","motion","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "LEDbehavior", "enum", title: "LED Behavior", options: ["LED Off", "Breathing", "Quick Blink on Temp/PIR"], defaultValue: "Quick Blink on Temp/PIR", required: false, displayDuringSetup: false input "tempoffset", "number", title: "Reporting threshold for temp", description: "Enter a value 1-50 changing reporting threshold for temp. Represents 0.1 degree increments.", range: "1..50", defaultValue: 50, required: false, displayDuringSetup: false input "humidityoffset", "number", title: "Reporting threshold for humidity", description: "Report when change occurs from 1%-50% RH)", range: "1..50", defaultValue: 1, required: false, displayDuringSetup: false input "luminanceoffset", "number", title: "Reporting threshold for Luminance", description: "valid values from 5% to 50%", range: "5..50", defaultValue: 5, required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 1-7, from high to low sensitivity (1 is highest)", range: "1..7", defaultValue: 4, required: false, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of minutes to wait to report motion cleared after a motion event if there is no motion detected.", range: "1..255", defaultValue: 5, required: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 2]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(checkBattery()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x7A: 2, 0x81: 1, 0x84: 2]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { if (state.debug) log.debug "---SECURITY COMMANDS SUPPORTED REPORT V1--- ${device.displayName} sent commandClassControl: ${cmd.commandClassControl}, commandClassSupport: ${cmd.commandClassSupport}, reportsToFollow: ${cmd.reportsToFollow}" response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true createEvent(map) } else { map.value = cmd.batteryLevel createEvent(map) } state.lastbatt = now() createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { if (state.debug) log.debug "---SENSOR MULTILEVEL v5 REPORT--- ${device.displayName} sent sensorType: ${cmd.sensorType} value: ${cmd.sensorValue} scale: ${cmd.scale} scaledSensorValue: ${cmd.scaledSensorValue}" def map = [:] switch (cmd.sensorType) { case 1: map.name = "temperature" def cmdScale = cmd.scale == 1 ? "F" : "C" map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.unit = getTemperatureScale() break; case 3: map.name = "illuminance" map.value = cmd.scaledSensorValue map.unit = "%" break; case 5: map.name = "humidity" map.value = cmd.scaledSensorValue map.unit = "%" break; default: map.descriptionText = cmd.toString() } createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x00 && cmd.eventParameter == 0x08) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } private checkBattery() { def request = [ zwave.batteryV1.batteryGet(), zwave.wakeUpV1.wakeUpNoMoreInformation() ] commands(request) } 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) { // if (state.debug) log.debug "4-in-1 sensor not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration commands to zooZ 4-in-1 sensor--" //if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset" def LEDbehav = 3 if (LEDbehavior == "LED Off") { LEDbehav=1 } else if (LEDbehavior == "Breathing") { LEDbehav=2 } else { LEDbehav=3 } def PIRsens = 4 if (PIRsensitivity) { PIRsens=PIRsensitivity } else { PIRsens = 4 } def MotionRst = 3 if (MotionReset) { MotionRst=MotionReset } else { MotionRst = 3 } def tempoff = 1 if (tempoffset) { tempoff=tempoffset } else { tempoff = 1 } def humidityoff = 10 if (humidityoffset) { humidityoff=humidityoffset } else { humidityoff = 10 } def luminanceoff = 10 if (luminanceoffset) { luminanceoff=luminanceoffset } else { luminanceoff = 10 } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:3600, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // configure temp scale to celcius or fahrenheight and set offset zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 1, scaledConfigurationValue: tempoff), zwave.configurationV1.configurationGet(parameterNumber: 0x02), // configure humidity offset zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: humidityoff), zwave.configurationV1.configurationGet(parameterNumber: 0x03), // configure luminance offset zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: luminanceoff), zwave.configurationV1.configurationGet(parameterNumber: 0x04), // send no-motion report x minutes after motion stops zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: MotionRst), zwave.configurationV1.configurationGet(parameterNumber: 0x05), // set motion sensor sensitivity zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: PIRsens), zwave.configurationV1.configurationGet(parameterNumber: 0x06), // set LED behavior zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: LEDbehav), zwave.configurationV1.configurationGet(parameterNumber: 0x07), // get updated battery and sensor data zwave.batteryV1.batteryGet(), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:0), zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5, scale:0), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-MiniPlug-ZEN07/device_type-zooZ-MiniPlug-ZEN07-v1.1.groovy ================================================ /* zooZ MiniPlug ZEN07 device handler for SmartThings version 1.0 by Robert Vandervoort 10/10/2016 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. some code used from various SmartThings device type and metering code from ElasticDev */ metadata { definition (name: "zooZ MiniPlug ZEN07 - RV v1.0", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" command "getPower" command "getEnergy" command "getVolts" command "getCurrent" command "checkstate" // RAW 0 0 0x1001 0 0 0 d 0x5E 0x72 0x86 0x85 0x59 0x5A 0x73 0x70 0x25 0x27 0x71 0x32 0x20 // MSR 027A-0003-0087 fingerprint deviceId: "0x1001", inClusters: "0x5E,0x72,0x86,0x85,0x59,0x5A,0x73,0x70,0x25,0x27,0x71,0x32,0x20" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { multiAttributeTile(name:"main", type:"generic", width:6, height:4, canChangeIcon: true) { tileAttribute("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } } valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} W', action:"getPower" } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"getEnergy" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"getCurrent" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"getVoltage" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'config', action:"configure", icon:"st.secondary.refresh" } standardTile("check", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'check', action:"checkstate" } main "main" details(["main","power","energy","current","voltage","reset","refresh","configure", "check"]) } preferences { input "energyReporting", "boolean", title: "Energy usage reports", defaultValue: true, displayDuringSetup: true input "reportInterval", "integer", title: "Energy report interval", description: "The time interval in seconds for sending energy usage reports", defaultValue: 300, range: "1..4294967295‬", required: false, displayDuringSetup: false input "reportThreshold", "integer", title: "Reporting threshold", description: "The percentage of change required for sending energy usage reports", defaultValue: 5, range: "1..99", required: false, displayDuringSetup: false input "loadWarning", "integer", title: "Load warning AMPs", description: "Set to a value in AMPs to provide heavy load warning notification.", defaultValue: 12, range: "1..12", required: false, displayDuringSetup: false input "overloadProtection", "integer", title: "Overload protection AMPs", description: "Must be higher than heavy load warning value. When this value is reached, the plug shuts down and must be reset.", defaultValue: 13, range: "1..15", required: false, displayDuringSetup: false input "manualOverride", "boolean", title: "Switch manual control", description: "Enable or disable the switch on the plug. Good for tamper protection.", defaultValue: true, displayDuringSetup: false input "stateRecvovery", "boolean", title: "Return to last state after power failure?", defaultValue: true, displayDuringSetup: false input "ledNotifications", "boolean", title: "LED Notifications?", description: "Enables or disables LED color change for heavy and overload notifications.", defaultValue: true, displayDuringSetup: false input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) configure() } def parse(String description) { def result = null def cmd = zwave.parse(description) if (cmd) { result = zwaveEvent(cmd) if (state.debug) log.debug "Parsed ${cmd} to ${result.inspect()}" } else { log.debug "Non-parsed event: ${description}" } return result } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug("ConfigurationReportv1 ${cmd.inspect()}") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { state.configParams << [(cmd.parameterNumber) : (cmd.configurationValue)] log.debug state.configParams } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationBulkReport cmd) { log.debug "Got a bulk report, but don't know what to do with it." } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport 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) createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false], displayed = true) } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; } map.isStateChange = true map.displayed = true createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "physical", displayed: true, isStateChange: true)] return result } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "digital", displayed: true, isStateChange: true)] return result } def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def checkstate() { // check our config state map log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" } def getPower() { zwave.meterV3.meterGet(scale: 2).format() //Wattage } def getVoltage() { zwave.meterV3.meterGet(scale: 4).format() //Volts } def getEnergy() { zwave.meterV3.meterGet(scale: 0).format() //kWh } def getCurrent() { zwave.meterV3.meterGet(scale: 5).format() //Amps } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.basicV1.basicGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def refresh() { def request = [ zwave.basicV1.basicGet(), zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps zwave.meterV3.meterGet(scale: 6) //Power Factor ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5) //Amps ] commands(request) } def configure() { def request = [ // Get version and firmware info zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // get all the config values zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationGet(parameterNumber: 0x02), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x05), zwave.configurationV1.configurationGet(parameterNumber: 0x06), zwave.configurationV1.configurationGet(parameterNumber: 0x07), zwave.configurationV1.configurationGet(parameterNumber: 0x08), zwave.configurationV1.configurationGet(parameterNumber: 0x09), zwave.configurationV1.configurationGet(parameterNumber: 0x0A), //this doesn't seem to work in ST... //zwave.configurationV2.configurationBulkGet (parameterOffset: 0x0001, numberOfParameters: 10), // enable or disable energy metering reports 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: 1), // Interval in seconds for sending energy metering reports zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 2, scaledConfigurationValue: 300), // Overload protection - set the number of AMPS you want to limit the plug to. 13 is what it is designed for. // when this value is hit, overload notification messages are sent and you have to press the button on the plug to reset it. zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: 13), // Heavy load warning AMP threshold - the plug led will turn yellow when you reach this AMP value. must be less than parameter 3/ zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: 12), // LED Notifications - 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 1), // percentage of change in any energy metric for a report to be sent - threshold reporting zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: 5), // power failure recovery state - 0=remain off when power restored 1=return to last state when power restored zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: 1), // auto power off timer - 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 12), // auto power off timer duration - a value in minutes 1-65535 zwave.configurationV1.configurationSet(parameterNumber: 0x09, size: 2, scaledConfigurationValue: 150), // manual control power on/off control - 0=disable action button 1=enable action button zwave.configurationV1.configurationSet(parameterNumber: 0x0A, size: 1, scaledConfigurationValue: 1), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + setConfigured() } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1250) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-MiniPlug-ZEN07/device_type-zooZ-MiniPlug-ZEN07-v1.2.groovy ================================================ /* zooZ MiniPlug ZEN07 device handler for SmartThings version 1.0 by Robert Vandervoort 10/10/2016 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. some code used from various SmartThings device type and metering code from ElasticDev */ metadata { definition (name: "zooZ MiniPlug ZEN07 - RV v1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Indicator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" command "getPower" command "getEnergy" command "getVoltage" command "getCurrent" command "checkstate" command "timerOn" command "timerOff" attribute "timerStatus", "enum", ["On", "Off"] // RAW 0 0 0x1001 0 0 0 d 0x5E 0x72 0x86 0x85 0x59 0x5A 0x73 0x70 0x25 0x27 0x71 0x32 0x20 // MSR 027A-0003-0087 fingerprint deviceId: "0x1001", inClusters: "0x5E,0x72,0x86,0x85,0x59,0x5A,0x73,0x70,0x25,0x27,0x71,0x32,0x20" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { standardTile("main", "device.switch", width:4, height:4, canChangeIcon: true) { state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} W', action:"getPower" } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"getEnergy" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"getCurrent" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"getVoltage" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'config', action:"configure", icon:"st.secondary.refresh" } standardTile("check", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'check', action:"checkstate" } standardTile("timer", "device.timerStatus", inactiveLabel: false, decoration: "flat", width:2, height:2) { state "off", label:'TIMER', action:"timerOn", icon: "st.illuminance.illuminance.dark" state "on", label:'TIMER', action:"timerOff", icon: "st.illuminance.illuminance.bright" } standardTile("indicator", "device.indicatorStatus", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "never", label:'LED', action:"indicator.indicatorWhenOn", icon: "st.illuminance.illuminance.dark" state "when on", label:'LED', action:"indicator.indicatorNever", icon: "st.illuminance.illuminance.bright" } main "main" details(["main","energy","reset","voltage","power","current","refresh","timer","indicator"]) } preferences { input "energyReporting", "boolean", title: "Energy usage reports", defaultValue: true, displayDuringSetup: true input "reportInterval", "integer", title: "Energy report interval", description: "The time interval in seconds for sending energy usage reports", defaultValue: 300, range: "1..4294967295‬", required: false, displayDuringSetup: false input "reportThreshold", "integer", title: "Reporting threshold", description: "The percentage of change required for sending energy usage reports", defaultValue: 5, range: "1..99", required: false, displayDuringSetup: false input "loadWarning", "integer", title: "Load warning AMPs", description: "Set to a value in AMPs to provide heavy load warning notification.", defaultValue: 12, range: "1..12", required: false, displayDuringSetup: false input "overloadProtection", "integer", title: "Overload protection AMPs", description: "Must be higher than heavy load warning value. When this value is reached, the plug shuts down and must be reset.", defaultValue: 13, range: "1..15", required: false, displayDuringSetup: false input "manualOverride", "boolean", title: "Switch manual control", description: "Enable or disable the switch on the plug. Good for tamper protection.", defaultValue: true, displayDuringSetup: false input "stateRecvovery", "boolean", title: "Return to last state after power failure?", defaultValue: true, displayDuringSetup: false input "ledNotifications", "boolean", title: "LED Notifications?", description: "Enables or disables LED color change for heavy and overload notifications.", defaultValue: true, displayDuringSetup: false input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) configure() } def parse(String description) { def result = null def cmd = zwave.parse(description) if (cmd) { result = zwaveEvent(cmd) if (state.debug) log.debug "Parsed ${cmd} to ${result.inspect()}" } else { log.debug "Non-parsed event: ${description}" } return result } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug("ConfigurationReportv1 ${cmd.inspect()}") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { //state.configParams.clear() // calculate decimal values for returned multibyte values def fullValue = 0 switch(cmd.size) { case 1: //1 byte fullValue = cmd.configurationValue * 1 break; case 2: //2 byte fullValue = cmd.configurationValue[1] + (cmd.configurationValue[0] * 0x100) break; case 3: //3 byte fullValue = cmd.configurationValue[2] + (cmd.configurationValue[1] * 0x100) + (cmd.configurationValue[0] * 0x10000) break; case 4: //4 byte fullValue = cmd.configurationValue[3] + (cmd.configurationValue[2] * 0x100) + (cmd.configurationValue[1] * 0x10000) + (cmd.configurationValue[0] * 0x1000000) break; } state.configParams << [(cmd.parameterNumber) : (fullValue)] // set states for any values coming in used for tiles def statusValue = [:] switch(cmd.parameterNumber) { case 5: //LED Indicator statusValue.name = "indicatorStatus" if (cmd.configurationValue == [0]) { statusValue.value = "never" } else if (cmd.configurationValue == [1]) { statusValue.value = "when on" } break; case 8: //Automatic shutoff timer statusValue.name = "timerStatus" if (cmd.configurationValue == [0]) { statusValue.value = "off" } else if (cmd.configurationValue == [1]) { statusValue.value = "on" } break; } statusValue.displayed = true createEvent(statusValue) //log.debug state.configParams } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationBulkReport cmd) { log.debug "Got a bulk report, but don't know what to do with it." } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport 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) createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false], displayed = true) } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; } map.isStateChange = true map.displayed = true createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "physical", displayed: true, isStateChange: true)] return result } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "digital", displayed: true, isStateChange: true)] return result } // parse the unhandled def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } // Commands follow def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def checkstate() { // check our config state map log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" state.configParams.each {parameter, value -> log.debug "Parameter ${parameter} = ${value}"} // LED Notifications - 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 0).format() /* if (state.configParams.(4) == [12]) { log.debug "this was true" } else log.debug "This was false :(" */ } def getEnergy() { zwave.meterV3.meterGet(scale: 0).format() //kWh } def getPower() { zwave.meterV3.meterGet(scale: 2).format() //Wattage } def getVoltage() { zwave.meterV3.meterGet(scale: 4).format() //Volts } def getCurrent() { zwave.meterV3.meterGet(scale: 5).format() //Amps } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def refresh() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5) //Amps ] commands(request) } def indicatorWhenOn() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 0x05, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def indicatorNever() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 5, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def timerOn() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def timerOff() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def configure() { /* ['1':[1],'2':[1, 44],'3':[13], '4':[12], '5':[1], '6':[5],'7':[1], '8':[0]],'9':[0, 150],'10':[1] if (energyReporting != state.configParams[1]) { confParam = energyReporting loadWarning integer 12 manualOverride boolean true overloadProtection integer 13 reportInterval integer 300 reportThreshold integer 5 stateRecvovery */ def request = [ // Get version and firmware info zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // get all the config values zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationGet(parameterNumber: 0x02), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x05), zwave.configurationV1.configurationGet(parameterNumber: 0x06), zwave.configurationV1.configurationGet(parameterNumber: 0x07), zwave.configurationV1.configurationGet(parameterNumber: 0x08), zwave.configurationV1.configurationGet(parameterNumber: 0x09), zwave.configurationV1.configurationGet(parameterNumber: 0x0A), /* //this doesn't seem to work in ST... //zwave.configurationV2.configurationBulkGet (parameterOffset: 0x0001, numberOfParameters: 10), // enable or disable energy metering reports 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: confParam1), // Interval in seconds for sending energy metering reports zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 2, scaledConfigurationValue: confParam2), // Overload protection - set the number of AMPS you want to limit the plug to. 13 is what it is designed for. // when this value is hit, overload notification messages are sent and you have to press the button on the plug to reset it. zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: confParam3), // Heavy load warning AMP threshold - the plug led will turn yellow when you reach this AMP value. must be less than parameter 3/ zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: confParam4), // LED Notifications - 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: confParam5), // percentage of change in any energy metric for a report to be sent - threshold reporting zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: confParam6), // power failure recovery state - 0=remain off when power restored 1=return to last state when power restored zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: confParam7), // auto power off timer - 0=disabled 1=enabled zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: confParam8), // auto power off timer duration - a value in minutes 1-65535 zwave.configurationV1.configurationSet(parameterNumber: 0x09, size: 2, scaledConfigurationValue: confParam9), // manual control power on/off control - 0=disable action button 1=enable action button zwave.configurationV1.configurationSet(parameterNumber: 0x0A, size: 1, scaledConfigurationValue: confParam10), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) */] commands(request) + setConfigured() } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1250) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-MiniPlug-ZEN07/device_type-zooZ-MiniPlug-ZEN07-v1.3.groovy ================================================ /* zooZ MiniPlug ZEN07 device handler for SmartThings version 1.0 by Robert Vandervoort 10/10/2016 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. some code used from various SmartThings device type and metering code from ElasticDev */ metadata { definition (name: "zooZ MiniPlug ZEN07 - RV v1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Indicator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" command "getPower" command "getEnergy" command "getVoltage" command "getCurrent" command "checkstate" command "timerOn" command "timerOff" attribute "timerStatus", "enum", ["On", "Off"] // RAW 0 0 0x1001 0 0 0 d 0x5E 0x72 0x86 0x85 0x59 0x5A 0x73 0x70 0x25 0x27 0x71 0x32 0x20 // MSR 027A-0003-0087 fingerprint deviceId: "0x1001", inClusters: "0x5E,0x72,0x86,0x85,0x59,0x5A,0x73,0x70,0x25,0x27,0x71,0x32,0x20" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { standardTile("main", "device.switch", width:4, height:4, canChangeIcon: true) { state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} W', action:"getPower" } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"getEnergy" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"getCurrent" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"getVoltage" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'config', action:"configure", icon:"st.secondary.refresh" } standardTile("check", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'check', action:"checkstate" } standardTile("timer", "device.timerStatus", inactiveLabel: false, decoration: "flat", width:2, height:2) { state "off", label:'TIMER', action:"timerOn", icon: "st.illuminance.illuminance.dark" state "on", label:'TIMER', action:"timerOff", icon: "st.illuminance.illuminance.bright" } standardTile("indicator", "device.indicatorStatus", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "never", label:'LED', action:"indicator.indicatorWhenOn", icon: "st.illuminance.illuminance.dark" state "when on", label:'LED', action:"indicator.indicatorNever", icon: "st.illuminance.illuminance.bright" } main "main" details(["main","energy","reset","voltage","power","current","refresh","timer","indicator","check"]) } preferences { input "energyReporting", "boolean", title: "Energy usage reports", defaultValue: true, displayDuringSetup: true input "reportInterval", "integer", title: "Energy report interval", description: "The time interval in seconds for sending energy usage reports", defaultValue: 300, range: "1..4294967295‬", required: false, displayDuringSetup: false input "reportThreshold", "integer", title: "Reporting threshold", description: "The percentage of change required for sending energy usage reports", defaultValue: 5, range: "1..99", required: false, displayDuringSetup: false input "loadWarning", "integer", title: "Load warning AMPs", description: "Set to a value in AMPs to provide heavy load warning notification.", defaultValue: 12, range: "1..12", required: false, displayDuringSetup: false input "overloadProtection", "integer", title: "Overload protection AMPs", description: "Must be higher than heavy load warning value. When this value is reached, the plug shuts down and must be reset.", defaultValue: 13, range: "1..15", required: false, displayDuringSetup: false input "manualOverride", "boolean", title: "Switch manual control", description: "Enable or disable the switch on the plug. Good for tamper protection.", defaultValue: true, displayDuringSetup: false input "stateRecvovery", "boolean", title: "Return to last state after power failure?", defaultValue: true, displayDuringSetup: false input "ledNotifications", "boolean", title: "LED Notifications?", description: "Enables or disables LED color change for heavy and overload notifications.", defaultValue: true, displayDuringSetup: false input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { //state.configParams.clear() updateDataValue("configured", "false") state.debug = ("true" == debugOutput) configure() } def parse(String description) { def result = null def cmd = zwave.parse(description) if (cmd) { result = zwaveEvent(cmd) if (state.debug) log.debug "Parsed ${cmd} to ${result.inspect()}" } else { log.debug "Non-parsed event: ${description}" } return result } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug("ConfigurationReportv1 ${cmd.inspect()}") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { // calculate decimal values for returned multibyte values def fullValue = 0 switch(cmd.size) { case 1: //1 byte fullValue = cmd.configurationValue * 1 break; case 2: //2 byte fullValue = cmd.configurationValue[1] + (cmd.configurationValue[0] * 0x100) break; case 3: //3 byte fullValue = cmd.configurationValue[2] + (cmd.configurationValue[1] * 0x100) + (cmd.configurationValue[0] * 0x10000) break; case 4: //4 byte fullValue = cmd.configurationValue[3] + (cmd.configurationValue[2] * 0x100) + (cmd.configurationValue[1] * 0x10000) + (cmd.configurationValue[0] * 0x1000000) break; } state.configParams << [(cmd.parameterNumber) : (fullValue)] // set states for any values coming in used for tiles def statusValue = [:] switch(cmd.parameterNumber) { case 5: //LED Indicator statusValue.name = "indicatorStatus" if (cmd.configurationValue == [0]) { statusValue.value = "never" } else if (cmd.configurationValue == [1]) { statusValue.value = "when on" } break; case 8: //Automatic shutoff timer statusValue.name = "timerStatus" if (cmd.configurationValue == [0]) { statusValue.value = "off" } else if (cmd.configurationValue == [1]) { statusValue.value = "on" } break; } statusValue.displayed = true createEvent(statusValue) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationBulkReport cmd) { log.debug "Got a bulk report, but don't know what to do with it." } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport 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) createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false], displayed = true) } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; } map.isStateChange = true map.displayed = true createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "physical", displayed: true, isStateChange: true)] return result } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "digital", displayed: true, isStateChange: true)] return result } // parse the unhandled def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } // Commands follow def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def checkstate() { // check our config state map log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" state.configParams.each {parameter, value -> log.debug "Parameter ${parameter} = ${value}"} // LED Notifications - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 0).format() /* if (state.configParams.(4) == [12]) { log.debug "this was true" } else log.debug "This was false :(" */ } def getEnergy() { zwave.meterV3.meterGet(scale: 0).format() //kWh } def getPower() { zwave.meterV3.meterGet(scale: 2).format() //Wattage } def getVoltage() { zwave.meterV3.meterGet(scale: 4).format() //Volts } def getCurrent() { zwave.meterV3.meterGet(scale: 5).format() //Amps } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def refresh() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5) //Amps ] commands(request) } def indicatorWhenOn() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 0x05, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def indicatorNever() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 5, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def timerOn() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def timerOff() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def configure() { def request = [ //this doesn't seem to work in ST... //zwave.configurationV2.configurationBulkGet (parameterOffset: 0x0001, numberOfParameters: 10), // Get version and firmware info zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // get all the config values zwave.configurationV1.configurationGet(parameterNumber: 0x01), zwave.configurationV1.configurationGet(parameterNumber: 0x02), zwave.configurationV1.configurationGet(parameterNumber: 0x03), zwave.configurationV1.configurationGet(parameterNumber: 0x04), zwave.configurationV1.configurationGet(parameterNumber: 0x05), zwave.configurationV1.configurationGet(parameterNumber: 0x06), zwave.configurationV1.configurationGet(parameterNumber: 0x07), zwave.configurationV1.configurationGet(parameterNumber: 0x08), zwave.configurationV1.configurationGet(parameterNumber: 0x09), zwave.configurationV1.configurationGet(parameterNumber: 0x0A) ] commands(request) + setConfigured() /* // set things that need to be set because their setting doesn't match what we want it to be set to def configSend = [:] // enable or disable energy metering reports 0=disabled 1=enabled int energyReportingInt = energyReporting? 1 : 0; log.debug energyReportingInt if (state.configParams.(1) != energyReportingInt) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: energyReporting) } // Interval in seconds for sending energy metering reports if (state.configParams.(2) != reportInterval) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 2, scaledConfigurationValue: reportInterval) } // Overload protection - set the number of AMPS you want to limit the plug to. 13 is what it is designed for. // when this value is hit, overload notification messages are sent and you have to press the button on the plug to reset it. if (state.configParams.(3) != overloadProtection) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: overloadProtection) } // Heavy load warning AMP threshold - the plug led will turn yellow when you reach this AMP value. must be less than parameter 3/ if (state.configParams.(4) != loadWarning) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: loadWarning) } // LED Notifications - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: confParam5), // percentage of change in any energy metric for a report to be sent - threshold reporting if (state.configParams.(6) != reportThreshold) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: reportThreshold) } // power failure recovery state - 0=remain off when power restored 1=return to last state when power restored if (state.configParams.(7) != stateRecvovery) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: stateRecvovery) } // auto power off timer - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: confParam8), // auto power off timer duration - a value in minutes 1-65535 // zwave.configurationV1.configurationSet(parameterNumber: 0x09, size: 2, scaledConfigurationValue: confParam9), // manual control power on/off control - 0=disable action button 1=enable action button if (state.configParams.(10) != manualOverride) { configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x0A, size: 1, scaledConfigurationValue: manualOverride) } // Can use the zwaveHubNodeId variable to add the hub to the device's associations: request << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) commands(configSend) + setConfigured() */ } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1250) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-MiniPlug-ZEN07/device_type-zooZ-MiniPlug-ZEN07-v1.4.groovy ================================================ /* zooZ MiniPlug ZEN07 device handler for SmartThings version 1.0 by Robert Vandervoort 10/10/2016 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. some code used from various SmartThings device type and metering code from ElasticDev */ metadata { definition (name: "zooZ MiniPlug ZEN07 - RV v1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Energy Meter" capability "Power Meter" capability "Actuator" capability "Indicator" capability "Switch" capability "Configuration" capability "Polling" capability "Refresh" capability "Sensor" command "reset" command "getPower" command "getEnergy" command "getVoltage" command "getCurrent" command "checkstate" command "timerOn" command "timerOff" attribute "timerStatus", "enum", ["On", "Off"] // RAW 0 0 0x1001 0 0 0 d 0x5E 0x72 0x86 0x85 0x59 0x5A 0x73 0x70 0x25 0x27 0x71 0x32 0x20 // MSR 027A-0003-0087 fingerprint deviceId: "0x1001", inClusters: "0x5E,0x72,0x86,0x85,0x59,0x5A,0x73,0x70,0x25,0x27,0x71,0x32,0x20" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" for (int i = 0; i <= 10000; i += 1000) { status "power ${i} W": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() } for (int i = 0; i <= 100; i += 10) { status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() } // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles (scale: 2) { standardTile("main", "device.switch", width:4, height:4, canChangeIcon: true) { state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} W', action:"getPower" } valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} kWh', action:"getEnergy" } valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} A', action:"getCurrent" } valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 2) { state "default", label:'${currentValue} V', action:"getVoltage" } standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'reset kWh', action:"reset" } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'config', action:"configure", icon:"st.secondary.refresh" } standardTile("check", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:'check', action:"checkstate" } standardTile("timer", "device.timerStatus", inactiveLabel: false, decoration: "flat", width:2, height:2) { state "off", label:'TIMER', action:"timerOn", icon: "st.illuminance.illuminance.dark" state "on", label:'TIMER', action:"timerOff", icon: "st.illuminance.illuminance.bright" } standardTile("indicator", "device.indicatorStatus", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "never", label:'LED', action:"indicator.indicatorWhenOn", icon: "st.illuminance.illuminance.dark" state "when on", label:'LED', action:"indicator.indicatorNever", icon: "st.illuminance.illuminance.bright" } main "main" details(["main","energy","reset","voltage","power","current","refresh","timer","indicator","check","configure"]) } preferences { input "energyReporting", "boolean", title: "Energy usage reports", defaultValue: true, displayDuringSetup: true input "reportInterval", "integer", title: "Energy report interval", description: "The time interval in seconds for sending energy usage reports", defaultValue: 300, range: "1..4294967295‬", required: false, displayDuringSetup: false input "reportThreshold", "integer", title: "Reporting threshold", description: "The percentage of change required for sending energy usage reports", defaultValue: 5, range: "1..99", required: false, displayDuringSetup: false input "loadWarning", "integer", title: "Load warning AMPs", description: "Set to a value in AMPs to provide heavy load warning notification.", defaultValue: 12, range: "1..12", required: false, displayDuringSetup: false input "overloadProtection", "integer", title: "Overload protection AMPs", description: "Must be higher than heavy load warning value. When this value is reached, the plug shuts down and must be reset.", defaultValue: 13, range: "1..15", required: false, displayDuringSetup: false input "manualOverride", "boolean", title: "Switch manual control", description: "Enable or disable the switch on the plug. Good for tamper protection.", defaultValue: true, displayDuringSetup: false input "stateRecvovery", "boolean", title: "Return to last state after power failure?", defaultValue: true, displayDuringSetup: false input "ledNotifications", "boolean", title: "LED Notifications?", description: "Enables or disables LED color change for heavy and overload notifications.", defaultValue: true, displayDuringSetup: false input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { //state.configParams.clear() updateDataValue("configured", "false") state.debug = ("true" == debugOutput) configure() } def parse(String description) { def result = null def cmd = zwave.parse(description) if (cmd) { result = zwaveEvent(cmd) if (state.debug) log.debug "Parsed ${cmd} to ${result.inspect()}" } else { log.debug "Non-parsed event: ${description}" } return result } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { log.debug("ConfigurationReportv1 ${cmd.inspect()}") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { // calculate decimal values for returned multibyte values def fullValue = 0 switch(cmd.size) { case 1: //1 byte fullValue = cmd.configurationValue[0] * 1 break; case 2: //2 byte fullValue = cmd.configurationValue[1] + (cmd.configurationValue[0] * 0x100) break; case 3: //3 byte fullValue = cmd.configurationValue[2] + (cmd.configurationValue[1] * 0x100) + (cmd.configurationValue[0] * 0x10000) break; case 4: //4 byte fullValue = cmd.configurationValue[3] + (cmd.configurationValue[2] * 0x100) + (cmd.configurationValue[1] * 0x10000) + (cmd.configurationValue[0] * 0x1000000) break; } state.configParams << [(cmd.parameterNumber) : (fullValue)] log.debug state.configParams // set states for any values coming in used for tiles def statusValue = [:] switch(cmd.parameterNumber) { case 5: //LED Indicator statusValue.name = "indicatorStatus" if (cmd.configurationValue == [0]) { statusValue.value = "never" } else if (cmd.configurationValue == [1]) { statusValue.value = "when on" } break; case 8: //Automatic shutoff timer statusValue.name = "timerStatus" if (cmd.configurationValue == [0]) { statusValue.value = "off" } else if (cmd.configurationValue == [1]) { statusValue.value = "on" } break; } statusValue.displayed = true createEvent(statusValue) } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationBulkReport cmd) { log.debug "Got a bulk report, but don't know what to do with it." } def zwaveEvent(physicalgraph.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) { log.debug "===Power level test node report received=== ${device.displayName}: statusOfOperation: ${cmd.statusOfOperation} testFrameCount: ${cmd.testFrameCount} testNodeid: ${cmd.testNodeid}" def request = [ physicalgraph.zwave.commands.powerlevelv1.PowerlevelGet() ] response(commands(request)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport 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) createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false], displayed = true) } def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def meterTypes = ["Unknown", "Electric", "Gas", "Water"] def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"] def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""] //NOTE ScaledPreviousMeterValue does not always contain a value def previousValue = cmd.scaledPreviousMeterValue ?: 0 def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display] switch(cmd.scale) { case 0: //kWh previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 1: //kVAh map.value = cmd.scaledMeterValue break; case 2: //Watts previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 4: //Volts previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; case 5: //Amps previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0 map.value = cmd.scaledMeterValue break; } map.isStateChange = true map.displayed = true createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "physical", displayed: true, isStateChange: true)] return result } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def value = (cmd.value ? "on" : "off") def result = [createEvent(name: "switch", value: value, type: "digital", displayed: true, isStateChange: true)] return result } // parse the unhandled def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled: $cmd" createEvent(descriptionText: cmd.toString(), isStateChange: false) } // Commands follow def on() { def request = [ zwave.basicV1.basicSet(value: 0xFF), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def off() { def request = [ zwave.basicV1.basicSet(value: 0x00), zwave.switchBinaryV1.switchBinaryGet() ] commands(request) } def getEnergy() { zwave.meterV3.meterGet(scale: 0).format() //kWh } def getPower() { zwave.meterV3.meterGet(scale: 2).format() //Wattage } def getVoltage() { zwave.meterV3.meterGet(scale: 4).format() //Volts } def getCurrent() { zwave.meterV3.meterGet(scale: 5).format() //Amps } def poll() { def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def refresh() { state.configParams.clear() def request = [ zwave.switchBinaryV1.switchBinaryGet(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5), //Amps ] commands(request) } def reset() { def request = [ zwave.meterV3.meterReset(), zwave.meterV3.meterGet(scale: 0), //kWh zwave.meterV3.meterGet(scale: 1), //kVAh zwave.meterV3.meterGet(scale: 2), //Wattage zwave.meterV3.meterGet(scale: 4), //Volts zwave.meterV3.meterGet(scale: 5) //Amps ] commands(request) } def indicatorWhenOn() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 0x05, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def indicatorNever() { def request = [ zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 5, size: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x05) ] commands(request) } def timerOn() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 1), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def timerOff() { def request = [ zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: 0), zwave.configurationV1.configurationGet(parameterNumber: 0x08) ] commands(request) } def checkstate() { // check our config state map log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" state.configParams.each { parameter, value -> log.debug "Parameter ${parameter} = ${value}"} // LED Notifications - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: 0).format() /* if (state.configParams.(4) == [12]) { log.debug "this was true" } else log.debug "This was false :(" */ } def configure() { def request = [] // Get version and firmware info request << zwave.versionV1.versionGet() request << zwave.firmwareUpdateMdV2.firmwareMdGet() // get all the config values request << zwave.configurationV1.configurationGet(parameterNumber: 0x01) request << zwave.configurationV1.configurationGet(parameterNumber: 0x02) request << zwave.configurationV1.configurationGet(parameterNumber: 0x03) request << zwave.configurationV1.configurationGet(parameterNumber: 0x04) request << zwave.configurationV1.configurationGet(parameterNumber: 0x05) request << zwave.configurationV1.configurationGet(parameterNumber: 0x06) request << zwave.configurationV1.configurationGet(parameterNumber: 0x07) request << zwave.configurationV1.configurationGet(parameterNumber: 0x08) request << zwave.configurationV1.configurationGet(parameterNumber: 0x09) request << zwave.configurationV1.configurationGet(parameterNumber: 0x0A) // Can use the zwaveHubNodeId variable to add the hub to the device's associations: request << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) commands(request) + setConfigured() // set things that need to be set because their setting doesn't match what we want it to be set to int energyReportingInt; switch (energyReporting) { case "true": energyReportingInt = 1 break; case "false": energyReportingInt = 0 break; } int manualOverrideInt; switch (manualOverride) { case "true": manualOverrideInt = 1 break; case "false": manualOverrideInt = 0 break; } int stateRecvoveryInt; switch(stateRecvovery) { case "true": stateRecvoveryInt = 1 break; case "false": stateRecvoveryInt = 0 break; } // log.debug "energy reporting preference = ${energyReporting}"; // log.debug "shit I cooked up from that preference = ${energyReportingInt}"; int reportIntervalInt = Integer.parseInt(reportInterval); int overloadProtectionInt = Integer.parseInt(overloadProtection); int loadWarningInt = Integer.parseInt(loadWarning); int reportThresholdInt = Integer.parseInt(reportThreshold); // int configParam1 = state.configParams.(1); // int configParam2 = state.configParams.(2); int configParam3 = state.configParams.(3); int configParam4 = state.configParams.(4); int configParam5 = state.configParams.(5); int configParam6 = state.configParams.(6); int configParam7 = state.configParams.(7); int configParam8 = state.configParams.(8); int configParam9 = state.configParams.(9); int configParam10 = state.configParams.(10); def configSend = [] // enable or disable energy metering reports 0=disabled 1=enabled if (state.configParams.(1) != energyReportingInt) { log.debug "config ${state.configParams.(1)} != request ${energyReportingInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: energyReportingInt) } else log.debug "config ${state.configParams.(1)} = request ${energyReportingInt} Energy reporting setting unchanged. Skipping it..." // Interval in seconds for sending energy metering reports if (state.configParams.(2) != reportIntervalInt) { log.debug "config ${state.configParams.(2)} != request ${reportIntervalInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 2, scaledConfigurationValue: reportIntervalInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x02) } else log.debug "config ${state.configParams.(2)} = request ${reportIntervalInt} Energy report sending interval setting unchanged. Skipping it..." // Overload protection - set the number of AMPS you want to limit the plug to. 13 is what it is designed for. // when this value is hit, overload notification messages are sent and you have to press the button on the plug to reset it. if (state.configParams.(3) != overloadProtectionInt) { log.debug "config ${state.configParams.(3)} != request ${overloadProtectionInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: overloadProtectionInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x03) } else "config ${state.configParams.(3)} = request ${overloadProtectionInt} Current overload limit setting unchanged. Skipping it..." // Heavy load warning AMP threshold - the plug led will turn yellow when you reach this AMP value. must be less than parameter 3/ if (state.configParams.(4) != loadWarningInt) { log.debug "config ${state.configParams.(4)} != request ${loadWarningInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: loadWarningInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x04) } else log.debug "config ${state.configParams.(4)} = request ${loadWarningInt} Current overload warning level setting unchanged. Skipping it..." // LED Notifications - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: confParam5), // percentage of change in any energy metric for a report to be sent - threshold reporting if (state.configParams.(6) != reportThresholdInt) { log.debug "config ${state.configParams.(6)} != request ${reportThresholdInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: reportThresholdInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x06) } else log.debug "config ${state.configParams.(6)} = request ${reportThresholdInt} Energy reporting threshold setting unchanged. Skipping it..." // power failure recovery state - 0=remain off when power restored 1=return to last state when power restored if (state.configParams.(7) != stateRecvoveryInt) { log.debug "config ${state.configParams.(7)} != request ${stateRecvoveryInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: stateRecvoveryInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x07) } else log.debug "config ${state.configParams.(7)} = request ${stateRecvoveryInt} Power failure state recovery setting unchanged. Skipping it..." // auto power off timer - 0=disabled 1=enabled // zwave.configurationV1.configurationSet(parameterNumber: 0x08, size: 1, scaledConfigurationValue: confParam8), // auto power off timer duration - a value in minutes 1-65535 // zwave.configurationV1.configurationSet(parameterNumber: 0x09, size: 2, scaledConfigurationValue: confParam9), // manual control power on/off control - 0=disable action button 1=enable action button if (state.configParams.(10) != manualOverrideInt) { log.debug "config ${state.configParams.(10)} != request ${manualOverrideInt} Queuing configuration command..." configSend << zwave.configurationV1.configurationSet(parameterNumber: 0x0A, size: 1, scaledConfigurationValue: manualOverrideInt) configSend << zwave.configurationV1.configurationGet(parameterNumber: 0x0A) } else log.debug "config ${state.configParams.(10)} = request ${manualOverrideInt} Manual control override setting unchanged. Skipping it..." // send the commands we need to send if there's anythign TO send if (configSend) { commands(configSend) + setConfigured() } } private setConfigured() { updateDataValue("configured", "true") } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1250) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Motion-Sensor-ZSE02/device_type-zooZ-Motion-Sensor-ZSE02_v1 ================================================ /* * V 1.0 of zooZ motion sensor ZSE-02 code 5/7/2016 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. On the bottom of the zooZ 4-in-1 you will see several small holes. There is a series of four holes and a hole all by itself. You'll need a paperclip or something similar that fits into the hole. While holding the sensor a foot or so from the hub, and with SmartThings in inclusion mode, gently depress the button inside the single hole twice rapidly. The light should blink. Please wait a few moments (usually 10 seconds or so) and you should see "zooZ 4-in-1 sensor - RV 1.0" appear in the found devices area. * Touch the "zooZ 4-in-1 sensor - RV 1.0" to configure. Here we will set your temperature scale preferecne and motion preferences. After you make your choices, touch done in the app. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * In order to get the configuration sent and initial sensor data, we need to wake the sensor up. Press the button on the device one time while holding it close to the hub. If you pressed the button the sensor should blink yellow once. Wait about 30 seconds, then refresh (drag the screen down) and you should see data on the screen for temp, humidity, illuminance, and battery. ** If you do not, please wait a minute or so and refresh the screen again by sliding it down. * If you still do not see anything after refreshing, touch the gear icon to enter the device preferences screen (make any adjustments or not) and then touch done. This will reset the configuration state so the device can be configured again and polled for data. Once you're back at the device screen, while holding the sensor close to the hub, press the small button we pressed earlier one time, making sure that the sensor blinks (if it doesn't, press the button again) and wait a minute or so, then refresh the device screen in the app again. You should see data on the screen now. *** IF YOU STILL ARE NOT GETTING DATA, go back to the preferences screen and enable debug logging, and touch done. You do not need to press the button on the sensor again at this point. Go into the SmartThings IDE and choose "live logging" from the top menu. While on the live logging screen and close to your hub with the sensor, press the button on the sensor, making sure it blinks, and watch the screen for results. You should see several lines of data come in slowly. This should tell you all your settings and what the configuration on the sensor is actually set to. It will then poll the sensors for data. If you do not ever see any data coming from the sensor, please post to the community or message me via github or the SmartThings community. */ metadata { definition (name: "zooZ motion sensor - RV 1.0", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Configuration" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 a 0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type: "generic", width: 6, height: 4){ tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff" } } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'tamper', icon:"st.motion.acceleration.active", backgroundColor:"#ff0000") state("inactive", label:'clear', icon:"st.motion.acceleration.inactive", backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } main(["main"]) details(["main","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true input "LEDbehavior", "enum", title: "LED Behavior", options: ["LED Off", "Breathing", "Quick Blink on Temp/PIR"], defaultValue: "Quick Blink on Temp/PIR", required: false, displayDuringSetup: false input "PIRsensitivity", "number", title: "PIR motion sensitivity", description: "A value from 1-7, from high to low sensitivity (1 is highest)", range: "1..7", defaultValue: 4, required: false, displayDuringSetup: true input "MotionReset", "number", title: "PIR reset time", description: "Number of minutes to wait to report motion cleared after a motion event if there is no motion detected.", range: "1..255", defaultValue: 3, required: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description.startsWith("Err 106")) { state.sec = 0 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.") } else if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 1]) state.sec = 1 // if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}" if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } else { log.warn "Unable to extract encapsulated cmd from $cmd" createEvent(descriptionText: cmd.toString()) } } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { if (state.debug) log.debug "---SECURITY COMMANDS SUPPORTED REPORT V1--- ${device.displayName} sent commandClassControl: ${cmd.commandClassControl}, commandClassSupport: ${cmd.commandClassSupport}, reportsToFollow: ${cmd.reportsToFollow}" response(configure()) } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { if (state.debug) log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { if (state.debug) log.debug "---SENSOR BINARY REPORT V2--- ${device.displayName} sent value: ${cmd.sensorValue}" motionEvent(cmd.sensorValue) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.event == 0x00 && cmd.eventParameter == 0x08) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName cover is open.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName cover has been closed.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command 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) { // if (state.debug) log.debug "4-in-1 sensor not sending configure until secure" // return [] //} if (state.debug) log.debug "--Sending configuration commands to zooZ 4-in-1 sensor--" //if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset" def LEDbehav = 3 if (LEDbehavior == "LED Off") { LEDbehav=1 } else if (LEDbehavior == "Breathing") { LEDbehav=2 } else { LEDbehav=3 } def PIRsens = 4 if (PIRsensitivity) { PIRsens=PIRsensitivity } else { PIRsens = 4 } def MotionRst = 3 if (MotionReset) { MotionRst=MotionReset } else { MotionRst = 3 } if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:1200, nodeid:zwaveHubNodeId), // Get Version information zwave.versionV1.versionGet(), zwave.firmwareUpdateMdV2.firmwareMdGet(), // send no-motion report x minutes after motion stops //zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: MotionRst), //zwave.configurationV1.configurationGet(parameterNumber: 0x05), // set motion sensor sensitivity //zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: PIRsens), //zwave.configurationV1.configurationGet(parameterNumber: 0x06), // set LED behavior //zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: LEDbehav), //zwave.configurationV1.configurationGet(parameterNumber: 0x07), // get updated battery data zwave.batteryV1.batteryGet(), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId) ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { if (state.sec) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() } } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Motion-Sensor-ZSE02/device_type-zooZ-Motion-Sensor-ZSE02_v1.1 ================================================ /* * V 1.1 of zooZ motion sensor ZSE-02 code 5/13/16 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. On the bottom of the zooZ 4-in-1 you will see several small holes. There is a series of four holes and a hole all by itself. You'll need a paperclip or something similar that fits into the hole. While holding the sensor a foot or so from the hub, and with SmartThings in inclusion mode, gently depress the button inside the single hole twice rapidly. The light should blink. Please wait a few moments (usually 10 seconds or so) and you should see "zooZ 4-in-1 sensor - RV 1.0" appear in the found devices area. * Touch the "zooZ 4-in-1 sensor - RV 1.0" to configure. Here we will set your temperature scale preferecne and motion preferences. After you make your choices, touch done in the app. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * In order to get the configuration sent and initial sensor data, we need to wake the sensor up. Press the button on the device one time while holding it close to the hub. If you pressed the button the sensor should blink yellow once. Wait about 30 seconds, then refresh (drag the screen down) and you should see data on the screen for temp, humidity, illuminance, and battery. ** If you do not, please wait a minute or so and refresh the screen again by sliding it down. * If you still do not see anything after refreshing, touch the gear icon to enter the device preferences screen (make any adjustments or not) and then touch done. This will reset the configuration state so the device can be configured again and polled for data. Once you're back at the device screen, while holding the sensor close to the hub, press the small button we pressed earlier one time, making sure that the sensor blinks (if it doesn't, press the button again) and wait a minute or so, then refresh the device screen in the app again. You should see data on the screen now. *** IF YOU STILL ARE NOT GETTING DATA, go back to the preferences screen and enable debug logging, and touch done. You do not need to press the button on the sensor again at this point. Go into the SmartThings IDE and choose "live logging" from the top menu. While on the live logging screen and close to your hub with the sensor, press the button on the sensor, making sure it blinks, and watch the screen for results. You should see several lines of data come in slowly. This should tell you all your settings and what the configuration on the sensor is actually set to. It will then poll the sensors for data. If you do not ever see any data coming from the sensor, please post to the community or message me via github or the SmartThings community. */ metadata { definition (name: "zooZ motion sensor ZSE-02 - RV 1.1", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 a 0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type: "generic", width: 6, height: 4){ tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff" } } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'DISABLED', backgroundColor:"#ff0000") state("inactive", label:'ENABLED', backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } main(["main"]) details(["main","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") result += response(configure()) } else { result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) } result } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel } state.lastbatt = now() createEvent(map) } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.eventParameter == [8] && cmd.event == 0x00) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName has been deactivated by the switch.") } else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName has been reactivated by the switch.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configure() { if (state.debug) log.debug "--Sending configuration commands to zooZ motion sensor--" if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:1200, nodeid:zwaveHubNodeId), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId), //Get association zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), // get updated battery and sensor data zwave.batteryV1.batteryGet(), ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Motion-Sensor-ZSE02/device_type-zooZ-Motion-Sensor-ZSE02_v1.2 ================================================ /* * V 1.2 of zooZ motion sensor ZSE-02 code 5/14/16 * by Robert Vandervoort * * 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. * --------------------------------------------------------------------------------------------------------------------------- INSTRUCTIONS: * First you will need to create a new device handler in SmartThings. Log in to the IDE and click on Device Handlers in the top menu. Then click "from code" below. You'l be presented with a blank area where you can copy this code and paste it in. * Next, scroll to the bottom and click create. Now click save, then click publish > for me. * You should now see this device type in your list of device handlers. Now we need to pair the device. * Put SmartThings into inclusion mode by going through the add new device dialog. * Tap zwave sensor on the app screen to configure. * Now go to your devices list in the SmartThings app and open up the newly added sensor. * The configuration and battery state will get pulled by pressing the button once, waiting a couple seconds, and pressing again. * From here on, each time the motion sensor wakes up it will query for battery level. That's it. If you see the red circle in the app that says disabled, press the switch once again so it turns green and you're now monitoring for motion. Press again to disable the sensor. */ metadata { definition (name: "zooZ motion sensor ZSE-02 - RV 1.2", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Motion Sensor" capability "Acceleration Sensor" capability "Sensor" capability "Battery" // RAW Description: 0 0 0x0701 0 0 0 a 0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86 attribute "tamper", "enum", ["detected", "clear"] fingerprint deviceId: "0x0701", inClusters: "0x5E 0x85 0x59 0x71 0x80 0x5A 0x73 0x84 0x72 0x86" } simulator { status "no motion" : "command: 9881, payload: 00300300" status "motion" : "command: 9881, payload: 003003FF" status "clear" : " command: 9881, payload: 0071050000000007030000" status "tamper" : "command: 9881, payload: 007105000000FF07030000" for (int i in [0, 5, 10, 15, 50, 99, 100]) { status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: i ) ).incomingMessage() } status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate( new physicalgraph.zwave.Zwave().batteryV1.batteryReport( batteryLevel: 255 ) ).incomingMessage() status "wake up": "command: 8407, payload:" } tiles (scale: 2) { multiAttributeTile(name:"main", type: "generic", width: 6, height: 4){ tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff" } } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label:'DISABLED', backgroundColor:"#ff0000") state("inactive", label:'ENABLED', backgroundColor:"#00ff00") } valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } main(["main"]) details(["main","acceleration","battery"]) } preferences { input "debugOutput", "boolean", title: "Enable debug logging?", defaultValue: false, displayDuringSetup: true } } def updated() { updateDataValue("configured", "false") state.debug = ("true" == debugOutput) } def parse(String description) { def result = null if (description != "updated") { def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 1]) if (cmd) { result = zwaveEvent(cmd) } } if (state.debug) log.debug "Parsed '${description}' to ${result.inspect()}" return result } def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def result = createEvent(descriptionText: "${device.displayName} woke up", displayed: true) def cmds = [] if (!isConfigured()) { // we're still in the process of configuring a newly joined device if (state.debug) log.debug("late configure") [result, response(configure())] } else if (isConfigured()){ cmds << zwave.batteryV1.batteryGet().format() cmds << "delay 3000" cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() [result, response(cmds)] } } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { if (state.debug) log.debug "---MANUFACTURER SPECIFIC REPORT V2--- ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) { if (state.debug) log.debug "---COMMAND CLASS VERSION REPORT V1--- ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}" } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" updateDataValue("fw", fw) if (state.debug) log.debug "---VERSION REPORT V1--- ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { if (state.debug) log.debug "---BATTERY V1 REPORT--- ${device.displayName} reports battery level of ${cmd.batteryLevel}" def result = [] def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { map.value = 1 map.descriptionText = "${device.displayName} battery is low" map.isStateChange = true } else { map.value = cmd.batteryLevel map.descriptionText = "${device.displayName} battery is at ${cmd.batteryLevel}" map.isStateChange = true } state.lastbatt = now() result << createEvent(map) result } def motionEvent(value) { def map = [name: "motion"] if (value != 0) { map.value = "active" map.descriptionText = "$device.displayName detected motion" } else { map.value = "inactive" map.descriptionText = "$device.displayName motion has stopped" } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { if (state.debug) log.debug "---BASIC SET REPORT V1--- ${device.displayName} sent value: ${cmd.value}" motionEvent(cmd.value) } def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (state.debug) log.debug "---NOTIFICATION REPORT V3--- ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}" def result = [] if (cmd.notificationType == 7) { if (cmd.eventParameter == [8] && cmd.event == 0x00) { result << motionEvent(0) } else if (cmd.event == 0x03) { result << createEvent(name: "acceleration", value: "active", descriptionText: "$device.displayName has been deactivated by the switch.") } else if (cmd.eventParameter == [3] && cmd.event == 0X00) { result << createEvent(name: "acceleration", value: "inactive", descriptionText: "$device.displayName has been reactivated by the switch.") } else if (cmd.event == 0x08) { result << motionEvent(255) } } else { result << createEvent(descriptionText: cmd.toString(), isStateChange: false) } result } def zwaveEvent(physicalgraph.zwave.Command cmd) { createEvent(descriptionText: cmd.toString(), isStateChange: false) } def configure() { if (state.debug) log.debug "--Sending configuration commands to zooZ motion sensor--" if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}" setConfigured() def request = [ // set wakeup interval to 20 mins zwave.wakeUpV1.wakeUpIntervalSet(seconds:1200, nodeid:zwaveHubNodeId), // Can use the zwaveHubNodeId variable to add the hub to the device's associations: zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId), //Get association zwave.associationV1.associationGet(groupingIdentifier:1), zwave.associationV1.associationGet(groupingIdentifier:2), // Get Version information zwave.versionV1.versionGet(), // get updated battery data zwave.batteryV1.batteryGet(), ] commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } private setConfigured() { updateDataValue("configured", "true") return [] } private isConfigured() { getDataValue("configured") == "true" } private command(physicalgraph.zwave.Command cmd) { cmd.format() } private commands(commands, delay=1000) { delayBetween(commands.collect{ command(it) }, delay) } ================================================ FILE: zooZ-Strip-ZEN20/device_type-zooZ-strip-ZEN20_v1.0 ================================================ /** * Derived from Aeon Smart Strip code Copyright 2015 SmartThings * reworked 6/2016 by Robert Vandervoort * * 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: "zooZ ZEN20 - Z-Wave plus power strip", namespace: "robertvandervoort", author: "Robert Vandervoort") { capability "Switch" capability "Refresh" capability "Configuration" capability "Actuator" capability "Zw Multichannel" (1..5).each { n -> attribute "switch$n", "enum", ["on", "off"] command "on$n" command "off$n" } //RAW DESC 0 0 0x1004 0 0 0 b 0x5E 0x85 0x59 0x5A 0x72 0x60 0x8E 0x73 0x27 0x25 0x86 // Device reset locally 0x5A, multi channel assoc 0x8E, powerlevel 0x73 fingerprint deviceId: "0x1004", inClusters: "0x5E,0x85,0x59,0x5A,0x72,0x60,0x8E,0x73,0x27,0x25,0x86" } // simulator metadata simulator { status "on": "command: 2003, payload: FF" status "off": "command: 2003, payload: 00" status "switch1 on": "command: 600D, payload: 01 00 25 03 FF" status "switch1 off": "command: 600D, payload: 01 00 25 03 00" status "switch5 on": "command: 600D, payload: 05 00 25 03 FF" status "switch5 off": "command: 600D, payload: 05 00 25 03 00" // reply messages reply "2001FF,delay 100,2502": "command: 2503, payload: FF" reply "200100,delay 100,2502": "command: 2503, payload: 00" } // tile definitions tiles { (1..5).each { n -> standardTile("switch$n", "switch$n", width: 1, height: 1, canChangeIcon: true) { state "on", label: '${name}', action: "off$n", icon: "st.switches.switch.on", backgroundColor: "#79b821" state "off", label: '${name}', action: "on$n", icon: "st.switches.switch.off", backgroundColor: "#ffffff" } valueTile("label$n", "socket $n", width: 2, height: 1, decoration: "flat") { state "default", label: "$n", defaultState: true } } standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") { state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" } main(["switch1"]) details(["switch1", "label1", "switch2", "label2", "switch3", "label3", "switch4", "label4", "switch5", "label5"]) } } def parse(String description) { def result = null if (description.startsWith("Err")) { result = createEvent(descriptionText:description, isStateChange:true) } else if (description != "updated") { def cmd = zwave.parse(description, [0x60: 3, 0x32: 3, 0x25: 1, 0x20: 1]) if (cmd) { result = zwaveEvent(cmd, null) } } log.debug "parsed '${description}' to ${result.inspect()}" result } def endpointEvent(endpoint, map) { if (endpoint) { map.name = map.name + endpoint.toString() } createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint) { def map = [name: "switch", type: "physical", value: (cmd.value ? "on" : "off")] def events = [endpointEvent(endpoint, map)] def cmds = [] if (endpoint) { cmds += delayBetween([2,0].collect { s -> encap(zwave.meterV3.meterGet(scale: s), endpoint) }, 1000) if(endpoint < 5) cmds += ["delay 1500", encap(zwave.basicV1.basicGet(), endpoint + 1)] } else if (events[0].isStateChange) { events += (1..5).collect { ep -> endpointEvent(ep, map.clone()) } cmds << "delay 3000" cmds += delayBetween((0..5).collect { ep -> encap(zwave.meterV3.meterGet(scale: 2), ep) }, 800) } if(cmds) events << response(cmds) events } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint) { def map = [name: "switch", value: (cmd.value ? "on" : "off")] def events = [endpointEvent(endpoint, map)] def cmds = [] if (!endpoint && events[0].isStateChange) { events += (1..5).collect { ep -> endpointEvent(ep, map.clone()) } } events } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, ep) { updateDataValue("MSR", String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)) null } def zwaveEvent(physicalgraph.zwave.Command cmd, ep) { log.debug "${device.displayName}: Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") } def onOffCmd(value, endpoint = null) { [ encap(zwave.basicV1.basicSet(value: value), endpoint), "delay 500", encap(zwave.switchBinaryV1.switchBinaryGet(), endpoint) ] } def on() { onOffCmd(0xFF) } def off() { onOffCmd(0x0) } def on1() { onOffCmd(0xFF, 1) } def on2() { onOffCmd(0xFF, 2) } def on3() { onOffCmd(0xFF, 3) } def on4() { onOffCmd(0xFF, 4) } def on5() { onOffCmd(0xFF, 5) } def off1() { onOffCmd(0, 1) } def off2() { onOffCmd(0, 2) } def off3() { onOffCmd(0, 3) } def off4() { onOffCmd(0, 4) } def off5() { onOffCmd(0, 5) } def refresh() { delayBetween([ zwave.basicV1.basicGet().format(), encap(zwave.basicV1.basicGet(), 1) // further gets are sent from the basic report handler ]) } def configure() { def cmds = [ //zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, configurationValue: [0, 0, 0, 1]).format(), //zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, configurationValue: [0, 0, 0x79, 0]).format(), //zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 90).format(), ] [5, 8, 9, 10, 11].each { p -> cmds << zwave.configurationV1.configurationSet(parameterNumber: p, size: 2, scaledConfigurationValue: 5).format() } [12, 15, 16, 17, 18].each { p -> cmds << zwave.configurationV1.configurationSet(parameterNumber: p, size: 1, scaledConfigurationValue: 50).format() } cmds += [ //zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 15*60).format(), //zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [1]).format(), ] delayBetween(cmds) + "delay 5000" + refresh() } private encap(cmd, endpoint) { if (endpoint) { zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd).format() } else { cmd.format() } }