diff --git a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy index dc7845a0c26..bc6dd3aaa47 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -37,6 +37,7 @@ metadata { fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3328-G", deviceJoinName: "Centralite Micro Motion Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv5", deviceJoinName: "Motion Sensor" + fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "Bosch", model: "RFDL-ZB-MS", deviceJoinName: "Bosch Motion Sensor" } simulator { @@ -174,7 +175,13 @@ private Map getBatteryResult(rawValue) { volts = maxVolts def pct = batteryMap[volts] result.value = pct - } else { + } else if (device.getDataValue("manufacturer") == "Bosch") { + def minValue = 21 + def maxValue = 30 + def pct = Math.round((rawValue - minValue) * 100 / (maxValue - minValue)) + pct = pct > 0 ? pct : 1 + result.value = Math.min(100, pct) + } else { // Centralite def useOldBatt = shouldUseOldBatteryReporting() def minVolts = useOldBatt ? 2.1 : 2.4 def maxVolts = useOldBatt ? 3.0 : 2.7 @@ -189,7 +196,7 @@ private Map getBatteryResult(rawValue) { // OR we don't currently have a battery reading // OR the value we just received is at least 2 steps off from the last reported value // OR the device's firmware is older than 1.15.7 - if(useOldBatt || state?.lastVolts == null || state?.lastVolts == volts || device.currentState("battery")?.value == null || Math.abs(curValVolts - volts) > 0.1) { + if (useOldBatt || state?.lastVolts == null || state?.lastVolts == volts || device.currentState("battery")?.value == null || Math.abs(curValVolts - volts) > 0.1) { def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) if (roundedPct <= 0) 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 900b3af518d..4300164ceaa 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 @@ -41,6 +41,7 @@ metadata { 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" + fingerprint mfr: "014F", prod: "5744", model: "3530", deviceJoinName: "GoControl In-Wall Dimmer" } simulator { diff --git a/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy b/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy new file mode 100644 index 00000000000..9193edaadd4 --- /dev/null +++ b/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy @@ -0,0 +1,182 @@ +/** + * 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 Dual Switch", namespace: "smartthings", author: "SmartThings") { + capability "Actuator" + capability "Health Check" + capability "Light" + capability "Refresh" + capability "Sensor" + capability "Switch" + + // This DTH uses 2 switch endpoints. Parent DTH controlls endpoint 1 so please use '1' at the end of deviceJoinName + // Child device (isComponent : false) representing endpoint 2 will substitude 1 with 2 for easier identification. + fingerprint mfr: "0258", prod: "0003", model: "008B", deviceJoinName: "NEO Coolcam Light Switch 1" + } + + // 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: "#00A0DC" + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + } + } + + 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"]) + } +} + +def installed() { + def componentLabel + if (device.displayName.endsWith('1')) { + componentLabel = "${device.displayName[0..-2]}2" + } else { + // no '1' at the end of deviceJoinName - use 2 to indicate second switch anyway + componentLabel = "$device.displayName 2" + } + try { + String dni = "${device.deviceNetworkId}-ep2" + addChildDevice("Binary Switch Endpoint", dni, device.hub.id, + [completedSetup: true, label: "${componentLabel}", + isComponent : false, componentName: "ch2", componentLabel: "${componentLabel}"]) + log.debug "Endpoint 2 (Binary Switch Endpoint) added as $componentLabel" + } catch (e) { + log.warn "Failed to add endpoint 2 ($desc) as Binary Switch Endpoint - $e" + } + configure() +} + +def updated() { + configure() +} + +def configure() { + // Device-Watch simply pings if no device events received for checkInterval duration of 32min = 2 * 15min + 2min lag time + sendEvent(name: "checkInterval", value: 30 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + def commands = [] + if (zwaveInfo.mfr.equals("0258")) { + commands << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [0]).format() + commands << "delay 100" + } + commands << zwave.basicV1.basicGet().format() + response(commands) +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description, [0x20: 1, 0x84: 1, 0x98: 1, 0x56: 1, 0x60: 3]) + if (cmd) { + result = zwaveEvent(cmd) + } + log.debug("'$description' parsed to $result") + return createEvent(result) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + [name: "switch", value: cmd.value ? "on" : "off"] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + [name: "switch", value: cmd.value ? "on" : "off"] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + [name: "switch", value: cmd.value ? "on" : "off"] +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) + if (cmd.sourceEndPoint == 1) { + zwaveEvent(encapsulatedCommand) + } else { // sourceEndPoint == 2 + childDevices[0]?.handleZWave(encapsulatedCommand) + [:] + } +} + +def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { + def versions = [0x31: 2, 0x30: 1, 0x84: 1, 0x9C: 1, 0x70: 2] + def version = versions[cmd.commandClass as Integer] + def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass) + def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } + [:] +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + [descriptionText: "$device.displayName: $cmd", isStateChange: true] +} + +def on() { + // parent DTH conrols endpoint 1 + def endpointNumber = 1 + delayBetween([ + encap(endpointNumber, zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF)), + encap(endpointNumber, zwave.switchBinaryV1.switchBinaryGet()) + ]) +} + +def off() { + // parent DTH conrols endpoint 1 + def endpointNumber = 1 + delayBetween([ + encap(endpointNumber, zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00)), + encap(endpointNumber, zwave.switchBinaryV1.switchBinaryGet()) + ]) +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + +def refresh() { + // parent DTH conrols endpoint 1 + def endpointNumber = 1 + encap(endpointNumber, zwave.switchBinaryV1.switchBinaryGet()) +} + +// sendCommand is called by endpoint 2 child device handler +def sendCommand(endpointDevice, commands) { + //There is only 1 child device - endpoint 2 + def endpointNumber = 2 + def result + if (commands instanceof String) { + commands = commands.split(',') as List + } + result = commands.collect { encap(endpointNumber, it) } + sendHubCommand(result, 100) +} + +def encap(endpointNumber, cmd) { + if (cmd instanceof physicalgraph.zwave.Command) { + zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpointNumber).encapsulate(cmd).format() + } else if (cmd.startsWith("delay")) { + cmd + } else { + def header = "600D00" + String.format("%s%02X%s", header, endpointNumber, cmd) + } +} + diff --git a/devicetypes/smartthings/zwave-endpoint-switch-binary.src/zwave-endpoint-switch-binary.groovy b/devicetypes/smartthings/zwave-endpoint-switch-binary.src/zwave-endpoint-switch-binary.groovy new file mode 100644 index 00000000000..aa63878733d --- /dev/null +++ b/devicetypes/smartthings/zwave-endpoint-switch-binary.src/zwave-endpoint-switch-binary.groovy @@ -0,0 +1,101 @@ +/** + * 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: "Binary Switch Endpoint", namespace: "smartthings", author: "SmartThings") { + capability "Actuator" + capability "Health Check" + capability "Refresh" + capability "Sensor" + capability "Switch" + } + + simulator { + } + + // 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: "#00A0DC" + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + } + } + + 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"]) + } +} + +def installed() { + configure() +} + +def updated() { + configure() +} + +def configure() { + // Device-Watch simply pings if no device events received for checkInterval duration of 32min + sendEvent(name: "checkInterval", value: 30 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + refresh() +} + +def handleZWave(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + switchEvents(cmd) +} + +def handleZWave(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + switchEvents(cmd) +} + +def handleZWave(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + switchEvents(cmd) +} + +def switchEvents(physicalgraph.zwave.Command cmd) { + def value = (cmd.value ? "on" : "off") + sendEvent(name: "switch", value: value, descriptionText: "$device.displayName was turned $value") +} + +def handleZWave(physicalgraph.zwave.Command cmd) { + sendEvent(descriptionText: "$device.displayName: $cmd", isStateChange: true, displayed: false) +} + +def on() { + // We do not use delayBetween, as delay required may be different for each parent device + parent.sendCommand(device, [zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF), + zwave.switchBinaryV1.switchBinaryGet()]) +} + +def off() { + // We do not use delayBetween, as delay required may be different for each parent device + parent.sendCommand(device, [zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00), + zwave.switchBinaryV1.switchBinaryGet()]) +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + +def refresh() { + parent.sendCommand(device, zwave.switchBinaryV1.switchBinaryGet()) +} + diff --git a/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy b/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy index 020a2a08e70..f4919c8f547 100644 --- a/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy +++ b/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy @@ -33,6 +33,7 @@ metadata { fingerprint inClusters: "0x26,0x32" fingerprint mfr:"0086", prod:"0003", model:"001B", deviceJoinName: "Aeotec Micro Smart Dimmer 2E" fingerprint mfr:"0086", prod:"0103", model:"0063", deviceJoinName: "Aeotec Smart Dimmer 6" + fingerprint mfr:"014F", prod:"5044", model:"3533", deviceJoinName: "GoControl Plug-in Dimmer" } simulator { 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 d9ebdc50e6d..903bde0cf43 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -29,6 +29,8 @@ metadata { fingerprint mfr: "0086", prod: "0003", model: "0012", deviceJoinName: "Aeotec Micro Smart Switch" fingerprint mfr: "021F", prod: "0003", model: "0087", deviceJoinName: "Dome On/Off Plug-in Switch" fingerprint mfr: "0086", prod: "0103", model: "0060", deviceJoinName: "Aeotec Smart Switch 6" + fingerprint mfr: "014F", prod: "574F", model: "3535", deviceJoinName: "GoControl Wall-Mounted Outlet" + fingerprint mfr: "014F", prod: "5053", model: "3531", deviceJoinName: "GoControl Plug-in Switch" } // simulator metadata diff --git a/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy b/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy index d0b2b8403ea..0d7ab4e5d8f 100644 --- a/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy +++ b/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy @@ -74,7 +74,7 @@ def configure() { log.debug "configure()" def cmds = [] - if (state.sec != 1) { + if (!isSecured()) { // secure inclusion may not be complete yet cmds << "delay 1000" } @@ -317,7 +317,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } private secure(physicalgraph.zwave.Command cmd) { - if (state.sec == 0) { // default to secure + if (!isSecured()) { // default to secure cmd.format() } else { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() @@ -327,3 +327,11 @@ private secure(physicalgraph.zwave.Command cmd) { private secureSequence(commands, delay=200) { delayBetween(commands.collect{ secure(it) }, delay) } + +private isSecured() { + if (zwaveInfo && zwaveInfo.zw) { + return zwaveInfo.zw.endsWith("s") + } else { + return state.sec == 1 + } +} diff --git a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy index 77b4dc23019..4a20cb1c2e7 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -42,6 +42,8 @@ metadata { fingerprint mfr: "001A", prod: "534C", model: "0000", deviceJoinName: "Eaton RF Master Switch" fingerprint mfr: "001A", prod: "5354", model: "0003", deviceJoinName: "Eaton RF Appliance Plug-In Module" fingerprint mfr: "001A", prod: "5352", model: "0000", deviceJoinName: "Eaton RF Accessory Switch" + fingerprint mfr: "014F", prod: "5753", model: "3535", deviceJoinName: "GoControl Smart In-Wall Switch" + fingerprint mfr: "014F", prod: "5257", model: "3033", deviceJoinName: "GoControl Wall Relay Switch" } // simulator metadata