diff --git a/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy b/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy index 3dce3ec841e..f73c65af0c8 100644 --- a/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy +++ b/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy @@ -308,7 +308,7 @@ def configure() { sendEvent(name: "windowShade", value: "unknown") log.debug "Configuring Reporting and Bindings." sendEvent(name: "checkInterval", value: (2 * 60 * 60 + 10 * 60), displayed: true, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"])) + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) def attrs_refresh = zigbee.readAttribute(CLUSTER_BASIC, BASIC_ATTR_SWBUILDID) + zigbee.readAttribute(CLUSTER_WINDOWCOVERING, WINDOWCOVERING_ATTR_LIFTPERCENTAGE) + 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 index 46dbcd1fa1d..1ee57352507 100644 --- 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 @@ -254,8 +254,14 @@ private channelNumber(String dni) { 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" + addChildDevice("Switch Child Device", + "${device.deviceNetworkId}-ep${i}", + device.hubId, + [completedSetup: true, + label: "${device.displayName} (CH${i})", + isComponent: true, + componentName: "ep$i", + componentLabel: "Channel $i" ]) } } diff --git a/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy b/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy index 32ca8418770..0a9b7f63346 100644 --- a/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy @@ -265,8 +265,10 @@ private createChildDevices() { addChildDevice( "Fibaro Double Switch 2 - USB", "${device.deviceNetworkId}-2", - null, - [completedSetup: true, label: "${device.displayName} (CH2)", isComponent: false] + device.hubId, + [completedSetup: true, + label: "${device.displayName} (CH2)", + isComponent: false] ) } catch (Exception e) { logging("${device.displayName} - error attempting to create child device: "+e, "debug") 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 cfff3472f74..c9f385d29e6 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 @@ -241,8 +241,10 @@ private createChildDevices() { addChildDevice( "Fibaro Wall Plug USB", "${device.deviceNetworkId}-2", - null, - [completedSetup: true, label: "${device.displayName} (CH2)", isComponent: false] + device.hubId, + [completedSetup: true, + label: "${device.displayName} (CH2)", + isComponent: false] ) } diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy old mode 100755 new mode 100644 index 4d05834ccff..fb906937c1a --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -126,9 +126,15 @@ def refresh() { } def configure() { - sendEvent(name: "checkInterval", value:20 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) - def cmds = [] def manufacturer = getDataValue("manufacturer") + + if (manufacturer == "eWeLink") { + sendEvent(name: "checkInterval", value:2 * 60 * 60 + 5 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + } else { + sendEvent(name: "checkInterval", value:20 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + } + def cmds = [] + log.debug "Configuring Reporting, IAS CIE, and Bindings." //The electricity attribute is reported without bind and reporting CFG. The TI plan reports the power once in about 10 minutes; the NXP plan reports the electricity once in 20 minutes if (manufacturer == "Aurora") { @@ -185,4 +191,4 @@ def getContactResult(value) { value : value, descriptionText: descriptionText ] -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy b/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy index dff6e9b1c14..fbb19db11e6 100644 --- a/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy +++ b/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy @@ -218,9 +218,14 @@ private void createChildDevices() { Integer buttons = (device.currentState("numberOfButtons").value).toBigInteger() for (i in 1..buttons) { - def child = addChildDevice("Child Button", "${device.deviceNetworkId}/${i}", null, - [completedSetup: true, label: "${device.displayName} button ${i}", - isComponent: true, componentName: "button$i", componentLabel: "Button $i"]) + def child = addChildDevice("Child Button", + "${device.deviceNetworkId}/${i}", + device.hubId, + [completedSetup: true, + label: "${device.displayName} button ${i}", + isComponent: true, + componentName: "button$i", + componentLabel: "Button $i"]) child.sendEvent(name: "supportedButtonValues", value: JsonOutput.toJson(["pushed", "held"]), displayed: false) child.sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false) diff --git a/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy b/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy index cef199f22a3..81d8f6c854c 100644 --- a/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy +++ b/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy @@ -30,6 +30,7 @@ metadata { fingerprint mfr: "0371", prod: "0103", model: "0001", deviceJoinName: "Aeon LED Bulb 6 Multi-White" //US fingerprint mfr: "0371", prod: "0003", model: "0001", deviceJoinName: "Aeon LED Bulb 6 Multi-White" //EU + fingerprint mfr: "0300", prod: "0003", model: "0004", deviceJoinName: "ilumin Tunable White" } simulator { diff --git a/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy b/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy index f03d79bce5c..95afcea1a98 100644 --- a/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy +++ b/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy @@ -320,13 +320,15 @@ private updateLocalSwitchState(childId, state) { private addChildSwitches() { for (i in 2..5) { String childDni = "${device.deviceNetworkId}/$i" - def child = addChildDevice("Child Switch", childDni, null, [ - completedSetup: true, - label : "$device.displayName Switch $i", - isComponent : true, - componentName : "switch$i", - componentLabel: "Switch $i" - ]) + def child = addChildDevice("Child Switch", + childDni, + device.hubId, + [completedSetup: true, + label : "$device.displayName Switch $i", + isComponent : true, + componentName : "switch$i", + componentLabel: "Switch $i" + ]) child.sendEvent(name: "switch", value: "off") } } diff --git a/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy b/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy index b576947aa0f..45687fb4ef0 100644 --- a/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy +++ b/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy @@ -11,6 +11,9 @@ * for the specific language governing permissions and limitations under the License. * */ +import groovy.json.JsonOutput + + metadata { definition (name: "Springs Window Fashions Shade", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind") { capability "Window Shade" @@ -111,6 +114,7 @@ def getCheckInterval() { def installed() { sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) response(refresh()) } @@ -242,6 +246,11 @@ def presetPosition() { zwave.switchMultilevelV1.switchMultilevelSet(value: 0xFF).format() } +def pause() { + log.debug "pause()" + stop() +} + def stop() { log.debug "stop()" zwave.switchMultilevelV3.switchMultilevelStopLevelChange().format() diff --git a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy index 494b8238120..13b017267db 100755 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -85,13 +85,13 @@ def parse(String description) { attrData.each { def map = [:] - if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { + if (it.value && it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { log.debug "power" map.name = "power" map.value = zigbee.convertHexToInt(it.value)/powerDiv map.unit = "W" } - else if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { + else if (it.value && it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { log.debug "energy" map.name = "energy" map.value = zigbee.convertHexToInt(it.value)/energyDiv diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy old mode 100755 new mode 100644 index 9c7fe2873d5..360589c7498 --- a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy +++ b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy @@ -159,6 +159,11 @@ def refresh() { def configure() { log.debug "configure" - sendEvent(name: "checkInterval", value:20 * 60 + 2*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + def manufacturer = getDataValue("manufacturer") + if (manufacturer == "eWeLink") { + sendEvent(name: "checkInterval", value:2 * 60 * 60 + 5 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + } else { + sendEvent(name: "checkInterval", value:20 * 60 + 2*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + } return zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 1200, 0x10) + refresh() -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy index b3331d7945b..33014ddca5d 100755 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -11,6 +11,8 @@ * 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 groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType metadata { @@ -201,6 +203,10 @@ def refresh() { return cmds } +def installed() { + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) +} + def configure() { // Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time) log.info "configure()" diff --git a/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy b/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy index 564793925c6..c424edc93af 100644 --- a/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy +++ b/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy @@ -198,9 +198,14 @@ private void onOffCmd(value, endpoint = null) { private void createChildDevices() { state.oldLabel = device.label for (i in 1..5) { - addChildDevice("Zooz Power Strip Outlet", "${device.deviceNetworkId}-ep${i}", null, - [completedSetup: true, label: "${device.displayName} (CH${i})", - isComponent: true, componentName: "ch$i", componentLabel: "Channel $i"]) + addChildDevice("Zooz Power Strip Outlet", + "${device.deviceNetworkId}-ep${i}", + device.hubId, + [completedSetup: true, + label: "${device.displayName} (CH${i})", + isComponent: true, + componentName: "ch$i", + componentLabel: "Channel $i"]) } } 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 1ee71062f79..2b11cf4fdb2 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -47,6 +47,7 @@ metadata { fingerprint mfr: "0371", prod: "0003", model: "00AF", deviceJoinName: "Aeotec Smart Switch 7", ocfDeviceType: "oic.d.smartplug" //EU fingerprint mfr: "0371", prod: "0103", model: "00AF", deviceJoinName: "Aeotec Smart Switch 7", ocfDeviceType: "oic.d.smartplug" //US fingerprint mfr: "0060", prod: "0004", model: "000B", deviceJoinName: "Everspring Smart Plug", ocfDeviceType: "oic.d.smartplug" //US + fingerprint mfr: "031E", prod: "0002", model: "0001", deviceJoinName: "Inovelli Switch Red Series" //US } // simulator metadata diff --git a/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy new file mode 100644 index 00000000000..614a84a3af9 --- /dev/null +++ b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy @@ -0,0 +1,259 @@ +/** + * Copyright 2019 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 Radiator Thermostat", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.thermostat") { + capability "Thermostat Mode" + capability "Refresh" + capability "Battery" + capability "Thermostat Heating Setpoint" + capability "Health Check" + capability "Thermostat" + capability "Temperature Measurement" + + fingerprint mfr: "0060", prod: "0015", model: "0001", deviceJoinName: "Everspring Thermostatic Radiator Valve", mnmn: "SmartThings", vid: "generic-radiator-thermostat" + //this DTH is sending temperature setpoint commands using Celsius scale and assumes that they'll be handled correctly by device + //if new device added to this DTH won't be able to do that, make sure to you'll handle conversion in a right way + } + + tiles(scale: 2) { + multiAttributeTile(name:"thermostat", type:"general", width:6, height:4, canChangeIcon: false) { + tileAttribute("device.thermostatMode", key: "PRIMARY_CONTROL") { + attributeState("off", action:"switchMode", nextState:"...", icon: "st.thermostat.heating-cooling-off") + attributeState("heat", action:"switchMode", nextState:"...", icon: "st.thermostat.heat") + attributeState("emergency heat", action:"switchMode", nextState:"...", icon: "st.thermostat.emergency-heat") + } + tileAttribute("device.temperature", key: "SECONDARY_CONTROL") { + attributeState("temperature", label:'${currentValue}°', icon: "st.alarm.temperature.normal", + backgroundColors:[ + // Celsius + [value: 0, color: "#153591"], + [value: 7, color: "#1e9cbb"], + [value: 15, color: "#90d2a7"], + [value: 23, color: "#44b621"], + [value: 28, color: "#f1d801"], + [value: 35, color: "#d04e00"], + [value: 37, color: "#bc2323"], + // Fahrenheit + [value: 40, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ] + ) + } + tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { + attributeState("default", label: '${currentValue}', unit: "°", defaultState: true) + } + } + controlTile("thermostatMode", "device.thermostatMode", "enum", width: 2 , height: 2, supportedStates: "device.supportedThermostatModes") { + state("off", action: "setThermostatMode", label: 'Off', icon: "st.thermostat.heating-cooling-off") + state("heat", action: "setThermostatMode", label: 'Heat', icon: "st.thermostat.heat") + state("emergency heat", action:"setThermostatMode", label: 'Emergency heat', icon: "st.thermostat.emergency-heat") + } + controlTile("heatingSetpoint", "device.heatingSetpoint", "slider", + sliderType: "HEATING", + debouncePeriod: 750, + range: "device.heatingSetpointRange", + width: 2, height: 2) { + state "default", action:"setHeatingSetpoint", label:'${currentValue}', backgroundColor: "#E86D13" + } + valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "battery", label: 'Battery:\n${currentValue}%', unit: "%" + } + standardTile("refresh", "command.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "refresh", label: 'refresh', action: "refresh.refresh", icon: "st.secondary.refresh-icon" + } + main "thermostat" + details(["thermostat", "thermostatMode", "heatingSetpoint", "battery", "refresh"]) + } +} + +def initialize() { + sendEvent(name: "checkInterval", value: 4 * 60 * 60 + 24 * 60 , displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "supportedThermostatModes", value: thermostatSupportedModes.encodeAsJson(), displayed: false) + sendEvent(name: "heatingSetpointRange", value: [minHeatingSetpointTemperature, maxHeatingSetpointTemperature], displayed: false) + response(refresh()) +} + +def installed() { + initialize() +} + +def updated() { + initialize() +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } else { + log.warn "${device.displayName} - no-parsed event: ${description}" + } + log.debug "Parse returned: ${result}" + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + log.debug "SecurityMessageEncapsulation into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "unable to extract secure command from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + + + +def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel + def map = [name: "battery", value: value, unit: "%"] + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { + def map = [name: "thermostatMode", data:[supportedThermostatModes: thermostatSupportedModes.encodeAsJson()]] + switch (cmd.mode) { + case 1: + map.value = "heat" + break + case 11: + map.value = "emergency heat" + break + case 0: + map.value = "off" + break + } + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { + def deviceTemperatureScale = cmd.scale ? 'F' : 'C' + createEvent(name: "heatingSetpoint", value: convertTemperatureIfNeeded(cmd.scaledValue, deviceTemperatureScale, cmd.precision), unit: temperatureScale) +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def deviceTemperatureScale = cmd.scale ? 'F' : 'C' + createEvent(name: "temperature", value: convertTemperatureIfNeeded(cmd.scaledSensorValue, deviceTemperatureScale, cmd.precision), unit: temperatureScale) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.warn "Unhandled command: ${cmd}" + [:] +} + +def setThermostatMode(String mode) { + def modeValue = 0 + if (thermostatSupportedModes.contains(mode)) { + switch (mode) { + case "heat": + modeValue = 1 + break + case "emergency heat": + modeValue = 11 + break + case "off": + modeValue = 0 + break + } + } else { + log.debug "Unsupported mode ${mode}" + } + + [ + secure(zwave.thermostatModeV2.thermostatModeSet(mode: modeValue)), + "delay 2000", + secure(zwave.thermostatModeV2.thermostatModeGet()) + ] +} + +def heat() { + setThermostatMode("heat") +} + +def emergencyHeat() { + setThermostatMode("emergency heat") +} + +def off() { + setThermostatMode("off") +} + +def setHeatingSetpoint(setpoint) { + setpoint = temperatureScale == 'C' ? setpoint : fahrenheitToCelsius(setpoint) + setpoint = Math.max(Math.min(setpoint, maxHeatingSetpointTemperature), minHeatingSetpointTemperature) + [ + secure(zwave.thermostatSetpointV2.thermostatSetpointSet([precision: 1, scale: 0, scaledValue: setpoint, setpointType: 1, size: 2])), + "delay 2000", + secure(zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: 1)) + ] +} + +def refresh() { + def cmds = [ + secure(zwave.batteryV1.batteryGet()), + secure(zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: 1)), + secure(zwave.sensorMultilevelV5.sensorMultilevelGet()), + secure(zwave.thermostatModeV2.thermostatModeGet()) + ] + + delayBetween(cmds, 2500) +} + +def ping() { + refresh() +} + +private secure(cmd) { + if (zwaveInfo.zw.endsWith("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} + +private getMaxHeatingSetpointTemperature() { + if (isEverspringRadiatorThermostat()) { + temperatureScale == 'C' ? 35 : 95 + } else { + temperatureScale == 'C' ? 30 : 86 + } +} + +private getMinHeatingSetpointTemperature() { + if (isEverspringRadiatorThermostat()) { + temperatureScale == 'C' ? 15 : 59 + } else { + temperatureScale == 'C' ? 10 : 50 + } +} + +private getThermostatSupportedModes() { + if (isEverspringRadiatorThermostat()) { + ["off", "heat", "emergency heat"] + } else { + ["off","heat"] + } +} + +private isEverspringRadiatorThermostat() { + zwaveInfo.mfr == "0060" && zwaveInfo.prod == "0015" +} diff --git a/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy b/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy index f8709453105..7015b52076c 100644 --- a/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy +++ b/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy @@ -11,6 +11,9 @@ * for the specific language governing permissions and limitations under the License. * */ +import groovy.json.JsonOutput + + metadata { definition (name: "Z-Wave Window Shade", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind") { capability "Window Shade" @@ -106,6 +109,7 @@ def getCheckInterval() { def installed() { sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) response(refresh()) } @@ -222,6 +226,11 @@ def presetPosition() { setLevel(preset ?: state.preset ?: 50) } +def pause() { + log.debug "pause()" + stop() +} + def stop() { log.debug "stop()" zwave.switchMultilevelV3.switchMultilevelStopLevelChange().format()