├── README.md ├── aeon-recessed-door-sensor-gen-5.groovy ├── aeon-recessed-multisensor-gen-5.groovy └── secure-zwave-energy-switch.groovy /README.md: -------------------------------------------------------------------------------- 1 | SmartThings 2 | Please use this as you see fit. USE AT OWN RISK!!! 3 | -------------------------------------------------------------------------------- /aeon-recessed-door-sensor-gen-5.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Aeon Recessed Door Sensor 3 | * Based On: Z-Wave Door/Window Sensor 4 | * 5 | * Author: Mike 6 | * Modified by: Mike 7 | * Date: 2015-2-4 8 | * 9 | * Updated by Alex Ruffell - Battery Fix 10 | * Updated On: 18-Jul-2017 11 | */ 12 | 13 | // for the UI 14 | metadata { 15 | // Automatically generated. Make future change here. 16 | definition (name: "Aeon Recessed Door Sensor", namespace: "jabbera", author: "Mike") { 17 | capability "Contact Sensor" 18 | capability "Sensor" 19 | capability "Battery" 20 | capability "Configuration" 21 | 22 | /* 23 | Z-Wave Command Classes 24 | Hex id from https://graph.api.smartthings.com/ide/doc/zwave-utils.html 25 | 26 | Manufacturer: Aeotec 27 | Model: Recessed Door Sensor Gen5 (ZW089-A) 28 | Z-Wave Certification Number: ZC10-14120008 29 | http://products.z-wavealliance.org/products/1179 30 | Product Type ID: 0x0102 31 | Product ID: 0x0059 32 | 33 | To Include: 34 | Turn the primary controller of Z-Wave network into inclusion mode, short press the product’s Z-Wave button that you can find in the back of the product. 35 | 36 | To Exclude: 37 | Turn the primary controller of Z-Wave network into exclusion mode, short press the product’s Z-Wave button that you can find in back of the product. 38 | 39 | Factory Reset: 40 | Press and hold the Z-Wave button that you can find in back of the product for 20 seconds and then release. This procedure should only be used when the primary controller is inoperable. 41 | 42 | Wake Up: 43 | Press and hold the Z-Wave button for 5 seconds will trigger sending the Wake up notification command and then keep waking up for 10 seconds after release the Z-Wave button. 44 | 45 | Supported Command Classes 46 | 47 | cc: 48 | 0x5E 49 | 0x86 Version 50 | 0x72 Manufacturer Specific 51 | 0x98 Security 52 | 53 | ccOut: 54 | 0x5A Device Reset Locally 55 | 0x82 Hail 56 | 57 | sec: 58 | 0x30 Sensor Binary 59 | 0x80 Battery 60 | 0x84 Wake Up 61 | 0x70 Configuration 62 | 0x85 Association 63 | 0x59 Association Grp Info 64 | 0x71 Alarm 65 | 0x7A Firmware Update Md 66 | 0x73 Powerlevel 67 | 68 | */ 69 | 70 | //Raw Description 71 | //zw:Ss type:0701 mfr:0086 prod:0102 model:0059 ver:1.13 zwv:3.92 lib:03 cc:5E,86,72,98 ccOut:5A,82 sec:30,80,84,70,85,59,71,7A,73 role:06 ff:8C00 ui:8C00 72 | 73 | //Fingerprint - old method 74 | fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98,0xEF,0x5A,0x82" 75 | fingerprint deviceId: "0x0701", inClusters: "0x5E 0x30 0x80 0x84 0x70 0x85 0x59 0x71 0x86 0x72 0x73 0x7A 0x98", outClusters: "0x5A 0x82" 76 | 77 | //Fingerprint - new method 78 | fingerprint mfr: "0086", prod: "0102", model: "0059" 79 | fingerprint type: "0701", cc: "5E,86,72,98", ccOut: "5A,82", sec: "sec:30,80,84,70,85,59,71,7A,73" 80 | 81 | } 82 | 83 | // simulator metadata 84 | simulator { 85 | // status messages 86 | status "open": "command: 2001, payload: FF" 87 | status "closed": "command: 2001, payload: 00" 88 | } 89 | 90 | // UI tile definitions 91 | tiles { 92 | standardTile("contact", "device.contact", width: 2, height: 2) { 93 | state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e" 94 | state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821" 95 | } 96 | valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { 97 | state "battery", label:'${currentValue}% battery', unit:"" 98 | } 99 | standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") { 100 | state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" 101 | } 102 | 103 | main (["contact"]) 104 | details(["contact","battery","refresh"]) 105 | } 106 | } 107 | 108 | /* 109 | Upon intial connection the switch sends an unsolicited ManufacturerSpecificReport 110 | We will setup the wake up interval there. This is a sleepy device meaning you cannot 111 | send it commands at any time. You can only send them between wake up intervals. This 112 | means the interval will only change once the device has woken up and we can ask it to change 113 | it connot be less then 8 minutes. 114 | */ 115 | 116 | 117 | def parse(String description) { 118 | def result = null 119 | 120 | log.debug("Parse got ${description?.inspect()}") 121 | 122 | if (description.startsWith("Err")) { 123 | result = createEvent(descriptionText:description) 124 | } else if (description == "updated") { 125 | // nothing to do. 126 | } else { 127 | def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 2, 0x71: 3, 0x9C: 1]) 128 | 129 | if (state.debug) log.debug("Parsed command: ${cmd?.inspect()}") 130 | 131 | if (cmd) { 132 | result = zwaveEvent(cmd) 133 | } 134 | } 135 | 136 | log.debug("Parse returned ${result}") 137 | 138 | return result 139 | } 140 | 141 | // Devices that support the Security command class can send messages in an encrypted form; 142 | // they arrive wrapped in a SecurityMessageEncapsulation command and must be unencapsulated 143 | def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { 144 | log.debug("Attempting to decrypt ${cmd?.inspect()}") 145 | def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 2, 0x71: 3, 0x9C: 1]) // can specify command class versions here like in zwave.parse 146 | if (encapsulatedCommand) { 147 | log.debug("Decrypted returned ${encapsulatedCommand?.inspect()}") 148 | return zwaveEvent(encapsulatedCommand) 149 | } 150 | else 151 | { 152 | log.debug("Failed to decrypt ${cmd?.inspect()}") 153 | } 154 | } 155 | 156 | 157 | def sensorValueEvent(value) { 158 | log.debug "sensorValueEvent(value:${value})" 159 | 160 | if (value) { 161 | createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open") 162 | } else { 163 | createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed") 164 | } 165 | } 166 | 167 | def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) 168 | { 169 | log.debug "BasicSet(value:${cmd.value})" 170 | 171 | sensorValueEvent(cmd.value) 172 | } 173 | 174 | def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) 175 | { 176 | log.debug "WakeUpNotification. Enabling battery level reporting (if needed) and asking for battery level." 177 | 178 | def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: true, displayed: true)] 179 | 180 | if (state.batteryReportingEnabled != false) { 181 | // Set param #101 (0x65) to 1 to enable reporting of battery levels when the sensor wakes up - do this once regardless of its current value. 182 | // I will have to add a preference to force the state.batteryReportingEnabled to false again in case the parameter gets reset to 0 somehow 183 | zwave.configurationV1.configurationSet(parameterNumber: 0x65, size: 1, scaledConfigurationValue: 1) 184 | log.debug "Set Parameter 101 to 1 to enable battery reporting." 185 | 186 | state.batteryReportingEnabled = true 187 | log.debug "state.batteryReportingEnabled set to ${state.batteryReportingEnabled} so we do not keep setting the parameter." 188 | } 189 | 190 | result << secure(zwave.batteryV1.batteryGet()) 191 | 192 | if (null == state.wakeUpSet) 193 | { 194 | def reportIntervalSec = 720*60 195 | 196 | log.debug "Setting wake up interval to: ${reportIntervalSec}" 197 | 198 | result << secure(zwave.wakeUpV2.wakeUpIntervalSet(seconds:reportIntervalSec, nodeid:zwaveHubNodeId)) 199 | } 200 | 201 | result << response("delay 6000") // This is to give the sensor enough time to return a result before telling the sensor to turn off its receiver 202 | result << secure(zwave.wakeUpV2.wakeUpNoMoreInformation()) 203 | result 204 | } 205 | 206 | def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { 207 | log.debug "BatteryReport(${cmd?.inspect()})" 208 | 209 | def map = [ name: "battery", unit: "%" ] 210 | if (cmd.batteryLevel == 0xFF) { 211 | map.value = 1 212 | map.descriptionText = "${device.displayName} has a low battery" 213 | map.isStateChange = true 214 | } else { 215 | map.value = cmd.batteryLevel 216 | map.displayed = true 217 | map.isStateChange = true 218 | } 219 | [createEvent(map), secure(zwave.wakeUpV2.wakeUpNoMoreInformation())] 220 | } 221 | 222 | def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { 223 | log.debug "ManufacturerSpecificReport: ${cmd.inspect()}" 224 | 225 | def reportIntervalSec = 720*60 226 | def result = [] 227 | 228 | log.debug "Setting wake up interval to: ${reportIntervalSec}" 229 | 230 | result << secure(zwave.wakeUpV2.wakeUpIntervalSet(seconds:reportIntervalSec, nodeid:zwaveHubNodeId)); 231 | result << secure(zwave.batteryV1.batteryGet()) 232 | 233 | state.wakeUpSet = true 234 | 235 | return result 236 | } 237 | 238 | def zwaveEvent(physicalgraph.zwave.Command cmd) { 239 | createEvent(descriptionText: "No handler for command: $device.displayName: ${cmd.inspect()}", displayed: state.display) 240 | } 241 | 242 | private secure(physicalgraph.zwave.Command cmd) { 243 | log.debug "Securing command: ${cmd?.inspect()}" 244 | response(zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()) 245 | } 246 | -------------------------------------------------------------------------------- /aeon-recessed-multisensor-gen-5.groovy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jabbera/SmartThings/f3f273dca91e3953e9fe714b8a508f6c092738ab/aeon-recessed-multisensor-gen-5.groovy -------------------------------------------------------------------------------- /secure-zwave-energy-switch.groovy: -------------------------------------------------------------------------------- 1 | // UNTESTED 2 | metadata { 3 | // Automatically generated. Make future change here. 4 | definition (name: "Secure Z-Wave Metering Switch", namespace: "jabbera", author: "Mike") { 5 | capability "Energy Meter" 6 | capability "Actuator" 7 | capability "Switch" 8 | capability "Power Meter" 9 | capability "Polling" 10 | capability "Refresh" 11 | capability "Sensor" 12 | 13 | command "reset" 14 | 15 | fingerprint inClusters: "0x25,0x32" 16 | } 17 | 18 | // simulator metadata 19 | simulator { 20 | status "on": "command: 2003, payload: FF" 21 | status "off": "command: 2003, payload: 00" 22 | 23 | for (int i = 0; i <= 10000; i += 1000) { 24 | status "power ${i} W": new physicalgraph.zwave.Zwave().meterV1.meterReport( 25 | scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage() 26 | } 27 | for (int i = 0; i <= 100; i += 10) { 28 | status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV1.meterReport( 29 | scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage() 30 | } 31 | 32 | // reply messages 33 | reply "2001FF,delay 100,2502": "command: 2503, payload: FF" 34 | reply "200100,delay 100,2502": "command: 2503, payload: 00" 35 | 36 | } 37 | 38 | // tile definitions 39 | tiles { 40 | standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { 41 | state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" 42 | state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" 43 | } 44 | valueTile("power", "device.power", decoration: "flat") { 45 | state "default", label:'${currentValue} W' 46 | } 47 | valueTile("energy", "device.energy", decoration: "flat") { 48 | state "default", label:'${currentValue} kWh' 49 | } 50 | standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat") { 51 | state "default", label:'reset kWh', action:"reset" 52 | } 53 | standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat") { 54 | state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" 55 | } 56 | standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") { 57 | state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" 58 | } 59 | 60 | main "switch" 61 | details(["switch","power","energy","reset","configure","refresh"]) 62 | } 63 | } 64 | 65 | def parse(String description) { 66 | def result = null 67 | def cmd = zwave.parse(description, [0x20: 1, 0x32: 1]) 68 | if (cmd) { 69 | result = createEvent(zwaveEvent(cmd)) 70 | } 71 | return result 72 | } 73 | 74 | // Devices that support the Security command class can send messages in an encrypted form; 75 | // they arrive wrapped in a SecurityMessageEncapsulation command and must be unencapsulated 76 | def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { 77 | def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x32: 1]) // can specify command class versions here like in zwave.parse 78 | if (encapsulatedCommand) { 79 | return zwaveEvent(encapsulatedCommand) 80 | } 81 | } 82 | def zwaveEvent(physicalgraph.zwave.commands.meterv1.MeterReport cmd) { 83 | if (cmd.scale == 0) { 84 | [name: "energy", value: cmd.scaledMeterValue, unit: "kWh"] 85 | } else if (cmd.scale == 1) { 86 | [name: "energy", value: cmd.scaledMeterValue, unit: "kVAh"] 87 | } 88 | else { 89 | [name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W"] 90 | } 91 | } 92 | 93 | def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) 94 | { 95 | [ 96 | name: "switch", value: cmd.value ? "on" : "off", type: "physical" 97 | ] 98 | } 99 | 100 | def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) 101 | { 102 | [ 103 | name: "switch", value: cmd.value ? "on" : "off", type: "digital" 104 | ] 105 | } 106 | 107 | def zwaveEvent(physicalgraph.zwave.Command cmd) { 108 | // Handles all Z-Wave commands we aren't interested in 109 | [:] 110 | } 111 | 112 | def on() { 113 | delayBetween([ 114 | secure(zwave.basicV1.basicSet(value: 0xFF)), 115 | secure(zwave.switchBinaryV1.switchBinaryGet()) 116 | ]) 117 | } 118 | 119 | def off() { 120 | delayBetween([ 121 | secure(zwave.basicV1.basicSet(value: 0x00)), 122 | secure(zwave.switchBinaryV1.switchBinaryGet()) 123 | ]) 124 | } 125 | 126 | def poll() { 127 | delayBetween([ 128 | secure(zwave.switchBinaryV1.switchBinaryGet()), 129 | secure(zwave.meterV2.meterGet(scale: 0)), 130 | secure(zwave.meterV2.meterGet(scale: 2)) 131 | ]) 132 | } 133 | 134 | def refresh() { 135 | delayBetween([ 136 | secure(zwave.switchBinaryV1.switchBinaryGet()), 137 | secure(zwave.meterV2.meterGet(scale: 0)), 138 | secure(zwave.meterV2.meterGet(scale: 2)) 139 | ]) 140 | } 141 | 142 | def reset() { 143 | return [ 144 | secure(zwave.meterV2.meterReset()), 145 | secure(zwave.meterV2.meterGet(scale: 0)) 146 | ] 147 | } 148 | 149 | def configure() { 150 | delayBetween([ 151 | secure(zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4)), // combined power in watts 152 | secure(zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300)), // every 5 min 153 | secure(zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8)), // combined energy in kWh 154 | secure(zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 300)), // every 5 min 155 | secure(zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0)), // no third report 156 | secure(zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 300)) // every 5 min 157 | ]) 158 | } 159 | 160 | private secure(physicalgraph.zwave.Command cmd) { 161 | response(zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()) 162 | } --------------------------------------------------------------------------------