From e08c0808a56da987e47052b290d813d257b07aa7 Mon Sep 17 00:00:00 2001 From: MMateusiakS Date: Wed, 18 Jul 2018 20:07:40 +0200 Subject: [PATCH 1/9] [WWST-626] Add DTH for ZigBee Danalock V3 (#3254) * Add DTH for ZigBee Danalock V3 * Changing checkInterval value and responseMap.data * changing folder name * changing deviceJoinName * Remove redundant files --- .../zigbee-lock-without-codes.src/README.md | 26 ++ .../zigbee-lock-without-codes.groovy | 256 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 devicetypes/smartthings/zigbee-lock-without-codes.src/README.md create mode 100644 devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy diff --git a/devicetypes/smartthings/zigbee-lock-without-codes.src/README.md b/devicetypes/smartthings/zigbee-lock-without-codes.src/README.md new file mode 100644 index 00000000000..b932fa44510 --- /dev/null +++ b/devicetypes/smartthings/zigbee-lock-without-codes.src/README.md @@ -0,0 +1,26 @@ +# Danalock ZigBee + +Local Execution + +Works with: + +* [Danalock V3 858125000074](https://danalock.com/products/danalock-v3-smart-lock/) + +## Table of contents + +* [Capabilities](#capabilities) +* [Device Health](#device-health) + +## Capabilities + +* **Configuration** +* **Health Check** +* **Sensor** +* **Battery** +* **Actuator** +* **Lock** +* **Refresh** + +## Device Health +* __122 min__ checkInterval + diff --git a/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy b/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy new file mode 100644 index 00000000000..7452d8999ae --- /dev/null +++ b/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy @@ -0,0 +1,256 @@ +/** + * + * Copyright 2018 SmartThings + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ + +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition (name:"ZigBee Lock Without Codes", namespace:"smartthings", author:"SmartThings", vid:"generic-lock-2", mnmn:"SmartThings", runLocally:true, minHubCoreVersion:'000.022.00013', executeCommandsLocally:true) { + capability "Actuator" + capability "Lock" + capability "Refresh" + capability "Sensor" + capability "Battery" + capability "Configuration" + capability "Health Check" + + fingerprint profileId:"0104, 000A", inClusters:"0000, 0001, 0003, 0009, 0020,0101, 0B05", outclusters:"000A, 0019, 0B05", manufacturer:"Danalock", model:"V3-BTZB", deviceJoinName:"Danalock V3 Smart Lock" + + } + + tiles(scale:2) { + multiAttributeTile(name:"toggle", type:"generic", width:6, height:4) { + tileAttribute("device.lock", key:"PRIMARY_CONTROL"){ + attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00A0DC", nextState:"unlocking" + attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking" + attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking" + attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#00A0DC" + attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff" + } + } + standardTile("lock", "device.lock", inactiveLabel:false, decoration:"flat", width:2, height:2) { + state "default", label:'lock', action:"lock.lock", icon:"st.locks.lock.locked", nextState:"locking" + } + standardTile("unlock", "device.lock", inactiveLabel:false, decoration:"flat", width:2, height:2) { + state "default", label:'unlock', action:"lock.unlock", icon:"st.locks.lock.unlocked", nextState:"unlocking" + + } + valueTile("battery", "device.battery", inactiveLabel:false, decoration:"flat", width:2, height:2) { + state "battery", label:'${currentValue}% battery', unit:"" + } + standardTile("refresh", "device.refresh", inactiveLabel:false, decoration:"flat", width:2, height:2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + + main "toggle" + details(["toggle", "lock", "unlock", "battery", "refresh"]) + } +} + +private getCLUSTER_POWER() { 0x0001 } +private getCLUSTER_DOORLOCK() { 0x0101 } +private getDOORLOCK_CMD_LOCK_DOOR() { 0x00 } +private getDOORLOCK_CMD_UNLOCK_DOOR() { 0x01 } +private getDOORLOCK_RESPONSE_OPERATION_EVENT() { 0x20 } +private getDOORLOCK_RESPONSE_PROGRAMMING_EVENT() { 0x21 } +private getPOWER_ATTR_BATTERY_PERCENTAGE_REMAINING() { 0x0021 } +private getDOORLOCK_ATTR_LOCKSTATE() { 0x0000 } + +def installed() { + log.debug "Executing installed()" + initialize() +} + +def uninstalled() { + log.debug "Executing uninstalled()" + sendEvent(name:"lockRemoved", value:device.id, isStateChange:true, displayed:false) +} + +def updated() { + try { + if (!state.init || !state.configured) { + state.init = true + def cmds = [] + if (!state.configured) { + cmds << initialize() + } else { + cmds << refresh() + } + + return response(cmds.flatten()) + } + } catch (e) { + log.warn "ZigBee DTH - updated() threw exception:- $e" + } + return null +} + +def ping() { + refresh() +} + +def refresh() { + def cmds = zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE) + return cmds +} + +def configure() { + def cmds = initialize() + return cmds +} + +def initialize() { + log.debug "Executing initialize()" + state.configured = true + sendEvent(name:"checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed:false, data: [protocol:"zigbee", hubHardwareId:device.hub.hardwareID, offlinePingable:"1"]) + + def cmds = zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE, + DataType.ENUM8, 0, 3600, null) + + zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,DataType.UINT8, 600, 21600, 0x01) + + zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) + + def allCmds = cmds + refresh() + return allCmds +} + +def lock() { + def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_LOCK_DOOR) + + zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) + + return cmds +} + +def unlock() { + def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_UNLOCK_DOOR) + + zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) + return cmds +} + +def parse(String description) { + def result = null + if (description) { + if (description.startsWith('read attr -')) { + result = parseAttributeResponse(description) + } else { + result = parseCommandResponse(description) + } + } + return result +} + +private def parseAttributeResponse(String description) { + Map descMap = zigbee.parseDescriptionAsMap(description) + log.debug "Executing parseAttributeResponse() with description map:- $descMap" + def result = [] + Map responseMap = [:] + def clusterInt = descMap.clusterInt + def attrInt = descMap.attrInt + def deviceName = device.displayName + responseMap.data = deviceName + + if (clusterInt == CLUSTER_POWER && attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) { + responseMap.name = "battery" + + if (Integer.parseInt(descMap.value, 16) != 255) { + responseMap.value = Math.round(Integer.parseInt(descMap.value, 16) / 2) + responseMap.descriptionText = "Battery is at ${responseMap.value}%" + } + + } else if (clusterInt == CLUSTER_DOORLOCK && attrInt == DOORLOCK_ATTR_LOCKSTATE) { + def value = Integer.parseInt(descMap.value, 16) + responseMap.name = "lock" + if (value == 0) { + responseMap.value = "unknown" + responseMap.descriptionText = "Unknown state" + } else if (value == 1) { + log.debug "locked" + responseMap.value = "locked" + responseMap.descriptionText = "Locked" + } else if (value == 2) { + log.debug "unlocked" + responseMap.value = "unlocked" + responseMap.descriptionText = "Unlocked" + } else { + responseMap.value = "unknown" + responseMap.descriptionText = "Unknown state" + } + } else { + return null + } + result << createEvent(responseMap) + return result +} + +private def parseCommandResponse(String description) { + Map descMap = zigbee.parseDescriptionAsMap(description) + log.debug "Executing parseCommandResponse() with description map:- $descMap" + + def deviceName = device.displayName + def result = [] + Map responseMap = [:] + def data = descMap.data + def cmd = descMap.commandInt + def clusterInt = descMap.clusterInt + responseMap.data = deviceName + + if (clusterInt == CLUSTER_DOORLOCK && (cmd == DOORLOCK_CMD_LOCK_DOOR || cmd == DOORLOCK_CMD_UNLOCK_DOOR)) { + def cmdList = [] + cmdList << "delay 4200" + cmdList << zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE).first() + result << response(cmdList) + } else if (clusterInt == CLUSTER_DOORLOCK && cmd == DOORLOCK_RESPONSE_OPERATION_EVENT) { + def eventSource = Integer.parseInt(data[0], 16) + def eventCode = Integer.parseInt(data[1], 16) + + responseMap.name = "lock" + responseMap.displayed = true + responseMap.isStateChange = true + + if (eventSource == 1) { + responseMap.data = [method: "command"] + } else if (eventSource == 2) { + def desc = "manually" + responseMap.data = [method: "manual"] + } + + switch (eventCode) { + case 1: + responseMap.value = "locked" + responseMap.descriptionText = "Locked ${desc}" + break + case 2: + responseMap.value = "unlocked" + responseMap.descriptionText = "Unlocked ${desc}" + break + default: + break + } + } + + result << createEvent(responseMap) + return result +} + +private Boolean secondsPast(timestamp, seconds) { + if (!(timestamp instanceof Number)) { + if (timestamp instanceof Date) { + timestamp = timestamp.time + } else if ((timestamp instanceof String) && timestamp.isNumber()) { + timestamp = timestamp.toLong() + } else { + return true + } + } + return (now() - timestamp) > (seconds * 1000) +} From abf72c2c0927343c8bce00a9c00eedfb728806be Mon Sep 17 00:00:00 2001 From: Zach Varberg Date: Wed, 18 Jul 2018 14:23:39 -0500 Subject: [PATCH 2/9] Move ZLL 5000k bulb to cloud This move the "ZLL White Color Temperature Bulb 5000k" DTH to execute in the cloud until 23. This is because in the current local implementation there isn't a read after a delay causing us to be out of sync temporarily. This addresses: https://smartthings.atlassian.net/browse/ICP-5419 This addresses: https://smartthings.atlassian.net/browse/ICP-5416 --- .../zll-white-color-temperature-bulb-5000k.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy b/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy index 7e144d6d139..16974898659 100644 --- a/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy +++ b/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy @@ -13,7 +13,7 @@ */ metadata { - definition (name: "ZLL White Color Temperature Bulb 5000K", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", runLocally: true, minHubCoreVersion: '000.021.00001', executeCommandsLocally: true) { + definition (name: "ZLL White Color Temperature Bulb 5000K", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", runLocally: true, minHubCoreVersion: '000.023.00001', executeCommandsLocally: true) { capability "Actuator" capability "Color Temperature" From 20aad8f8123c31d52a7958141ff6126dc52c0b2b Mon Sep 17 00:00:00 2001 From: ALamchaS Date: Wed, 18 Jul 2018 23:29:41 +0200 Subject: [PATCH 3/9] [ICP-5298] DTH hotfix, update mfr/model checks. (#3269) --- .../smartthings/zwave-siren.src/zwave-siren.groovy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy index f9ed139e9c8..c50305095b3 100644 --- a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy +++ b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy @@ -115,7 +115,7 @@ def initialize() { def configure() { log.debug "config" def cmds = [] - if (zwaveInfo.mfr == "0258" && zwaveInfo.model == "1088") { + if (zwaveInfo.mfr == "0131" && zwaveInfo.model == "1083") { // Set alarm volume to 2 (medium) cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [2]).format() cmds << "delay 500" @@ -136,13 +136,16 @@ def poll() { } } +def on() { + log.debug "sending on" + def on() { log.debug "sending on" // ICP-5323: Zipato siren sometimes fails to make sound for full duration // Those alarms do not end with Siren Notification Report. // For those cases we add additional state check after alarm duration to // synchronize cloud state with actual device state. - if (zwaveInfo.mfr == "0258" && zwaveInfo.model == "1088") { + if (zwaveInfo.mfr == "0131" && zwaveInfo.model == "1083") { [ zwave.basicV1.basicSet(value: 0xFF).format(), zwave.basicV1.basicGet().format(), @@ -156,6 +159,7 @@ def on() { ] } } +} def off() { log.debug "sending off" From c67a4b8fa59a167fa0798d406c9539a625018ade Mon Sep 17 00:00:00 2001 From: ALamchaS Date: Wed, 18 Jul 2018 23:32:53 +0200 Subject: [PATCH 4/9] [ICP-5448] Refresh child device state in ping() to make it able to recover from offline state. (#3270) --- .../fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy b/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy index dfbddfbed9e..80b541b1e37 100644 --- a/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy @@ -164,6 +164,7 @@ def configure() { def ping() { log.debug "ping..()" + childRefresh() refresh() //response(refresh()) } @@ -510,4 +511,4 @@ private parameterMap() {[ 8: "Cyan", 9: "Magenta" ], def: "0", title: "Ring LED color when off", descr: "Ring LED colour when the device is OFF.", defValDescr: "Off (Default)"] -]} \ No newline at end of file +]} From 8312dbd76c2eab4a0bc18cdf0caa8b3dc959fe0f Mon Sep 17 00:00:00 2001 From: greens Date: Wed, 18 Jul 2018 14:37:21 -0700 Subject: [PATCH 5/9] ICP-5298 (#3272) Fixing build --- devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy | 4 ---- 1 file changed, 4 deletions(-) diff --git a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy index c50305095b3..215d40cacfe 100644 --- a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy +++ b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy @@ -136,9 +136,6 @@ def poll() { } } -def on() { - log.debug "sending on" - def on() { log.debug "sending on" // ICP-5323: Zipato siren sometimes fails to make sound for full duration @@ -159,7 +156,6 @@ def on() { ] } } -} def off() { log.debug "sending off" From a347569e9f34fed2f53f1f2362988678422e2ba6 Mon Sep 17 00:00:00 2001 From: Vinay Rao Date: Sat, 21 Jul 2018 12:08:14 -0700 Subject: [PATCH 6/9] NYCE generic UI metadata (#3281) --- .../nyce-motion-sensor.src/nyce-motion-sensor.groovy | 2 +- .../nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy b/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy index 2e99485aefa..f0d56ab66d8 100644 --- a/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy +++ b/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy @@ -16,7 +16,7 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus metadata { - definition (name: "NYCE Motion Sensor", namespace: "smartthings", author: "SmartThings") { + definition (name: "NYCE Motion Sensor", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-motion-2") { capability "Motion Sensor" capability "Configuration" capability "Battery" diff --git a/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy b/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy index 9b39146e092..aa5de1ebebd 100644 --- a/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy +++ b/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy @@ -18,7 +18,7 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus metadata { - definition (name: "NYCE Open/Closed Sensor", namespace: "smartthings", author: "NYCE") { + definition (name: "NYCE Open/Closed Sensor", namespace: "smartthings", author: "NYCE", mnmn: "SmartThings", vid: "generic-contact-3") { capability "Battery" capability "Configuration" capability "Contact Sensor" From 2923f143c3bf78982f664b2b870350bffc8346ad Mon Sep 17 00:00:00 2001 From: Mariusz A Date: Mon, 23 Jul 2018 20:02:18 +0200 Subject: [PATCH 7/9] Icp 5475 [UK] Incorrect device states on ST Classic app (#3278) * ICP-5475 [UK] Incorrect device states on ST Classic app Fixed device states according to temperatureAlarm capability Added battery initial state check * ICP-5475 Post review fixes * ICP-5475 clearHeat changed to clear --- .../zwave-basic-heat-alarm.groovy | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy b/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy index 610859095c5..83727dc49bc 100644 --- a/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy +++ b/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy @@ -32,10 +32,9 @@ metadata { tiles(scale: 2) { multiAttributeTile(name: "heat", type: "lighting", width: 6, height: 4) { - tileAttribute("device.heat", key: "PRIMARY_CONTROL") { + tileAttribute("device.temperatureAlarm", key: "PRIMARY_CONTROL") { attributeState("cleared", label: "cleared", icon: "st.alarm.smoke.clear", backgroundColor: "#ffffff") - attributeState("detected", label: "HEAT", icon: "st.alarm.smoke.smoke", backgroundColor: "#e86d13") - attributeState("tested", label: "TEST", icon: "st.alarm.smoke.test", backgroundColor: "#e86d13") + attributeState("heat", label: "HEAT", icon: "st.alarm.smoke.smoke", backgroundColor: "#e86d13") } } valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { @@ -49,15 +48,19 @@ metadata { def installed() { def cmds = [] - // Device checks in every 4 hours, this interval allows us to miss one check-in notification before marking offline - cmds << createEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - cmds << createHeatEvents("heatClear") + cmds << checkIntervalEvent + cmds << createHeatEvents("clear") cmds.each { cmd -> sendEvent(cmd) } + response(initialPoll()) } def updated() { + //sendEvent(checkIntervalEvent) +} + +def getCheckIntervalEvent() { // Device checks in every 4 hours, this interval allows us to miss one check-in notification before marking offline - sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + createEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } def getCommandClassVersions() { @@ -123,17 +126,15 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm switch (cmd.event) { case 0x00: case 0xFE: - result = createHeatEvents("heatClear") + result = createHeatEvents("clear") break case 0x01: //Overheat detected case 0x02: //Overheat detected Unknown Location case 0x03: //Rapid Temperature Rise case 0x03: //Rapid Temperature Rise Unknown Location + case 0x07: //Tested result = createHeatEvents("heat") break - case 0x07: - result = createHeatEvents("tested") - break } } return result @@ -145,20 +146,32 @@ def createHeatEvents(name) { switch (name) { case "heat": text = "$device.displayName heat was detected!" - result = createEvent(name: "heat", value: "detected", descriptionText: text) + result = createEvent(name: "temperatureAlarm", value: "heat", descriptionText: text) break - case "tested": - text = "$device.displayName heat tested" - result = createEvent(name: "heat", value: "tested", descriptionText: text) - break - case "heatClear": + case "clear": text = "$device.displayName heat is clear" - result = createEvent(name: "heat", value: "cleared", descriptionText: text) - break - case "testClear": - text = "$device.displayName heat cleared" - result = createEvent(name: "heat", value: "cleared", descriptionText: text) + result = createEvent(name: "temperatureAlarm", value: "cleared", descriptionText: text, isStateChange: true) + log.debug "Clear event created" break } return result +} + +private command(physicalgraph.zwave.Command cmd) { + if (zwaveInfo?.zw?.endsWith("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} + +private commands(commands, delay = 200) { + delayBetween(commands.collect { command(it) }, delay) +} + +def initialPoll() { + def request = [] + // check initial battery + request << zwave.batteryV1.batteryGet() + commands(request, 500) + ["delay 6000", command(zwave.wakeUpV1.wakeUpNoMoreInformation())] } \ No newline at end of file From fb42e7b7e61e4a3647f77487a4679c0ec148b16b Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 23 Jul 2018 15:18:54 -0700 Subject: [PATCH 8/9] Wwst 1093 Fibaro Wall Plug UK (#3277) WWST-1093 Fibaro Wall Plug UK --- .../fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy | 3 +-- .../zwave-metering-switch-secure.groovy | 2 +- .../zwave-metering-switch.src/zwave-metering-switch.groovy | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy b/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy index 3b977448e5c..76d6edc2f46 100644 --- a/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy @@ -12,8 +12,7 @@ metadata { command "reset" - fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Wall Plug EU ZW5" // EU - fingerprint mfr: "010F", prod: "1801", model: "1000", deviceJoinName: "Fibaro Wall Plug ZW5" // UK + fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Wall Plug EU ZW5" fingerprint deviceId: "0x1001", inClusters:"0x5E,0x22,0x59,0x56,0x7A,0x32,0x71,0x73,0x31,0x85,0x70,0x72,0x5A,0x8E,0x25,0x86" } diff --git a/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy b/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy index a362f7a3235..f750dbb9c81 100644 --- a/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy +++ b/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy @@ -26,7 +26,7 @@ metadata { command "reset" fingerprint deviceId: "0x1001", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x32, 0x8E, 0x71, 0x73, 0x98, 0x31, 0x25, 0x86", outClusters: "" - fingerprint mfr: "0072", prod: "0501", model: "0F06", deviceJoinName: "Fibaro Wall Plug ZW5" // US + fingerprint mfr: "0072", prod: "0501", model: "0F06", deviceJoinName: "Fibaro Wall Plug ZW5" // US } // simulator metadata diff --git a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy index ca5260d6998..b23ed3aa3c9 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -35,6 +35,8 @@ metadata { fingerprint mfr: "014F", prod: "5053", model: "3531", deviceJoinName: "GoControl Plug-in Switch" fingerprint mfr: "0063", prod: "4F44", model: "3031", deviceJoinName: "GE Direct-Wire Outdoor Switch" fingerprint mfr: "0258", prod: "0003", model: "0087", deviceJoinName: "NEO Coolcam Power plug" + fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Wall Plug ZW5" // EU + fingerprint mfr: "010F", prod: "1801", model: "1000", deviceJoinName: "Fibaro Wall Plug ZW5" // UK } // simulator metadata From 7a6f190635c33953e5d551c3f7e7fdc9f4fa730e Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 24 Jul 2018 11:34:12 -0700 Subject: [PATCH 9/9] ICP-3042 Fan Controller DTH (#3117) ICP-3042 Fan Controller DTH --- .../zwave-dimmer-switch-generic.groovy | 4 - .../zwave-fan-controller.groovy | 160 ++++++++++++++++++ 2 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy index 4e3553571be..49cf4c94215 100644 --- a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy @@ -28,7 +28,6 @@ metadata { fingerprint mfr: "001D", prod: "3201", model: "0001", deviceJoinName: "Leviton Dimmer Switch" fingerprint mfr: "001D", prod: "1B03", model: "0334", deviceJoinName: "Leviton Universal Dimmer" fingerprint mfr: "011A", prod: "0102", model: "0201", deviceJoinName: "Enerwave In-Wall Dimmer" - fingerprint mfr: "001D", prod: "1001", model: "0334", deviceJoinName: "Leviton 3-Speed Fan Controller" fingerprint mfr: "001D", prod: "0602", model: "0334", deviceJoinName: "Leviton Magnetic Low Voltage Dimmer" fingerprint mfr: "001D", prod: "0401", model: "0334", deviceJoinName: "Leviton 600W Incandescent Dimmer" fingerprint mfr: "0111", prod: "8200", model: "0200", deviceJoinName: "Remotec Technology Plug-In Dimmer" @@ -37,9 +36,6 @@ metadata { fingerprint mfr: "0039", prod: "5044", model: "3038", deviceJoinName: "Honeywell Z-Wave Plug-in Dimmer" fingerprint mfr: "0039", prod: "4944", model: "3038", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Dimmer" fingerprint mfr: "0039", prod: "4944", model: "3130", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Toggle Dimmer" - fingerprint mfr: "0063", prod: "4944", model: "3034", deviceJoinName: "GE In-Wall Smart Fan Control" - fingerprint mfr: "0063", prod: "4944", model: "3131", deviceJoinName: "GE In-Wall Smart Fan Control" - fingerprint mfr: "0039", prod: "4944", model: "3131", deviceJoinName: "Honeywell Z-Wave Plus In-Wall Fan Speed Control" fingerprint mfr: "001A", prod: "4449", model: "0101", deviceJoinName: "Eaton RF Master Dimmer" fingerprint mfr: "001A", prod: "4449", model: "0003", deviceJoinName: "Eaton RF Dimming Plug-In Module" fingerprint mfr: "0086", prod: "0103", model: "0063", deviceJoinName: "Aeotec Smart Dimmer 6" diff --git a/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy b/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy new file mode 100644 index 00000000000..c4308be48c0 --- /dev/null +++ b/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy @@ -0,0 +1,160 @@ +/** + * Copyright 2018 SmartThings + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ +metadata { + definition(name: "Z-Wave Fan Controller", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.fan") { + capability "Switch Level" + capability "Switch" + capability "Fan Speed" + capability "Health Check" + capability "Actuator" + capability "Refresh" + capability "Sensor" + + command "low" + command "medium" + command "high" + command "raiseFanSpeed" + command "lowerFanSpeed" + + fingerprint mfr: "001D", prod: "1001", model: "0334", deviceJoinName: "Leviton 3-Speed Fan Controller" + fingerprint mfr: "0063", prod: "4944", model: "3034", deviceJoinName: "GE In-Wall Smart Fan Control" + fingerprint mfr: "0063", prod: "4944", model: "3131", deviceJoinName: "GE In-Wall Smart Fan Control" + fingerprint mfr: "0039", prod: "4944", model: "3131", deviceJoinName: "Honeywell Z-Wave Plus In-Wall Fan Speed Control" + } + + simulator { + status "00%": "command: 2003, payload: 00" + status "33%": "command: 2003, payload: 21" + status "66%": "command: 2003, payload: 42" + status "99%": "command: 2003, payload: 63" + } + + tiles(scale: 2) { + multiAttributeTile(name: "fanSpeed", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.fanSpeed", key: "PRIMARY_CONTROL") { + attributeState "0", label: "off", action: "switch.on", icon: "st.thermostat.fan-off", backgroundColor: "#ffffff" + attributeState "1", label: "low", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "2", label: "medium", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "3", label: "high", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + } + tileAttribute("device.fanSpeed", key: "VALUE_CONTROL") { + attributeState "VALUE_UP", action: "raiseFanSpeed" + attributeState "VALUE_DOWN", action: "lowerFanSpeed" + } + } + + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh" + } + main "fanSpeed" + details(["fanSpeed", "refresh"]) + } + +} + +def installed() { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + response(refresh()) +} + +def parse(String description) { + def result = null + if (description != "updated") { + log.debug "parse() >> zwave.parse($description)" + def cmd = zwave.parse(description, [0x20: 1, 0x26: 1]) + if (cmd) { + result = 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) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) { + fanEvents(cmd) +} + +def fanEvents(physicalgraph.zwave.Command cmd) { + def value = (cmd.value ? "on" : "off") + def result = [createEvent(name: "switch", value: value)] + result << createEvent(name: "level", value: cmd.value == 99 ? 100 : cmd.value) + result << createEvent(name: "fanSpeed", value: cmd.value/33) + return result +} + +def on() { + setLevel(0xFF) +} + +def off() { + setLevel(0x00) +} + +def setLevel(value) { + log.debug "setLevel >> value: $value" + def level = value as Integer + level = level == 255 ? level : Math.max(Math.min(level, 99), 0) + sendEvent(name: "switch", value: level > 0 ? "on" : "off") + delayBetween([zwave.basicV1.basicSet(value: level).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000) +} + +def setFanSpeed(speed) { + setLevel(speed * 33) +} + +def raiseFanSpeed() { + setFanSpeed(Math.min((device.currentValue("fanSpeed") as Integer) + 1, 3)) +} + +def lowerFanSpeed() { + setFanSpeed(Math.max((device.currentValue("fanSpeed") as Integer) - 1, 0)) +} + +def low() { + setFanSpeed(1) +} + +def medium() { + setFanSpeed(2) +} + +def high() { + setFanSpeed(3) +} + +def refresh() { + zwave.switchMultilevelV1.switchMultilevelGet().format() +} + +def ping() { + refresh() +} +