From d626c5f2a197df38d8cbf670125a48a8abe37ce9 Mon Sep 17 00:00:00 2001 From: twack Date: Thu, 25 May 2017 07:57:19 -0700 Subject: [PATCH 1/6] ocf-update-fortrezz-siren --- devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy index 9ee8071..9c0d62b 100644 --- a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy +++ b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy @@ -16,7 +16,7 @@ * Date: 2014-07-15 */ metadata { - definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings") { + definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") { capability "Actuator" capability "Alarm" capability "Battery" From df8e435fcca7ae6997a30b068ebe030d2b5f510e Mon Sep 17 00:00:00 2001 From: Vinay Rao Date: Thu, 25 May 2017 17:09:54 -0700 Subject: [PATCH 2/6] ICP-1056 Updating the icon and ocf device type for fortrezz siren --- .../smartthings/smartalert-siren.src/smartalert-siren.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy b/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy index 4481e76..a1585bf 100644 --- a/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy +++ b/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy @@ -16,7 +16,7 @@ * Date: 2013-03-05 */ metadata { - definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.smokedetector") { + definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") { capability "Actuator" capability "Switch" capability "Sensor" From 7f3cd0cdaa59da69b362dcd8fd0d14a7300ecf13 Mon Sep 17 00:00:00 2001 From: Donald Kirker Date: Fri, 26 May 2017 01:39:05 -0700 Subject: [PATCH 3/6] ICP-1016 Fix default value for states for Aeon Siren Gen5 --- devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy b/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy index 3eb9770..8c6ecc2 100644 --- a/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy +++ b/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy @@ -61,6 +61,8 @@ metadata { def installed() { // Device-Watch simply pings if no device events received for 32min(checkInterval) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + response(secure(zwave.basicV1.basicGet())) } def updated() { @@ -163,4 +165,4 @@ private secure(physicalgraph.zwave.Command cmd) { * */ def ping() { secure(zwave.basicV1.basicGet()) -} \ No newline at end of file +} From fc1f1508adee47f693c9308fcd5a4618da0c66db Mon Sep 17 00:00:00 2001 From: Bob Florian Date: Sat, 6 May 2017 09:40:01 -0700 Subject: [PATCH 4/6] MSA-1951 Added Inovelli 2-Channel Smart Plug --- .../inovelli-2-channel-smart-plug.groovy | 266 ++++++++++++++++++ .../switch-child-device.groovy | 49 ++++ 2 files changed, 315 insertions(+) create mode 100644 devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy create mode 100644 devicetypes/erocm123/switch-child-device.src/switch-child-device.groovy diff --git a/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy b/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy new file mode 100644 index 0000000..2aabca2 --- /dev/null +++ b/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy @@ -0,0 +1,266 @@ +/** + * + * Inovelli 2-Channel Smart Plug + * + * github: Eric Maycock (erocm123) + * Date: 2017-04-27 + * Copyright Eric Maycock + * + * Includes all configuration parameters and ease of advanced configuration. + * + * 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: "Inovelli 2-Channel Smart Plug", namespace: "erocm123", author: "Eric Maycock") { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Polling" + capability "Refresh" + capability "Health Check" + fingerprint manufacturer: "015D", prod: "0221", model: "251C" + } + simulator {} + preferences {} + tiles { + multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + } + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + main(["switch"]) + details(["switch", + childDeviceTiles("all"), "refresh" + ]) + } +} +def parse(String description) { + def result = [] + def cmd = zwave.parse(description) + if (cmd) { + result += zwaveEvent(cmd) + logging("Parsed ${cmd} to ${result.inspect()}", 1) + } else { + logging("Non-parsed event: ${description}", 2) + } + return result +} +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + logging("BasicReport ${cmd} - ep ${ep}", 2) + if (ep) { + def event + childDevices.each { + childDevice -> + if (childDevice.deviceNetworkId == "$device.deviceNetworkId-ep$ep") { + childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off") + } + } + if (cmd.value) { + event = [createEvent([name: "switch", value: "on"])] + } else { + def allOff = true + childDevices.each { + n -> + if (n.currentState("switch").value != "off") allOff = false + } + if (allOff) { + event = [createEvent([name: "switch", value: "off"])] + } else { + event = [createEvent([name: "switch", value: "on"])] + } + } + return event + } +} +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + logging("BasicSet ${cmd}", 2) + def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital") + def cmds = [] + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1) + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + return [result, response(commands(cmds))] // returns the result of reponse() +} +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) { + logging("SwitchBinaryReport ${cmd} - ep ${ep}", 2) + if (ep) { + def event + def childDevice = childDevices.find { + it.deviceNetworkId == "$device.deviceNetworkId-ep$ep" + } + if (childDevice) childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off") + if (cmd.value) { + event = [createEvent([name: "switch", value: "on"])] + } else { + def allOff = true + childDevices.each { + n-> + if (n.currentState("switch").value != "off") allOff = false + } + if (allOff) { + event = [createEvent([name: "switch", value: "off"])] + } else { + event = [createEvent([name: "switch", value: "on"])] + } + } + return event + } else { + def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital") + def cmds = [] + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1) + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + return [result, response(commands(cmds))] // returns the result of reponse() + } +} +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + logging("MultiChannelCmdEncap ${cmd}", 2) + def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) + } +} +def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { + logging("ManufacturerSpecificReport ${cmd}", 2) + def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) + logging("msr: $msr", 2) + updateDataValue("MSR", msr) +} +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // This will capture any commands not handled by other instances of zwaveEvent + // and is recommended for development so you can see every command the device sends + logging("Unhandled Event: ${cmd}", 2) +} +def on() { + logging("on()", 1) + commands([ + zwave.switchAllV1.switchAllOn(), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + ]) +} +def off() { + logging("off()", 1) + commands([ + zwave.switchAllV1.switchAllOff(), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + ]) +} +void childOn(String dni) { + logging("childOn($dni)", 1) + def cmds = [] + cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni)))) + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + sendHubCommand(cmds, 1000) +} +void childOff(String dni) { + logging("childOff($dni)", 1) + def cmds = [] + cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni)))) + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + sendHubCommand(cmds, 1000) +} +void childRefresh(String dni) { + logging("childRefresh($dni)", 1) + def cmds = [] + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + sendHubCommand(cmds, 1000) +} +def poll() { + logging("poll()", 1) + commands([ + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2), + ]) +} +def refresh() { + logging("refresh()", 1) + commands([ + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2), + ]) +} +def ping() { + logging("ping()", 1) + refresh() +} +def installed() { + logging("installed()", 1) + command(zwave.manufacturerSpecificV1.manufacturerSpecificGet()) + createChildDevices() +} +def updated() { + logging("updated()", 1) + if (!childDevices) { + createChildDevices() + } else if (device.label != state.oldLabel) { + childDevices.each { + if (it.label == "${state.oldLabel} (CH${channelNumber(it.deviceNetworkId)})") { + def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})" + it.setLabel(newLabel) + } + } + state.oldLabel = device.label + } + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "needUpdate", value: device.currentValue("needUpdate"), displayed: false, isStateChange: true) +} +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'", 2) +} +private encap(cmd, endpoint) { + if (endpoint) { + zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } else { + cmd + } +} +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) +} +private channelNumber(String dni) { + dni.split("-ep")[-1] as Integer +} +private void createChildDevices() { + state.oldLabel = device.label + for (i in 1..2) { + addChildDevice("Switch Child Device", "${device.deviceNetworkId}-ep${i}", null, [completedSetup: true, label: "${device.displayName} (CH${i})", + isComponent: true, componentName: "ep$i", componentLabel: "Channel $i" + ]) + } +} + +private def logging(message, level) { + if (logLevel != "0") { + switch (logLevel) { + case "1": + if (level > 1) log.debug "$message" + break + case "99": + log.debug "$message" + break + } + } +} diff --git a/devicetypes/erocm123/switch-child-device.src/switch-child-device.groovy b/devicetypes/erocm123/switch-child-device.src/switch-child-device.groovy new file mode 100644 index 0000000..19f997d --- /dev/null +++ b/devicetypes/erocm123/switch-child-device.src/switch-child-device.groovy @@ -0,0 +1,49 @@ +/** + * Switch Child Device + * + * Copyright 2017 Eric Maycock + * + * 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: "Switch Child Device", namespace: "erocm123", author: "Eric Maycock") { + capability "Switch" + capability "Actuator" + capability "Sensor" + capability "Refresh" + } + + tiles { + multiAttributeTile(name:"switch", type: "lighting", width: 3, height: 4, canChangeIcon: true){ + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"turningOn" + attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC", nextState:"turningOff" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" + } + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + } +} + +void on() { + parent.childOn(device.deviceNetworkId) +} + +void off() { + parent.childOff(device.deviceNetworkId) +} + +void refresh() { + parent.childRefresh(device.deviceNetworkId) +} From 79a6a6472e3b3bc035ef19e216030843339526a3 Mon Sep 17 00:00:00 2001 From: jackchi Date: Mon, 29 May 2017 11:02:48 -0700 Subject: [PATCH 5/6] [DHF-7] [ICP-1084] Adds scheduled 1 hr ping for offline devices; updates checkInterval to 1 hour --- .../zwave-lock.src/zwave-lock.groovy | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy index 50b251f..bbd9ac8 100644 --- a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy +++ b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy @@ -86,13 +86,13 @@ import physicalgraph.zwave.commands.doorlockv1.* import physicalgraph.zwave.commands.usercodev1.* def installed() { - // Device-Watch simply pings if no device events received for 32min(checkInterval) - sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Device-Watch pings if no device events received for 1 hour (checkInterval) + sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } def updated() { - // Device-Watch simply pings if no device events received for 32min(checkInterval) - sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Device-Watch pings if no device events received for 1 hour (checkInterval) + sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) try { if (!state.init) { state.init = true @@ -152,6 +152,10 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported def zwaveEvent(DoorLockOperationReport cmd) { def result = [] + + unschedule("followupStateCheck") + unschedule("stateCheck") + def map = [ name: "lock" ] if (cmd.doorLockMode == 0xFF) { map.value = "locked" @@ -365,7 +369,7 @@ def zwaveEvent(UserCodeReport cmd) { code = state["set$name"] ?: decrypt(state[name]) ?: "****" state.remove("set$name".toString()) } else { - map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ] ] + map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ], isStateChange: true ] map.descriptionText = "$device.displayName code $cmd.userIdentifier is set" map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode) map.isStateChange = true @@ -456,11 +460,12 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { // The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1 def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ] - result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId)) - if (state.assoc != zwaveHubNodeId) { - result << response(zwave.associationV1.associationGet(groupingIdentifier:2)) - } - result + def cmds = [ + zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(), + "delay 1200", + zwave.associationV1.associationGet(groupingIdentifier:2).format() + ] + [result, response(cmds)] } def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { @@ -530,11 +535,18 @@ def unlockwtimeout() { lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT) } -/** - * PING is used by Device-Watch in attempt to reach the Device - * */ def ping() { - refresh() + runIn(30, followupStateCheck) + secure(zwave.doorLockV1.doorLockOperationGet()) +} + +def followupStateCheck() { + runEvery1Hour(stateCheck) + stateCheck() +} + +def stateCheck() { + sendHubCommand(new physicalgraph.device.HubAction(secure(zwave.doorLockV1.doorLockOperationGet()))) } def refresh() { From d864c5e3b3d4735133876cada6e256a7c082b473 Mon Sep 17 00:00:00 2001 From: Donald Kirker Date: Fri, 26 May 2017 01:18:02 -0700 Subject: [PATCH 6/6] ICP-1076 Fix Aeon Door/Window Sensor 6 initial value of null --- .../zwave-door-window-sensor.groovy | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy index 0cf6d46..835d7af 100644 --- a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy +++ b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy @@ -113,9 +113,9 @@ def updated() { def configure() { commands([ - zwave.manufacturerSpecificV2.manufacturerSpecificGet(), - zwave.batteryV1.batteryGet() - ], 6000) + zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW), + zwave.manufacturerSpecificV2.manufacturerSpecificGet() + ], 1000) } def sensorValueEvent(value) { @@ -190,11 +190,17 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) cmds << "delay 1200" } + + if (device.currentValue("contact") == null) { // Incase our initial request didn't make it + cmds << command(zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW)) + } + if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) { cmds << command(zwave.batteryV1.batteryGet()) - } else { + } else { // If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() } + [event, response(cmds)] }