From 9c2b27aa16b98ec534474273edf28493c67f6b5d Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:39:35 +0800 Subject: [PATCH 001/184] DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch (#69686) * DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch * change jion name Co-authored-by: Winnie Wen --- .../zwave-metering-switch.src/zwave-metering-switch.groovy | 1 + 1 file changed, 1 insertion(+) 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 b4c54658a1a..507ec4b53e2 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -52,6 +52,7 @@ metadata { fingerprint mfr: "031E", prod: "0002", model: "0001", deviceJoinName: "Inovelli Switch" //US //Inovelli Switch Red Series fingerprint mfr: "0154", prod: "0003", model: "000A", deviceJoinName: "POPP Outlet", ocfDeviceType: "oic.d.smartplug" //EU //POPP Smart Outdoor Plug fingerprint mfr: "010F", prod: "1F01", model: "1000", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Fibaro walli Outlet //Fibaro Outlet + fingerprint mfr: "0312", prod: "FF00", model: "FF0E", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP21ZP } // simulator metadata From 7bbd865dbf9c46822804cf6078e9f99e1ca12f15 Mon Sep 17 00:00:00 2001 From: jiangshanyang <72915227+jiangshanyang0203@users.noreply.github.com> Date: Fri, 2 Jul 2021 22:13:00 +0800 Subject: [PATCH 002/184] Adjust the calculation method of battery of ThirdReality door sensor --- .../Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index 29eb6e072dc..f36c65ea5f6 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -127,7 +127,7 @@ def refresh() { log.debug "Refreshing Battery and ZONE Status" def manufacturer = getDataValue("manufacturer") def refreshCmds = zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) - if (manufacturer == "ORVIBO" || manufacturer == "eWeLink" || manufacturer == "HEIMAN" || manufacturer == "Third Reality, Inc") { + if (manufacturer == "ORVIBO" || manufacturer == "eWeLink" || manufacturer == "HEIMAN" ) { refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } else { // this is actually just supposed to be for Aurora, but we'll make it the default as it's more widely supported refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) From 38031697b4a8a660a7124779a2139fb5b5182664 Mon Sep 17 00:00:00 2001 From: Konrad Date: Fri, 2 Jul 2021 16:54:14 +0200 Subject: [PATCH 003/184] ICP-14003 - adds mnmn and vid for Leviton Zigbee Dimmers: DG3HL,DG6HD fingerprints --- .../smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy index 8e90fbedd01..19854866e2a 100644 --- a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy +++ b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy @@ -53,8 +53,8 @@ metadata { fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 145", deviceJoinName: "Innr Light" //Innr Smart Candle White // Leviton - fingerprint manufacturer: "Leviton", model: "DG3HL", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Leviton Zigbee Plug-in DImmer DG3HL, Raw Description: 01 0104 0101 00 08 0000 0003 0004 0005 0006 0008 0301 0B05 01 0019 - fingerprint manufacturer: "Leviton", model: "DG6HD", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" //Leviton Zigbee Dimmer DG6HD, Raw Description: 01 0104 0101 00 08 0000 0003 0004 0005 0006 0008 0301 0B05 + fingerprint manufacturer: "Leviton", model: "DG3HL", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.smartplug", mnmn: "SmartThings", vid:"SmartThings-smartthings-Leviton_Zigbee_Dimmer" //Leviton Zigbee Plug-in DImmer DG3HL, Raw Description: 01 0104 0101 00 08 0000 0003 0004 0005 0006 0008 0301 0B05 01 0019 + fingerprint manufacturer: "Leviton", model: "DG6HD", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch", mnmn: "SmartThings", vid:"SmartThings-smartthings-Leviton_Zigbee_Dimmer" //Leviton Zigbee Dimmer DG6HD, Raw Description: 01 0104 0101 00 08 0000 0003 0004 0005 0006 0008 0301 0B05 // OSRAM fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Smart Connected Light From 49e9a50099f6ff7f4ffa53940dfe4bf9b0c4776e Mon Sep 17 00:00:00 2001 From: natec007 Date: Fri, 2 Jul 2021 14:35:30 -0700 Subject: [PATCH 004/184] DevWs for Plaid Systems LLC containing containing Spruce Controller SST (#68969) * DevWs for Plaid Systems LLC containing containing Spruce Controller SST * fixed spaces to tabs --- .../spruce-controller.groovy | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy index 64c0a54dcd4..c2a6159c6df 100644 --- a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy +++ b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2020 PlaidSystems + * Copyright 2021 PlaidSystems * * 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: @@ -11,6 +11,14 @@ * for the specific language governing permissions and limitations under the License. * +Version v3.7 + * update add zoneOn, zoneOff commands for external integration + * move zone status update to parse + + Version v3.6 + * update setTouchButtonDuration to only apply when controller is switched off + * add external command settingsMap for use with user added Spruce Scheduler + Version v3.5 * update zigbee ONOFF cluster * update Health Check @@ -56,7 +64,7 @@ import groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType //dth version -def getVERSION() {'v3.5 3-2021'} +def getVERSION() {'v3.7 6-2021'} def getDEBUG() {false} def getHC_INTERVAL_MINS() {60} //zigbee cluster, attribute, identifiers @@ -88,10 +96,13 @@ metadata { attribute "rainSensor", "string" attribute "valveDuration", "NUMBER" + command "zoneOn" + command "zoneOff" command "setStatus" command "setRainSensor" command "setControllerState" command "setValveDuration" + command "settingsMap" //new release fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01", zigbeeNodeType: "ROUTER", deviceJoinName: "Spruce Irrigation Controller" @@ -141,7 +152,8 @@ metadata { //----------------------zigbee parse-------------------------------// // Parse incoming device messages to generate events -def parse(String description) { +def parse(description) { + if (DEBUG) log.debug description def result = [] def endpoint, value, command def map = zigbee.parseDescriptionAsMap(description) @@ -179,7 +191,8 @@ def parse(String description) { def child = childDevices.find{it.deviceNetworkId == "${device.deviceNetworkId}:${endpoint}"} if (child) child.sendEvent(name: "valve", value: onoff) - if (device.latestValue("controllerState") == "off") return setTouchButtonDuration() + sendEvent(name: "status", value: "Zone ${endpoint-1} ${onoff}", descriptionText: "Zone ${endpoint-1} ${onoff}", displayed:true) + return setTouchButtonDuration() break case "rainsensor": def rainSensor = (value == 1 ? "wet" : "dry") @@ -317,7 +330,7 @@ def setTouchButtonDuration() { def sendCmds = [] sendCmds.push(zigbee.writeAttribute(zigbee.ONOFF_CLUSTER, OFF_WAIT_TIME_ATTRIBUTE, DataType.UINT16, touchButtonDuration, [destEndpoint: 1])) - return sendCmds + if (device.latestValue("controllerState") == "off") return sendCmds } //controllerState @@ -403,7 +416,6 @@ def valveOn(valueMap) { def endpoint = valueMap.dni.replaceFirst("${device.deviceNetworkId}:","").toInteger() def duration = (device.latestValue("valveDuration").toInteger()) - sendEvent(name: "status", value: "${valueMap.label} on for ${duration}min(s)", descriptionText: "Zone ${valueMap.label} on for ${duration}min(s)") if (DEBUG) log.debug "state ${state.hasConfiguredHealthCheck} ${zigbee.ONOFF_CLUSTER}" zoneOn(endpoint, duration) } @@ -411,14 +423,12 @@ def valveOn(valueMap) { def valveOff(valueMap) { def endpoint = valueMap.dni.replaceFirst("${device.deviceNetworkId}:","").toInteger() - sendEvent(name: "status", value: "${valueMap.label} turned off", descriptionText: "${valueMap.label} turned off") - zoneOff(endpoint) } def zoneOn(endpoint, duration) { - //send duration from slider - return zoneDuration(duration) + zigbee.command(zigbee.ONOFF_CLUSTER, 1, "", [destEndpoint: endpoint]) + //send duration + return zoneDuration(duration.toInteger()) + zigbee.command(zigbee.ONOFF_CLUSTER, 1, "", [destEndpoint: endpoint]) } def zoneOff(endpoint) { @@ -464,7 +474,7 @@ def startSchedule() { //write switch time settings map def settingsMap(WriteTimes, attrType) { - + if (DEBUG) log.debug "settingsMap ${WriteTimes}, ${attrType}" def runTime def sendCmds = [] for (endpoint in 1..17) { From f650e7d04f22b0a52ac58826d84eb786fd9fee02 Mon Sep 17 00:00:00 2001 From: NArlt <79513123+NArlt@users.noreply.github.com> Date: Fri, 2 Jul 2021 23:36:33 +0200 Subject: [PATCH 005/184] DevWs for TechniSat Digital GmbH containing containing TechniSat Double-Switch including child DTH (#66242) * DevWs for TechniSat Digital GmbH containing containing TechniSat Double-Switch * added child DTH for serial switch * requested changes * switched child DTH to "smartthings/Child Metering Switch" --- .../technisat-series-switch.groovy | 461 ++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy diff --git a/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy b/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy new file mode 100644 index 00000000000..c1287b2e8c7 --- /dev/null +++ b/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy @@ -0,0 +1,461 @@ +/** + * Copyright 2021 TechniSat + * + * 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 groovy.json.JsonOutput + +metadata { + definition (name: "TechniSat Series switch", namespace: "TechniSat", author: "TechniSat", vid:"generic-switch-power-energy", + mnmn: "SmartThings") { + capability "Energy Meter" + capability "Switch" + capability "Power Meter" + capability "Refresh" + capability "Configuration" + capability "Health Check" + + fingerprint mfr: "0299", prod: "0003", model: "1A91", deviceJoinName: "TechniSat Switch 1" + } + + preferences { + parameterMap.each { + input(title: "Parameter ${it.paramZwaveNum}: ${it.title}", + description: it.descr, + type: "paragraph", + element: "paragraph") + if (it.enableSwitch) { + input(name: it.enableKey, + title: "Enable", + type: "bool", + required: false) + } + input(name: it.key, + title: it.paramName, + type: it.type, + options: it.values, + range: it.range, + required: false) + } + } +} + +private createChild() { + + log.debug "createChild componentLabel: ${componentLabel}" + try { + String dni = "${device.deviceNetworkId}:2" + def componentLabel = "${device.displayName[0..-2]}2" + addChildDevice("smartthings","Child Metering Switch", dni, device.getHub().getId(), + [completedSetup: true, label: "${componentLabel}", isComponent: false]) + log.debug "Endpoint 2 (TechniSat Series switch child) added as $componentLabel" + } catch (e) { + log.warn "Failed to add endpoint 2 ($desc) as TechniSat Series switch child - $e" + } +} + +def installed() { + log.debug "installed()" + createChild() + initStateConfig() + initialize() +} + +def updated() { + log.debug "updated()" + initialize() + syncConfig() +} + +def initialize() { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +def getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x32: 3, // Meter + 0x56: 1, // Crc16Encap + 0x60: 3, // Multi-Channel + 0x70: 2, // Configuration + 0x98: 1, // Security + ] +} + +def parse(String description) { + def result = null + if (description != "updated") { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result = zwaveEvent(cmd) + log.debug("'$description' parsed to $result") + } else { + log.debug("Couldn't zwave.parse '$description'") + } + } + result +} + +def createMeterEvent(cmd) { + def eventMap = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + } else if (cmd.scale == 1) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kVAh" + } else if (cmd.scale == 2) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + } + } + eventMap +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, endpoint=null) { + log.debug "v3 Meter report endpoint $endpoint: "+cmd + if (endpoint == 1) { + createEvent(createMeterEvent(cmd)) + } else if (endpoint == 2) { + childDevices[0]?.sendEvent(createMeterEvent(cmd)) + } + +} + +def handlOnOffReport(cmd, endpoint) { + def value = (cmd.value ? "on" : "off") + if (endpoint == 1) { + def evt = createEvent(name: "switch", value: value, type: "physical", descriptionText: "$device.displayName was turned $value") + if (evt.isStateChange) { + [evt, response(["delay 3000",encapEp(endpoint, meterGet(scale: 2))])] + } else { + evt + } + } else if (endpoint == 2) { + childDevices[0]?.sendEvent(name: "switch", value: value, type: "physical", descriptionText: "$device.displayName was turned $value") + sendHubCommand(encapEp(endpoint, meterGet(scale: 2))) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint=null) { + log.debug "Basic report endpoint $endpoint: "+cmd + handlOnOffReport(cmd,endpoint) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint=null) { + log.debug "Switch binary report endpoint: $endpoint: "+cmd + handlOnOffReport(cmd,endpoint) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def param = parameterMap.find( {it.paramZwaveNum == cmd.parameterNumber } ) + + if (state.currentConfig."$param.key".status != "sync") { + if (state.currentConfig."$param.key"?.newValue == cmd.scaledConfigurationValue || + state.currentConfig."$param.key".status == "init") { + log.debug "Parameter ${param.key} set to value:${cmd.scaledConfigurationValue}" + state.currentConfig."$param.key".status = "sync" + state.currentConfig."$param.key".value = cmd.scaledConfigurationValue + } else { + log.debug "Parameter ${param.key} set to value failed: is:${cmd.scaledConfigurationValue} <> ${state.currentConfig."$param.key".newValue}" + state.currentConfig."$param.key".status = "failed" + syncConfig() + } + } else { + log.debug "Parameter ${param.key} update received. value:${cmd.scaledConfigurationValue}" + state.currentConfig."$param.key".value = cmd.scaledConfigurationValue + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { + cmd.parameter = cmd.parameter.drop(2) + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x32: 3]) + log.debug "handle cmd on endpoint ${cmd.sourceEndPoint}" + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, endpoint=null) { + if (endpoint == null) { + log.debug "${device.displayName}: Unhandled: $cmd" + } else { + log.debug("$device.displayName: $cmd endpoint: $endpoint") + } + [:] +} + +def getEndpoint(deviceNetworkId) { + def split = deviceNetworkId?.split(":") + return (split.length > 1) ? split[1] as Integer : null +} + +def createOnOffCmd(value, endpoint = 1) { + log.debug "createOnOffCmd value $value endpoint $endpoint" + delayBetween([ + encapEp(endpoint, zwave.switchBinaryV1.switchBinarySet(switchValue: value)), + encapEp(endpoint, zwave.switchBinaryV1.switchBinaryGet()), + encapEp(endpoint, meterGet(scale: 2)) + ]) +} + +def on() { + createOnOffCmd(0xFF) +} + +def off() { + createOnOffCmd(0x00) +} + +def childOnOff(deviceNetworkId, value) { + def endpoint = getEndpoint(deviceNetworkId) + log.debug("childOnOff from endpoint ${endpoint}") + if (endpoint != null) { + sendHubCommand(createOnOffCmd(value, endpoint)) + } +} + +def ping() { + log.debug "ping()" + refresh() +} + +def poll() { + sendHubCommand(refresh()) +} + +def refreshAll() { + sendHubCommand(refresh(1)) + sendHubCommand(refresh(2)) +} + +def refresh(endpoint = 1) { + log.debug "refresh()" + delayBetween([ + encapEp(endpoint, zwave.switchBinaryV1.switchBinaryGet()), + encapEp(endpoint, meterGet(scale: 0)), + encapEp(endpoint, meterGet(scale: 2)) + ]) +} + +def childRefresh(deviceNetworkId) { + def endpoint = getEndpoint(deviceNetworkId) + log.debug("childRefresh from endpoint ${endpoint}") + if (endpoint != null) { + sendHubCommand(refresh(endpoint)) + } +} + + +def childReset(deviceNetworkId) { + def endpoint = getEndpoint(deviceNetworkId) + log.debug("childReset from endpoint ${endpoint}") +} + +def configure() { + log.debug "configure()" + def result = [] + + log.debug "Configure zwaveInfo: "+zwaveInfo + + initStateConfigFromDevice() + logStateConfig() + refreshAll() +} + +def meterGet(map) { + return zwave.meterV2.meterGet(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + log.debug "Parsed SecurityMessageEncapsulation into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract Secure command from $cmd" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { + def version = commandClassVersions[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) { + log.debug "Parsed Crc16Encap into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract CRC16 command from $cmd" + } +} + +private secEncap(physicalgraph.zwave.Command cmd) { + log.debug "encapsulating command using Secure Encapsulation, command: $cmd" + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() +} + +private crcEncap(physicalgraph.zwave.Command cmd) { + log.debug "encapsulating command using CRC16 Encapsulation, command: $cmd" + zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() +} + +def encapEp(endpointNumber, cmd) { + if (cmd instanceof physicalgraph.zwave.Command) { + encap(zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpointNumber).encapsulate(cmd)) + } else if (cmd.startsWith("delay")) { + cmd + } else { + def header = "600D00" + String.format("%s%02X%s", header, endpointNumber, cmd) + } +} + +private encap(physicalgraph.zwave.Command cmd) { + if (zwaveInfo?.zw?.contains("s")) { + secEncap(cmd) + } else if (zwaveInfo?.cc?.contains("56")) { + crcEncap(cmd) + } else { + log.debug "no encapsulation supported for command: $cmd" + cmd.format() + } +} + +private isConfigChanged(parameter) { + def settingsValue = settings."$parameter.key" + log.debug "isConfigChanged parameter:${parameter.key}: ${settingsValue}" + if (parameter.enableSwitch) { + if (settings."$parameter.enableKey" != null) { + if (settings."$parameter.enableKey" == false) { + settingsValue = 0; + } + } + } + if (settingsValue != null) { + Integer value = 0 + if (parameter.type == "number") { + value = settingsValue + } else { + value = Integer.parseInt(settingsValue) + } + if (state.currentConfig."$parameter.key".value != value) { + state.currentConfig."$parameter.key".newValue = value + log.debug "${parameter.key} set:${value} value:${state.currentConfig."$parameter.key".value} newValue:${state.currentConfig."$parameter.key".newValue}" + return true + } else if (state.currentConfig."$parameter.key".status != "sync") { + log.debug "${parameter.key} retry to set; is:${state.currentConfig."$parameter.key".value} should:${state.currentConfig."$parameter.key".newValue}" + return true + } + return false + } else { + log.debug "pref value not set yet" + return false + } +} + +private syncConfig() { + def commands = [] + parameterMap.each { + if (isConfigChanged(it)) { + log.debug "Parameter ${it.key} has been updated from value: ${state.currentConfig."$it.key".value} to ${state.currentConfig."$it.key".newValue}" + state.currentConfig."$it.key".status = "syncPending" + commands << response(encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: state.currentConfig."$it.key".newValue, + parameterNumber: it.paramZwaveNum, size: it.paramZwaveSize))) + commands << response(encap(zwave.configurationV2.configurationGet(parameterNumber: it.paramZwaveNum))) + } else if (state.currentConfig."$it.key".value == null) { + log.warn "Parameter ${it.key} no. ${it.paramZwaveNum} has no value. Please check preference declaration for errors." + } + } + if (commands) { + sendHubCommand(commands,1000) + } +} + +private initStateConfig() { + log.debug "initStateConfig()" + state.currentConfig = [:] + parameterMap.each { + log.debug "set $it.key" + state.currentConfig."$it.key" = [:] + state.currentConfig."$it.key".value = new Integer('0') + state.currentConfig."$it.key".newValue = new Integer('0') + state.currentConfig."$it.key".status = "init" + } +} + +private initStateConfigFromDevice() { + log.debug "initStateConfigFromDevice()" + def commands = [] + parameterMap.each { + commands << response(encap(zwave.configurationV2.configurationGet(parameterNumber: it.paramZwaveNum))) + } + if (commands) { + sendHubCommand(commands,1000) + } +} + +private logStateConfig() { + parameterMap.each { + log.debug "key:$it.key value: ${state.currentConfig."$it.key".value} newValue: ${state.currentConfig."$it.key".newValue} status: ${state.currentConfig."$it.key".status}" + } +} + +private getParameterMap() { + [ + [ + title: "Wattage meter report interval", + descr: "Interval of current wattage meter reports in 10 seconds. 3 ... 8640 (30 seconds - 1 day)", + key: "wattageMeterReportInterval", + paramName: "Set Value (3..8640)", + type: "number", + range: "3..8640", + enableSwitch: true, + enableSwitchDefaultValue: true, + enableKey: "wattageMeterReportDisable", + paramZwaveNum: 2, + paramZwaveSize: 1 + ], + [ + title: "Energy meter report interval", + descr: "Interval of active energy meter reports in minutes. 10 ... 30240 (10 minutes - 3 weeks)", + key: "energyMeterReportInterval", + enableSwitch: true, + enableSwitchDefaultValue: true, + enableKey: "energyMeterReportDisable", + paramName: "Set Value (10..30240)", + type: "number", + range: "10..30240", + paramZwaveNum: 3, + paramZwaveSize: 2 + ], + [ + title: "Operation mode of buttons T1 - T4", + descr: "Operation mode of buttons T1 - T4", + key: "buttonModeSetting", + paramName: "Select", + type: "enum", + values: [ + 0: "0 - top buttons turn outputs on, bottom buttons turn outputs off", + 1: "1 - buttons toggle the outputs on/off" + ], + paramZwaveNum: 4, + paramZwaveSize: 1 + ] + ] +} \ No newline at end of file From 1ef97e41afb168c3d6e2c619321ddc5030fb2a0e Mon Sep 17 00:00:00 2001 From: jiangshanyang <72915227+jiangshanyang0203@users.noreply.github.com> Date: Thu, 8 Jul 2021 21:38:58 +0800 Subject: [PATCH 006/184] Add smartplug and modify switch of ThirdReality Add smartplug and modify switch of ThirdReality Plug and Switch --- .../smartthings/zigbee-switch.src/zigbee-switch.groovy | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 7884121a1a8..4e9f7be26d1 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -95,9 +95,10 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0019", manufacturer: "", model: "TERNCY-LS01", deviceJoinName: "Terncy Switch" //Terncy Smart Light Socket // Third Reality - fingerprint profileId: "0104", inClusters: "0000, 0006", outClusters: "0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS009Z", deviceJoinName: "RealitySwitch Switch" //RealitySwitch-Gen3 Zigbee Mode - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS008Z", deviceJoinName: "RealitySwitch Switch" //RealitySwitch Plus - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS007Z", deviceJoinName: "RealitySwitch Switch" //RealitySwitch + fingerprint profileId: "0104", inClusters: "0000, 0006", outClusters: "0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS009Z", deviceJoinName: "ThirdReality Switch" //RealitySwitch-Gen3 Zigbee Mode + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS008Z", deviceJoinName: "ThirdReality Switch" //RealitySwitch Plus + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS007Z", deviceJoinName: "ThirdReality Switch" //RealitySwitch + fingerprint profileId: "0104", deviceId: "0051", inClusters: "0000, 0003, 0004, 0005, 0006",outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSP019BZ", deviceJoinName: "ThirdReality Plug", ocfDeviceType: "oic.d.smartplug" //RealityPlug // Dawon fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0019, 0002, 0009", manufacturer: "DAWON_DNS", model: "PM-S140-ZB", deviceJoinName: "Dawon Switch" //DAWOS DNS In-Wall Switch PM-S140-ZB @@ -184,4 +185,4 @@ def configure() { sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) log.debug "Configuring Reporting and Bindings." zigbee.onOffRefresh() + zigbee.onOffConfig() -} \ No newline at end of file +} From d05a6aa8f8acc9cb42d3f847b196d78c5f9f9110 Mon Sep 17 00:00:00 2001 From: Aaron Huus Date: Tue, 13 Jul 2021 15:58:10 -0500 Subject: [PATCH 007/184] Updating Ecolink URL --- smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy index 2a3a78cb1d9..ca7f0cc9be0 100644 --- a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy +++ b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy @@ -201,7 +201,7 @@ def callback() { redirect_uri: callbackUrl ] - def tokenUrl = "https://www.ecobee.com/home/token?${toQueryString(tokenParams)}" + def tokenUrl = "${apiEndpoint}/token?${toQueryString(tokenParams)}" httpPost(uri: tokenUrl) { resp -> state.refreshToken = resp.data.refresh_token From 932788bee5aec50151f2c158a246d8a5ec1d8a7e Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Thu, 15 Jul 2021 23:42:34 -0700 Subject: [PATCH 008/184] DevWs for Smartenit, Inc containing containing EVSE (#70221) * DevWs for Smartenit, Inc containing containing EVSE * Space fixes * Adjusted MeteringCluster constant reference. Syntax fixes, * Spacing fixes, removed refresh() commands from health check * Configuration modifications. --- .../smartelek-evse.src/smartelek-evse.groovy | 341 ++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy diff --git a/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy b/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy new file mode 100644 index 00000000000..ccd01619da8 --- /dev/null +++ b/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy @@ -0,0 +1,341 @@ +/**************************************************************************** + * DRIVER NAME: Smartenit EVSE + * DESCRIPTION: Device handler for Smartenit SmartElek EVSE + * + * $Rev: $: 2 + * $Author: $: Luis Contreras + * $Date: $: 06/23/2021 + * $HeadURL: $: + + **************************************************************************** + * This software is owned by Compacta and/or its supplier and is protected + * under applicable copyright laws. All rights are reserved. We grant You, + * and any third parties, a license to use this software solely and + * exclusively on Compacta products. You, and any third parties must reproduce + * the copyright and warranty notice and any other legend of ownership on each + * copy or partial copy of the software. + * + * THIS SOFTWARE IS PROVIDED "AS IS". COMPACTA MAKES NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, + * ACCURACY OR LACK OF NEGLIGENCE. COMPACTA SHALL NOT, UNDERN ANY CIRCUMSTANCES, + * BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, SPECIAL, + * INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON WHATSOEVER. + * + * Copyright Compacta International, Ltd 2016. All rights reserved + ****************************************************************************/ + // EVSE Cluster Doc: https://docs.smartenit.io/display/SMAR/EVSE+Processor+Details + + import groovy.transform.Field + + @Field final EVSECluster = 0xFF00 + @Field final MeteringCurrentSummation = 0x0000 + @Field final MeteringInstantDemand = 0x0400 + @Field final EnergyDivisor = 100000 + @Field final CurrentDivisor = 100 + @Field final ChargingStatus = 0x0000 + @Field final ChargerLevel = 0x0001 + @Field final ChargerAutoStart = 0x0003 + @Field final ChargerFault = 0x0004 + @Field final ChargerMaximumCurrent = 0x0011 + @Field final ChargerSessionDuration = 0x0013 + @Field final ChargerDeliveredSummation = 0x0014 + @Field final ChargerSessionSummation = 0x0015 + @Field final ChargerSessionPeakCurrent = 0x0016 + @Field final ChargerVRMS = 0x0020 + @Field final ChargerIRMS = 0x0021 + @Field final SmartenitMfrCode = 0x1075 + @Field final StartCharging = 0x00 + @Field final StopCharging = 0x02 + @Field final EnableAutoStartMode = 0x04 + @Field final DisableAutoStartMode = 0x05 + +metadata { + definition (name: "SmartElek EVSE", namespace: "Smartenit", author: "Luis Contreras", mnmn: "SmartThingsCommunity", vid: "18da1704-2bbc-37ec-92a5-35e911024cea", ocfDeviceType: "oic.d.smartplug") { + capability "monthpublic25501.chargerstate" + capability "monthpublic25501.chargerlevel" + capability "monthpublic25501.chargerfault" + capability "monthpublic25501.chargerirms" + capability "monthpublic25501.chargersessionpeakcurrent" + capability "monthpublic25501.chargersessionsummation" + capability "monthpublic25501.chargerautostart" + capability "monthpublic25501.chargermaximumcurrent" + capability "monthpublic25501.chargersessionduration" + capability "Actuator" + capability "Configuration" + capability "Refresh" + capability "Power Meter" + capability "Energy Meter" + capability "Switch" + capability "Health Check" + capability "Voltage Measurement" + + command "stopcharging" + command "startcharging" + + fingerprint model: "IOTEVSE-Z", manufacturer: "Smartenit, Inc", deviceJoinName: "Smartenit EVSE" + } +} + +def getFPoint(String FPointHex){ + return (Float)Long.parseLong(FPointHex, 16) +} + +// Parse incoming device messages to generate events +def parse(String description) { + def event = zigbee.getEvent(description) + if (event) { + log.debug "event: ${event}, ${event.name}, ${event.value}" + if (event.name == "power") { + sendEvent(name: "power", value: (event.value/EnergyDivisor)) + } else { + sendEvent(event) + } + } + else { + def mapDescription = zigbee.parseDescriptionAsMap(description) + log.debug "mapDescription... : ${mapDescription}" + if (mapDescription) { + if (mapDescription.clusterInt == zigbee.SIMPLE_METERING_CLUSTER) { + if (mapDescription.attrInt == MeteringCurrentSummation) { + return sendEvent(name:"energy", value: getFPoint(mapDescription.value)/EnergyDivisor) + } else if (mapDescription.attrInt == MeteringInstantDemand) { + return sendEvent(name:"power", value: getFPoint(mapDescription.value/EnergyDivisor)) + } + } else if (mapDescription.clusterInt == EVSECluster) { + log.debug "EVSE cluster, attrId: ${mapDescription.attrId}, value: ${mapDescription.value}" + if (mapDescription.attrInt == ChargingStatus) { + def strvalue = parseChargerStatusValue(mapDescription.value) + log.debug "charging status attribute: ${mapDescription.value}, ${strvalue}" + if (strvalue == "unplugged") { + sendEvent(name:"sessionDuration", value: "--") + sendEvent(name:"sessionSummation", value: 0) + } + if (strvalue == "charging") { + sendEvent(name:"switch", value:"on") + } else { + sendEvent(name:"switch", value:"off") + } + return sendEvent(name:"chargerStatus", value: strvalue) + } else if (mapDescription.attrInt == ChargerLevel) { + def strvalue = parseChargerLevelValue(mapDescription.value) + return sendEvent(name:"level", value: strvalue) + } else if (mapDescription.attrInt == ChargerAutoStart) { + def val = zigbee.convertHexToInt(mapDescription.value) + log.debug "autostart value: ${val} " + return sendEvent(name:"autoStart", value: val) + } else if (mapDescription.attrInt == ChargerFault) { + def strvalue = parseChargerFaultValue(mapDescription.value) + return sendEvent(name:"fault", value: strvalue) + } else if (mapDescription.attrInt == ChargerMaximumCurrent) { + log.debug "charger max current: ${mapDescription.value}" + return sendEvent(name:"maximumCurrent", value: getFPoint(mapDescription.value)/CurrentDivisor, unit: "A") + } else if (mapDescription.attrInt == ChargerSessionDuration) { + int time = (int) Long.parseLong(mapDescription.value, 16); + log.debug "ChargerSessionDuration attribute: ${mapDescription.value}, time: ${time}" + def hours = Math.round(Math.floor(time / 3600)) + def secs = time % 3600 + def mins = Math.round(Math.floor(secs / 60)) + def timestr = "${hours} hr:${mins} min" + return sendEvent(name:"sessionDuration", value: timestr) + } else if (mapDescription.attrInt == ChargerSessionSummation) { + log.debug "ChargerSessionSummation attribute: ${mapDescription.value}" + return sendEvent(name:"sessionSummation", value: getFPoint(mapDescription.value)/EnergyDivisor, unit: "kWh") + } else if (mapDescription.attrInt == ChargerSessionPeakCurrent) { + log.debug "ChargerSessionPeakCurrent attribute: ${mapDescription.value}" + return sendEvent(name:"sessionPeakCurrent", value: getFPoint(mapDescription.value) / 100, unit: "A") + } else if (mapDescription.attrInt == ChargerVRMS) { + log.debug "ChargerVRMS attribute: ${mapDescription.value}" + return sendEvent(name:"voltage", value: getFPoint(mapDescription.value) / 100) + } else if (mapDescription.attrInt == ChargerIRMS) { + log.debug "ChargerIRMS attribute: ${mapDescription.value}" + return sendEvent(name:"current", value: getFPoint(mapDescription.value) / 100, unit: "A") + } else { + log.debug "attribute not handled" + } + } + } + } +} + +def setAutoStart(val) { + log.debug "Set auto start to: ${val}" + sendEvent(name:"autoStart", value: val) + + if (val == "1") { + log.debug "Sending enable autostart" + zigbee.command(EVSECluster, EnableAutoStartMode, "", [mfgCode: SmartenitMfrCode]) + } else if (val == "0") { + log.debug "Sending disable autostart" + zigbee.command(EVSECluster, DisableAutoStartMode, "", [mfgCode: SmartenitMfrCode]) + } +} + +def setMaximumCurrent(val) { + log.debug "Set max current val: ${val}" + + sendEvent(name:"maximumCurrent", value: val, unit: "A") + + int newMax = (int) (val * 100) + int convert = ((newMax << 8) & 0xFF00) | ((newMax >> 8) & 0xFF) + + zigbee.writeAttribute(EVSECluster, ChargerMaximumCurrent, 0x21, convert, [mfgCode: SmartenitMfrCode]) +} + +def parseChargerLevelValue(val) { + log.debug "parseChargerLevelValue: ${val}" + switch (val as Integer) { + case 0: + log.debug "level is unknown" + return "Unknown" + case 1: + log.debug "Charging @ L1" + return "Level 1" + case 2: + log.debug "Charging @ L2" + return "Level 2" + default: + return "" + } +} + +def parseChargerFaultValue(val) { + log.debug "parseChargerFaultValue: ${val}" + switch (val as Integer) { + case 0: + log.debug "No fault" + return "None" + case 1: + log.debug "Meter failed" + return "Meter failure" + case 2: + log.debug "Overvoltage" + return "Overvoltage" + case 3: + log.debug "Undervoltage" + return "Undervoltage" + case 4: + log.debug "Overcurrent" + return "Overcurrent" + case 5: + log.debug "Overheating" + return "Overheating" + case 16: + log.debug "Contact Wet" + return "Contact Wet" + case 17: + log.debug "Contact Dry" + return "Contact Dry" + case 18: + log.debug "Ground fault" + return "Ground Fault" + case 19: + log.debug "Pilot Short Circuit" + return "Short Circuit" + case 20: + log.debug "Wrong Supply" + return "Wrong Supply" + case 21: + log.debug "GFCI Failure" + return "GFCI Failure" + case 22: + log.debug "GMI Fault" + return "GMI Fault" + default: + log.debug "Unknown fault" + return "Unknown fault" + } +} + +def parseChargerStatusValue(val) { + log.debug "parseChargerStatusValue: ${val}" + switch (val as Integer) { + case 0: + log.debug "value is Unplugged" + return "unplugged" + break; + case 1: + log.debug "value is Plugged In" + return "pluggedin" + break; + case 2: + return "pluggedin" + break; + case 3: + log.debug "value is Charging" + return "charging" + break; + case 4: + log.debug "value is Fault" + return "fault" + break; + case 5: + log.debug "value is Charging Completed" + return "chargingcompleted" + break; + default: + return "" + break; + } +} + +def on() { + log.debug "received on command" + zigbee.command(EVSECluster, StartCharging, "", [mfgCode: SmartenitMfrCode]) +} + +def off() { + log.debug "received off command" + zigbee.command(EVSECluster, StopCharging, "", [mfgCode: SmartenitMfrCode]) +} + +def stopcharging() { + log.debug "sending stopcharging command.." + zigbee.command(EVSECluster, StopCharging, "", [mfgCode: SmartenitMfrCode]) +} + +def startcharging() { + log.debug "sending startcharging command.." + zigbee.command(EVSECluster, StartCharging, "", [mfgCode: SmartenitMfrCode]) +} + +def refresh() { + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation) + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand) + + zigbee.readAttribute(EVSECluster, ChargingStatus, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerVRMS, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerSessionSummation, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerSessionDuration, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerIRMS, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerLevel, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerMaximumCurrent, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerFault, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerSessionPeakCurrent, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(EVSECluster, ChargerAutoStart, [mfgCode: SmartenitMfrCode]) +} + +def configure() { + log.debug "in configure()" + configureHealthCheck() + return (zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation, 0x25, 0, 600, 50) + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand, 0x2a, 0, 600, 50) + + zigbee.configureReporting(EVSECluster, ChargingStatus, 0x30, 0x0, 0x0, null, [mfgCode: SmartenitMfrCode]) + + refresh() + ) +} + +def configureHealthCheck() { + Integer hcIntervalMinutes = 10 + sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} + +def updated() { + log.debug "in updated()" + // updated() doesn't have it's return value processed as hub commands, so we have to send them explicitly + def cmds = configureHealthCheck() + cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it)) } +} + +def ping() { + return refresh() +} \ No newline at end of file From 75efb54ee39b81ddda44ec86515f65182084f697 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Fri, 16 Jul 2021 15:13:15 +0800 Subject: [PATCH 009/184] WWST-7664 HEIMAN wall outlet HS6ESK-EF (#70996) --- .../zigbee-metering-plug.src/zigbee-metering-plug.groovy | 1 + 1 file changed, 1 insertion(+) 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 64b6b97e3c8..a280ced8888 100644 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -29,6 +29,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0105", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet (USB) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0104", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0009, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "E_Socket", deviceJoinName: "HEIMAN Outlet" //HEIMAN Smart Outlet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "HEIMAN", model: "HS6ESK-W-EF-3.0", deviceJoinName: "HEIMAN Outlet", ocfDeviceType: "oic.d.smartplug" //HEIMAN Smart Outlet fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "sengled", model: "E1C-NB7", deviceJoinName: "Sengled Outlet" //Sengled Smart Plug with Energy Tracker fingerprint profileId: "0104", manufacturer: "frient A/S", model: "SPLZB-131", deviceJoinName: "frient Outlet" // frient smart plug mini, raw description: 02 0104 0051 10 09 0000 0702 0003 0009 0B04 0006 0004 0005 0002 05 0000 0019 000A 0003 0406 fingerprint profileId: "0104", manufacturer: "frient A/S", model: "SPLZB-132", deviceJoinName: "frient Outlet" // frient smart plug mini, raw description: 02 0104 0051 10 09 0000 0702 0003 0009 0B04 0006 0004 0005 0002 05 0000 0019 000A 0003 0406 From 05bdf17ee2f4419d1dfdf07f542f8ff9914cc3b3 Mon Sep 17 00:00:00 2001 From: Steven Green Date: Fri, 16 Jul 2021 12:59:07 -0700 Subject: [PATCH 010/184] ICP-14063 Yale YDF40 reports double lock percentage (#68519) * ICP-14063 Yale YDF40 reports double lock percentage * refactoring --- devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index 8f63826a068..cb71cefc23f 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -477,10 +477,11 @@ private def parseAttributeResponse(String description) { def deviceName = device.displayName if (clusterInt == CLUSTER_POWER && attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) { responseMap.name = "battery" - responseMap.value = Math.round(Integer.parseInt(descMap.value, 16) / 2) // Handling Yale locks incorrect battery reporting issue if (reportsBatteryIncorrectly()) { responseMap.value = Integer.parseInt(descMap.value, 16) + } else { + 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) { @@ -1158,8 +1159,9 @@ def reportsBatteryIncorrectly() { "YRD210 PB DB", "YRD220/240 TSDB", "YRL210 PB LL", + "c700000202" //YDF40 ] - return (isYaleLock() && device.getDataValue("model") in badModels) + return device.getDataValue("model") in badModels } /** From 2a77200943ff07b494fb5598d2e76392d1c3ffa9 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Fri, 16 Jul 2021 15:03:18 -0700 Subject: [PATCH 011/184] DevWs for Smartenit, Inc containing containing Testing (#68971) * DevWs for Smartenit, Inc containing containing Testing * Style adjustments, child device handlers added. * Removed installed(), updated(), parse() from Child DTHes. Constants access modified. JoinName changed to Smartenit Switch. * Event description map comparison type modifications * Space fixes, cluster integer comparison fix * Child device reference changed to Child Switch --- .../iot8-z-child-analog-contact-switch.groovy | 32 +++ .../iot8-z-child-contact-switch.groovy | 32 +++ .../smartenit/iot8-z.src/iot8-z.groovy | 223 ++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 devicetypes/smartenit/iot8-z-child-analog-contact-switch.src/iot8-z-child-analog-contact-switch.groovy create mode 100644 devicetypes/smartenit/iot8-z-child-contact-switch.src/iot8-z-child-contact-switch.groovy create mode 100644 devicetypes/smartenit/iot8-z.src/iot8-z.groovy diff --git a/devicetypes/smartenit/iot8-z-child-analog-contact-switch.src/iot8-z-child-analog-contact-switch.groovy b/devicetypes/smartenit/iot8-z-child-analog-contact-switch.src/iot8-z-child-analog-contact-switch.groovy new file mode 100644 index 00000000000..5b86c69f3d2 --- /dev/null +++ b/devicetypes/smartenit/iot8-z-child-analog-contact-switch.src/iot8-z-child-analog-contact-switch.groovy @@ -0,0 +1,32 @@ +/** + * Virtual IOT8Z + * + * Copyright 2021 Luis Contreras + * + * 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: "IOT8-Z-child-analog-contact-switch", namespace: "Smartenit", author: "Luis Contreras", cstHandler: true, mnmn: "SmartThingsCommunity", vid: "50830b33-69d6-32a0-bebd-952eac44d074") { + capability "Contact Sensor" + capability "Sensor" + capability "Switch" + capability "monthpublic25501.analogSensor" + } +} + +// handle commands +def on() { + parent.childOn(device.deviceNetworkId) +} + +def off() { + parent.childOff(device.deviceNetworkId) +} \ No newline at end of file diff --git a/devicetypes/smartenit/iot8-z-child-contact-switch.src/iot8-z-child-contact-switch.groovy b/devicetypes/smartenit/iot8-z-child-contact-switch.src/iot8-z-child-contact-switch.groovy new file mode 100644 index 00000000000..d142fe92d17 --- /dev/null +++ b/devicetypes/smartenit/iot8-z-child-contact-switch.src/iot8-z-child-contact-switch.groovy @@ -0,0 +1,32 @@ +/** + * IOT8-Z_DI + * + * Copyright 2021 Luis Contreras + * + * 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: "IOT8-Z-child-contact-switch", namespace: "Smartenit", author: "Luis Contreras") { + capability "Actuator" + capability "Contact Sensor" + capability "Switch" + capability "Health Check" + } +} + +def on() { + log.debug "Executing 'on'" + parent.childOn(device.deviceNetworkId) +} + +def off() { + log.debug "Executing 'off'" + parent.childOff(device.deviceNetworkId) +} \ No newline at end of file diff --git a/devicetypes/smartenit/iot8-z.src/iot8-z.groovy b/devicetypes/smartenit/iot8-z.src/iot8-z.groovy new file mode 100644 index 00000000000..c500d1325ce --- /dev/null +++ b/devicetypes/smartenit/iot8-z.src/iot8-z.groovy @@ -0,0 +1,223 @@ +/** + * IOT8Z + * + * Copyright 2021 Luis Contreras + * + * 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: "IOT8-Z", namespace: "Smartenit", author: "Luis Contreras", cstHandler: true, mnmn: "SmartThingsCommunity", vid: "6d510b74-469c-3fa0-be7a-ec0894d38dcb") { + capability "Contact Sensor" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "Sensor" + capability "Switch" + capability "monthpublic25501.analogSensor" + + command "childOn", ["string"] + command "childOff", ["string"] + + fingerprint manufacturer: "Smartenit, Inc", model: "IOT8-Z", deviceJoinName: "Smartenit Switch", profileId: "0104", inClusters: "0000, 0003, 0006, 000C, 000F", outClusters: "0019" + } +} + +private getANALOG_INPUT_CLUSTER() { 0x000C } +private getBINARY_INPUT_CLUSTER() { 0x000F } +private getPRESENT_VALUE_ATTRIBUTE() { 0x0055 } +private getONOFF_ATTRIBUTE() { 0x0000 } + +def installed() { + log.debug "Installed" + createChildDevices() +} + +def updated() { + log.debug "Updated" + refresh() +} + +// parse events into attributes +def parse(String description) { + Map eventMap = zigbee.getEvent(description) + Map eventDescMap = zigbee.parseDescriptionAsMap(description) + + if (eventMap) { + if ((eventDescMap?.sourceEndpoint == "01") || (eventDescMap?.endpoint == "01")) { + if (eventDescMap?.clusterInt == ANALOG_INPUT_CLUSTER) { + return createEvent(name: "inputValue", value: eventDescMap?.value) + } else { + sendEvent(eventMap) + } + } else { + def childDevice = childDevices.find { + it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.sourceEndpoint}" || it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.endpoint}" + } + if (childDevice) { + childDevice.sendEvent(eventMap) + } else { + log.debug "Child device: $device.deviceNetworkId:${eventDescMap.sourceEndpoint} was not found" + } + } + } else if (eventDescMap) { + if ((eventDescMap?.sourceEndpoint == "01") || (eventDescMap?.endpoint == "01")) { + if (eventDescMap?.clusterInt == BINARY_INPUT_CLUSTER) { + if (eventDescMap?.value == "00") { + return createEvent(name: "contact", value: "open") + } else if (eventDescMap?.value == "01") { + return createEvent(name: "contact", value: "closed") + } + } else if (eventDescMap?.clusterInt == ANALOG_INPUT_CLUSTER) { + long convertedValue = Long.parseLong(eventDescMap?.value, 16) + Float percentage = Float.intBitsToFloat(convertedValue.intValue()) + percentage = (percentage / 1.60) * 100.0 + def ceilingVal = Math.ceil(percentage) + if (ceilingVal > 100.0) { + ceilingVal = 100.0 + } + + int intValue = (int) ceilingVal + return createEvent(name: "inputValue", value: intValue) + } + } else { + def childDevice = childDevices.find { + it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.sourceEndpoint}" || it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.endpoint}" + } + if (childDevice) { + if (eventDescMap?.clusterInt == BINARY_INPUT_CLUSTER) { + if (eventDescMap?.value == "00") { + def map = createEvent(name: "contact", value: "open") + childDevice.sendEvent(map) + } else if (eventDescMap?.value == "01") { + def map = createEvent(name: "contact", value: "closed") + childDevice.sendEvent(map) + } + } else if (eventDescMap?.clusterInt == ANALOG_INPUT_CLUSTER) { + long convertedValue = Long.parseLong(eventDescMap?.value, 16) + Float percentage = Float.intBitsToFloat(convertedValue.intValue()) + percentage = (percentage / 1.60) * 100.0 + def ceilingVal = Math.ceil(percentage) + if (ceilingVal > 100.0) { + ceilingVal = 100.0 + } + + int intValue = (int) ceilingVal + + def map = createEvent(name: "inputValue", value: intValue) + childDevice.sendEvent(map) + } + } + } + } +} + +def on() { + zigbee.on() +} + +def off() { + zigbee.off() +} + +def childOn(String dni) { + def childEndpoint = getChildEndpoint(dni) + zigbee.command(zigbee.ONOFF_CLUSTER, 0x01, "", [destEndpoint: childEndpoint]) +} + +def childOff(String dni) { + def childEndpoint = getChildEndpoint(dni) + zigbee.command(zigbee.ONOFF_CLUSTER, 0x00, "", [destEndpoint: childEndpoint]) +} + +def ping() { + refresh() +} + +def refresh() { + def refreshCommands = zigbee.onOffRefresh() + def numberOfChildDevices = 8 + + for (def endpoint : 2..numberOfChildDevices) { + refreshCommands += zigbee.readAttribute(zigbee.ONOFF_CLUSTER, ONOFF_ATTRIBUTE, [destEndpoint: endpoint]) + } + for (def endpoint : 1..4) { + refreshCommands += zigbee.readAttribute(BINARY_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, [destEndpoint: endpoint]) + } + + refreshCommands += zigbee.readAttribute(ANALOG_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, [destEndpoint: 0x0001]); + refreshCommands += zigbee.readAttribute(ANALOG_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, [destEndpoint: 0x0002]); + log.debug "refreshCommands: $refreshCommands" + + return refreshCommands +} + +private void createChildDevices() { + def numberOfChildDevices = 8 + + for (def endpoint: 2..numberOfChildDevices) { + try { + if (endpoint == 2) { + addChildDevice("Smartenit", "IOT8-Z-child-analog-contact-switch", "${device.deviceNetworkId}:0${endpoint}", device.hubId, + [completedSetup: true, + label: "${device.displayName} ${endpoint}", + isComponent: false + ]) + } else if (endpoint >= 3 && endpoint <= 4) { + addChildDevice("Smartenit", "IOT8-Z-child-contact-switch", "${device.deviceNetworkId}:0${endpoint}", device.hubId, + [completedSetup: true, + label: "${device.displayName} ${endpoint}", + isComponent: false + ]) + } else if (endpoint >= 5 && endpoint <= 8) { + addChildDevice("smartthings", "Child Switch", "${device.deviceNetworkId}:0${endpoint}", device.hubId, + [completedSetup: true, + label: "${device.displayName} ${endpoint}", + isComponent: false + ]) + } + } catch (Exception e) { + log.debug "Exception creating child device: ${e}" + } + } +} + +def configure() { + log.debug "configure" + + configureHealthCheck() + def configurationCommands = zigbee.configureReporting(BINARY_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, 0x10, 10, 600, null) + for (def endpoint: 2..4) { + configurationCommands += zigbee.configureReporting(BINARY_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, 0x10, 10, 600, null, [destEndpoint: endpoint]) + } + + configurationCommands += zigbee.onOffConfig(0, 120) + for (def endpoint : 2..8) { + configurationCommands += zigbee.configureReporting(zigbee.ONOFF_CLUSTER, ONOFF_ATTRIBUTE, 0x10, 0, 120, null, [destEndpoint: endpoint]) + } + + configurationCommands += zigbee.configureReporting(ANALOG_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, 0x39, 10, 600, 0x3dcccccd) + configurationCommands += zigbee.configureReporting(ANALOG_INPUT_CLUSTER, PRESENT_VALUE_ATTRIBUTE, 0x39, 10, 600, 0x3dcccccd, [destEndpoint: 2]) + + configurationCommands << refresh() + log.debug "configurationCommands: $configurationCommands" + return configurationCommands +} + +private getChildEndpoint(String dni) { + dni.split(":")[-1] as Integer +} + +def configureHealthCheck() { + log.debug "configureHealthCheck" + Integer hcIntervalMinutes = 12 + def healthEvent = [name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]] + sendEvent(healthEvent) +} \ No newline at end of file From ea240df07f07e87dd3eba3fb2be1d29b0c671d7a Mon Sep 17 00:00:00 2001 From: natec007 Date: Fri, 16 Jul 2021 15:05:41 -0700 Subject: [PATCH 012/184] DevWs for Plaid Systems LLC containing containing Spruce Sensor (#70599) * DevWs for Plaid Systems LLC containing containing Spruce Sensor * Fix device join name Update magic numbers to use constants or predefined values --- .../spruce-sensor.src/spruce-sensor.groovy | 525 +++++++----------- 1 file changed, 189 insertions(+), 336 deletions(-) diff --git a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy index d8ff0f971e9..6d20eb83694 100644 --- a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy +++ b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy @@ -1,7 +1,7 @@ /** - * Spruce Sensor -updated with SLP3 model number 3/2019 + * Spruce Sensor -updated for new Samsung App * - * Copyright 2014 Plaid Systems + * Copyright 2021 Plaid Systems * * 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: @@ -12,257 +12,164 @@ * 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. * - -------10/20/2015 Updates-------- - -Fix/add battery reporting interval to update - -remove polling and/or refresh - - -------5/2017 Updates-------- - -Add fingerprints for SLP - -add device health, check every 60mins + 2mins - - -------3/2019 Updates-------- - -Add fingerprints for SLP3 - -change device health from 62mins to 3 hours + + -------6/2021 Updates-------- + - Update for 2021 Samsung SmartThings App + */ - + +import groovy.json.JsonOutput +import physicalgraph.zigbee.zcl.DataType + +//dth version +def getVERSION() {"v1.0 6-2021"} +def getDEBUG() {true} +def getHC_INTERVAL_SECS() {3720} +def getMEASURED_VALUE_ATTRIBUTE() {0x0000} +def getCONFIGURE_REPORTING_RESPONSE_COMMAND() {0x07} + metadata { - definition (name: "Spruce Sensor", namespace: "plaidsystems", author: "Plaid Systems") { - - capability "Configuration" + definition (name: "Spruce Sensor", namespace: "plaidsystems", author: "Plaid Systems", mnmn: "SmartThingsCommunity", + mcdSync: true, vid: "4cff4731-67ce-310b-ada0-4d8e169a6df0") { + + capability "Sensor" + capability "Temperature Measurement" + capability "Relative Humidity Measurement" capability "Battery" - capability "Relative Humidity Measurement" - capability "Temperature Measurement" - capability "Sensor" - capability "Health Check" - //capability "Polling" - - attribute "maxHum", "string" - attribute "minHum", "string" - - - command "resetHumidity" - command "refresh" - - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", deviceJoinName: "Spruce Irrigation" //Spruce Sensor - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", deviceJoinName: "Spruce Irrigation" //Spruce Sensor - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + capability "Health Check" + capability "Configuration" + capability "Refresh" + + attribute "reportingInterval", "NUMBER" + + //new release + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "-100..100", displayDuringSetup: false - input "interval", "number", title: "Report Interval", description: "How often the device should report in minutes", range: "1..120", defaultValue: 10, displayDuringSetup: false - input "resetMinMax", "bool", title: "Reset Humidity min and max", required: false, displayDuringSetup: false - } - - tiles { - valueTile("temperature", "device.temperature", canChangeIcon: false, canChangeBackground: false) { - state "temperature", label:'${currentValue}°', - backgroundColors:[ - [value: 31, 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"] - ] - } - valueTile("humidity", "device.humidity", width: 2, height: 2, canChangeIcon: false, canChangeBackground: true) { - state "humidity", label:'${currentValue}%', unit:"", - backgroundColors:[ - [value: 0, color: "#635C0C"], - [value: 16, color: "#EBEB21"], - [value: 22, color: "#C7DE6A"], - [value: 42, color: "#9AD290"], - [value: 64, color: "#44B621"], - [value: 80, color: "#3D79D9"], - [value: 96, color: "#0A50C2"] - ], icon:"st.Weather.weather12" - } - - valueTile("maxHum", "device.maxHum", canChangeIcon: false, canChangeBackground: false) { - state "maxHum", label:'High ${currentValue}%', unit:"", - backgroundColors:[ - [value: 0, color: "#635C0C"], - [value: 16, color: "#EBEB21"], - [value: 22, color: "#C7DE6A"], - [value: 42, color: "#9AD290"], - [value: 64, color: "#44B621"], - [value: 80, color: "#3D79D9"], - [value: 96, color: "#0A50C2"] - ] - } - valueTile("minHum", "device.minHum", canChangeIcon: false, canChangeBackground: false) { - state "minHum", label:'Low ${currentValue}%', unit:"", - backgroundColors:[ - [value: 0, color: "#635C0C"], - [value: 16, color: "#EBEB21"], - [value: 22, color: "#C7DE6A"], - [value: 42, color: "#9AD290"], - [value: 64, color: "#44B621"], - [value: 80, color: "#3D79D9"], - [value: 96, color: "#0A50C2"] - ] - } - - valueTile("battery", "device.battery", decoration: "flat", canChangeIcon: false, canChangeBackground: false) { - state "battery", label:'${currentValue}% battery' - } - - main (["humidity"]) - details(["humidity","maxHum","minHum","temperature","battery"]) + input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph", title: "" + input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + + input description: "Gen 1 & 2 Sensors only: Measurement Interval 1-120 minutes (default: 10 minutes)", displayDuringSetup: false, type: "paragraph", element: "paragraph", title: "" + input "interval", "number", title: "Measurement Interval", description: "Set how often you would like to check soil moisture in minutes", range: "1..120", defaultValue: 10, displayDuringSetup: false + + input title: "Version", description: VERSION, displayDuringSetup: true, type: "paragraph", element: "paragraph" } + } -def parse(String description) { - log.debug "Parse description $description config: ${device.latestValue('configuration')} interval: $interval" - - Map map = [:] - - if (description?.startsWith('catchall:')) { - map = parseCatchAllMessage(description) - } - else if (description?.startsWith('read attr -')) { +// Parse incoming device messages to generate events +def parse(description) { + + def map + if (description?.startsWith("read attr -")) { + log.debug "read attr - ${description}" map = parseReportAttributeMessage(description) - } - else if (description?.startsWith('temperature: ') || description?.startsWith('humidity: ')) { - map = parseCustomMessage(description) } - def result = map ? createEvent(map) : null - - //check in configuration change - if (!device.latestValue('configuration')) result = poll() - if (device.latestValue('configuration') as float != interval && interval != null) { - result = poll() - } - log.debug "result: $result" - return result - -} + else if (isSupportedDescription(description)) { + log.debug "supported description: $description" + map = parseSupportedMessage(description) + } + else if (description?.startsWith("catchall:")) { + log.debug "catchall ${description}" + map = parseCatchAllMessage(description) + } + else if (DEBUG) log.debug "uncaught ${description}" + def result = map ? createEvent(map) : null + //check for configuration change and send configuration change + if (map && map.name == "temperature" && isIntervalChange()) result = ping() + + if (DEBUG) log.debug "parse result: $result" + return result +} private Map parseCatchAllMessage(String description) { - Map resultMap = [:] - def linkText = getLinkText(device) - //log.debug "Catchall" - def descMap = zigbee.parse(description) - - //check humidity configuration is complete - if (descMap.command == 0x07 && descMap.clusterId == 0x0405){ - def configInterval = 10 - if (interval != null) configInterval = interval - sendEvent(name: 'configuration',value: configInterval, descriptionText: "Configuration Successful") - //setConfig() - log.debug "config complete" - //return resultMap = [name: 'configuration', value: configInterval, descriptionText: "Settings configured successfully"] - } - else if (descMap.command == 0x0001){ - def hexString = "${hex(descMap.data[5])}" + "${hex(descMap.data[4])}" - def intString = Integer.parseInt(hexString, 16) - //log.debug "command: $descMap.command clusterid: $descMap.clusterId $hexString $intString" - - if (descMap.clusterId == 0x0402){ - def value = getTemperature(hexString) - resultMap = getTemperatureResult(value) - } - else if (descMap.clusterId == 0x0405){ - def value = Math.round(new BigDecimal(intString / 100)).toString() - resultMap = getHumidityResult(value) - - } - else return null - } - else return null - - return resultMap -} - -private Map parseReportAttributeMessage(String description) { - def descMap = parseDescriptionAsMap(description) - log.debug "Desc Map: $descMap" - log.debug "Report Attributes" - Map resultMap = [:] - if (descMap.cluster == "0001" && descMap.attrId == "0000") { - resultMap = getBatteryResult(descMap.value) - } - return resultMap + def map = zigbee.parseDescriptionAsMap(description) + + def command = zigbee.convertHexToInt(map.command) + def cluster = ( map.clusterId == null ? zigbee.convertHexToInt(map.cluster) : zigbee.convertHexToInt(map.clusterId) ) + def value = (map.value != null ? zigbee.convertHexToInt(map.value) : null) + + if (DEBUG) log.debug "command: ${command} cluster: ${cluster} value: ${value}" + + //check humidity configuration update is complete + if (command == CONFIGURE_REPORTING_RESPONSE_COMMAND && cluster == zigbee.RELATIVE_HUMIDITY_CLUSTER){ + sendEvent(name: "reportingInterval", value: getReportInterval(), descriptionText: "Configuration Successful") + sendEvent(name: "checkInterval", value: deviceWatchSeconds(), displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + log.debug "config complete ${getReportInterval()}" + } + + if (DEBUG) log.debug "no catchall found" + return null + } -def parseDescriptionAsMap(description) { - (description - "read attr - ").split(",").inject([:]) { map, param -> - def nameAndValue = param.split(":") - map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] +private Map parseReportAttributeMessage(String description) { + def map = zigbee.parseDescriptionAsMap(description) + + def cluster = ( map.cluster != null ? zigbee.convertHexToInt(map.cluster) : null ) + def attribute = ( map.attrId != null ? zigbee.convertHexToInt(map.attrId) : null ) + def value = ( map.value != null ? zigbee.convertHexToInt(map.value) : null ) + + if (cluster == zigbee.POWER_CONFIGURATION_CLUSTER && attribute == MEASURED_VALUE_ATTRIBUTE) { + return getBatteryResult(value) } + + if (DEBUG) log.debug "no read attr found" + return null } -private Map parseCustomMessage(String description) { - Map resultMap = [:] - - log.debug "parseCustom" - if (description?.startsWith('temperature: ')) { +private Map parseSupportedMessage(String description) { + + //temperature + if (description?.startsWith("temperature: ")) { def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale()) - resultMap = getTemperatureResult(value) + return getTemperatureResult(value) } - else if (description?.startsWith('humidity: ')) { + + //humidity + if (description?.startsWith("humidity: ")) { def pct = (description - "humidity: " - "%").trim() - if (pct.isNumber()) { - def value = Math.round(new BigDecimal(pct)).toString() - resultMap = getHumidityResult(value) - } else { - log.error "invalid humidity: ${pct}" - } + if (pct.isNumber()) { + def value = Math.round(new BigDecimal(pct)).toString() + return getHumidityResult(value) + } } - return resultMap -} - -private Map getHumidityResult(value) { - def linkText = getLinkText(device) - def maxHumValue = 0 - def minHumValue = 0 - if (device.currentValue("maxHum") != null) maxHumValue = device.currentValue("maxHum").toInteger() - if (device.currentValue("minHum") != null) minHumValue = device.currentValue("minHum").toInteger() - log.debug "Humidity max: ${maxHumValue} min: ${minHumValue}" - def compare = value.toInteger() - - if (compare > maxHumValue) { - sendEvent(name: 'maxHum', value: value, unit: '%', descriptionText: "${linkText} soil moisture high is ${value}%") - } - else if (((compare < minHumValue) || (minHumValue <= 2)) && (compare != 0)) { - sendEvent(name: 'minHum', value: value, unit: '%', descriptionText: "${linkText} soil moisture low is ${value}%") - } - - return [ - name: 'humidity', - value: value, - unit: '%', - descriptionText: "${linkText} soil moisture is ${value}%" - ] } +//----------------------event values-------------------------------// -def getTemperature(value) { - def celsius = (Integer.parseInt(value, 16).shortValue()/100) - //log.debug "Report Temp $value : $celsius C" - if(getTemperatureScale() == "C"){ - return celsius - } else { - return celsiusToFahrenheit(celsius) as Integer - } +private Map getHumidityResult(value) { + log.debug "Humidity: $value" + def linkText = getLinkText(device) + + return [ + name: "humidity", + value: value, + unit: "%", + descriptionText: "${linkText} soil moisture is ${value}%" + ] } private Map getTemperatureResult(value) { log.debug "Temperature: $value" def linkText = getLinkText(device) - + if (tempOffset) { - value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) + def offset = tempOffset as int + def v = value as int + value = v + offset } def descriptionText = "${linkText} is ${value}°${temperatureScale}" + return [ - name: 'temperature', + name: "temperature", value: value, descriptionText: descriptionText, unit: temperatureScale @@ -270,148 +177,94 @@ private Map getTemperatureResult(value) { } private Map getBatteryResult(value) { - log.debug 'Battery' + log.debug "Battery: $value" def linkText = getLinkText(device) - - def result = [ - name: 'battery' - ] - - def min = 2500 - def percent = ((Integer.parseInt(value, 16) - min) / 5) + + def min = 2500 + def percent = (value - min) / 5 percent = Math.max(0, Math.min(percent, 100.0)) - result.value = Math.round(percent) - - def descriptionText - if (percent < 10) result.descriptionText = "${linkText} battery is getting low $percent %." - else result.descriptionText = "${linkText} battery is ${result.value}%" - - return result -} + value = Math.round(percent) -def resetHumidity(){ - def linkText = getLinkText(device) - def minHumValue = 0 - def maxHumValue = 0 - sendEvent(name: 'minHum', value: minHumValue, unit: '%', descriptionText: "${linkText} min soil moisture reset to ${minHumValue}%") - sendEvent(name: 'maxHum', value: maxHumValue, unit: '%', descriptionText: "${linkText} max soil moisture reset to ${maxHumValue}%") -} - -def setConfig(){ - def configInterval = 100 - if (interval != null) configInterval = interval - sendEvent(name: 'configuration',value: configInterval, descriptionText: "Configuration initialized") + def descriptionText = "${linkText} battery is ${value}%" + if (percent < 10) descriptionText = "${linkText} battery is getting low $percent %." + + return [ + name: "battery", + value: value, + descriptionText: descriptionText + ] } -def installed(){ + +//----------------------configuration-------------------------------// + +def installed() { //check every 62 minutes - sendEvent(name: "checkInterval", value: 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: deviceWatchSeconds(), displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } //when device preferences are changed -def updated(){ - log.debug "device updated" - if (!device.latestValue('configuration')) configure() - else{ - if (resetMinMax == true) resetHumidity() - if (device.latestValue('configuration') as float != interval && interval != null){ - sendEvent(name: 'configuration',value: 0, descriptionText: "Settings changed and will update at next report. Measure interval set to ${interval} mins") - } - } - //check every 62mins or interval + 120s - def reportingInterval = interval * 60 + 2 * 60 - if (reportingInterval < 3720) reportingInterval = 3720 - sendEvent(name: "checkInterval", value: reportingInterval, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +def updated() { + if (DEBUG) log.debug "device updated" + + //set reportingInterval = 0 to trigger update + if (isIntervalChange()) sendEvent(name: "reportingInterval", value: 0, descriptionText: "Settings changed and will update at next report. Measure interval set to ${getReportInterval()} mins") } -//poll -def poll() { - log.debug "poll called" - List cmds = [] - if (!device.latestValue('configuration')) cmds += configure() - else if (device.latestValue('configuration').toInteger() != interval && interval != null) { - cmds += intervalUpdate() - } - //cmds += refresh() - log.debug "commands $cmds" - return cmds?.collect { new physicalgraph.device.HubAction(it) } +//has interval been updated +def isIntervalChange() { + if (DEBUG) log.debug "isIntervalChange ${getReportInterval()} ${device.latestValue("reportingInterval")}" + return (getReportInterval() != device.latestValue("reportingInterval")) } -//update intervals -def intervalUpdate(){ - log.debug "intervalUpdate" - def minReport = 10 - def maxReport = 610 - if (interval != null) { - minReport = interval - maxReport = interval * 61 - } - [ - "zcl global send-me-a-report 0x405 0x0000 0x21 $minReport $maxReport {6400}", "delay 500", - "send 0x${device.deviceNetworkId} 1 1", "delay 500", - "zcl global send-me-a-report 1 0x0000 0x21 0x0C 0 {0500}", "delay 500", - "send 0x${device.deviceNetworkId} 1 1", "delay 500", - ] +//settings default interval +def getReportInterval() { + return (interval != null ? interval : 10) } -def refresh() { - log.debug "refresh" - [ - "st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 500", - "st rattr 0x${device.deviceNetworkId} 1 0x405 0", "delay 500", - "st rattr 0x${device.deviceNetworkId} 1 1 0" - ] +//Device-Watch every 62mins or settings interval + 120s +def deviceWatchSeconds() { + def intervalSeconds = getReportInterval() * 60 + 2 * 60 + if (intervalSeconds < HC_INTERVAL_SECS) intervalSeconds = HC_INTERVAL_SECS + return intervalSeconds +} + +//ping +def ping() { + if (DEBUG) log.debug "device health ping" + + List cmds = [] + if (isIntervalChange()) cmds = reporting() + else cmds = refresh() + + return cmds?.collect { new physicalgraph.device.HubAction(it) } } //configure def configure() { - //set minReport = measurement in minutes - def minReport = 10 - def maxReport = 610 - - //String zigbeeId = swapEndianHex(device.hub.zigbeeId) - //log.debug "zigbeeid ${device.zigbeeId} deviceId ${device.deviceNetworkId}" - if (!device.zigbeeId) sendEvent(name: 'configuration',value: 0, descriptionText: "Device Zigbee Id not found, remove and attempt to rejoin device") - else sendEvent(name: 'configuration',value: 100, descriptionText: "Configuration initialized") - //log.debug "Configuring Reporting and Bindings. min: $minReport max: $maxReport " - - [ - "zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 0x405 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 1000", - - //temperature - "zcl global send-me-a-report 0x402 0x0000 0x29 1 0 {3200}", - "send 0x${device.deviceNetworkId} 1 1", "delay 500", - - //min = soil measure interval - "zcl global send-me-a-report 0x405 0x0000 0x21 $minReport $maxReport {6400}", - "send 0x${device.deviceNetworkId} 1 1", "delay 500", - - //min = battery measure interval 1 = 1 hour - "zcl global send-me-a-report 1 0x0000 0x21 0x0C 0 {0500}", - "send 0x${device.deviceNetworkId} 1 1", "delay 500" - ] + refresh() + return reporting() + refresh() } -private hex(value) { - new BigInteger(Math.round(value).toString()).toString(16) -} +//set reporting +def reporting() { + //set min/max report from interval setting + def minReport = getReportInterval() + def maxReport = getReportInterval() * 61 -private String swapEndianHex(String hex) { - reverseArray(hex.decodeHex()).encodeHex() -} + def reportingCmds = [] + reportingCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 1, 0, 0x01, [destEndpoint: 1]) + reportingCmds += zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, minReport, maxReport, 0x6400, [destEndpoint: 1]) + reportingCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, 0x0C, 0, 0x0500, [destEndpoint: 1]) -private byte[] reverseArray(byte[] array) { - int i = 0; - int j = array.length - 1; - byte tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array + return reportingCmds } + +def refresh() { + log.debug "refresh" + def refreshCmds = [] + refreshCmds += zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, MEASURED_VALUE_ATTRIBUTE, [destEndpoint: 1]) + refreshCmds += zigbee.readAttribute(zigbee.RELATIVE_HUMIDITY_CLUSTER, MEASURED_VALUE_ATTRIBUTE, [destEndpoint: 1]) + refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, MEASURED_VALUE_ATTRIBUTE, [destEndpoint: 1]) + + return refreshCmds +} \ No newline at end of file From a51dfa880487e8913c19d9f2a51ae1843c6d08ad Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Sat, 17 Jul 2021 06:06:21 +0800 Subject: [PATCH 013/184] add eWeLink temp/humi Sensor (#70669) * add eWeLink temp/humi Sensor * Update smartsense-temp-humidity-sensor.groovy change deviceJoinName: "eWeLink Multipurpose Sensor" * Update smartsense-temp-humidity-sensor.groovy Co-authored-by: yu zhou <2217902261@qq.com> --- .../smartsense-temp-humidity-sensor.groovy | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index 2cca97187ed..7e04310670c 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -34,6 +34,9 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0009, 0402", manufacturer: "HEIMAN", model: "HT-EM", deviceJoinName: "HEIMAN Multipurpose Sensor" //HEIMAN Temperature & Humidity Sensor fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0402, 0B05", manufacturer: "HEIMAN", model: "HT-EF-3.0", deviceJoinName: "HEIMAN Multipurpose Sensor" //HEIMAN Temperature & Humidity Sensor fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0020,0402,0405", outClusters: "0003,000A,0019", manufacturer: "frient A/S", model :"HMSZB-110", deviceJoinName: "frient Multipurpose Sensor" // frient Humidity Sensor + + //eWeLink + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0402, 0405", outClusters: "0003", manufacturer: "eWeLink", model: "TH01", deviceJoinName: "eWeLink Multipurpose Sensor" } simulator { @@ -174,6 +177,12 @@ def refresh() { return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)+ zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000)+ zigbee.readAttribute(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000) + } else if (isEWeLinkTh01()) { + return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware + zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware + zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) + + zigbee.readAttribute(0x0405, 0x0000) + + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) } else { return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware @@ -202,6 +211,13 @@ def configure() { zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000, DataType.UINT16, 60, 600, 1*100) + zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 60, 600, 0xA) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020, DataType.UINT8, 30, 21600, 0x1) + } else if (isEWeLinkTh01()) { + return refresh() + + zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) + // New firmware + zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0xC2DF]) + // Original firmware + zigbee.batteryConfig() + + zigbee.temperatureConfig(3600, 7200) + + zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 3600, 7200, null) } else { return refresh() + zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) + // New firmware @@ -214,3 +230,7 @@ def configure() { private Boolean isFrientSensor() { device.getDataValue("manufacturer") == "frient A/S" } + +private Boolean isEWeLinkTh01() { + device.getDataValue("manufacturer") == "eWeLink" && device.getDataValue("model") == "TH01" +} From 3e4dc6d8116a28c9eecc3a1bd3c262c5d7d71b7f Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Sat, 17 Jul 2021 06:19:41 +0800 Subject: [PATCH 014/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug (#69769) * DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug * delete dummy code for pull request review. * 1.Uniform parameter organization; 2.restore codes about checkInterval except parameter offlinePingable. * restore offlinePingable: "1" except dimmer * remove code about lastCheckIn and ignored offlinePingable * delete dummy code as review requested * 1. Syntax format compliance adjustment 2. delete dummy code * Syntax format compliance adjustment * delete capability "Light" Co-authored-by: Winnie Wen --- .../min-smart-plug.src/min-smart-plug.groovy | 390 ++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy diff --git a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy new file mode 100644 index 00000000000..1c07abef3bd --- /dev/null +++ b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy @@ -0,0 +1,390 @@ +/** + * Min Smart Plug v1.0.4 + * + * Models: MINOSTON (MP21Z) + * + * Author: + * winnie (sky-nie) + * + * Documentation: + * + * Changelog: + * + * 1.0.4 (07/13/2021) + * - Syntax format compliance adjustment + * - delete dummy code + * + * 1.0.3 (07/12/2021) + * 1.0.2 (07/07/2021) + * - delete dummy code + * + * 1.0.1 (03/17/2021) + * - Simplify the code, delete dummy code + * + * 1.0.0 (03/11/2021) + * - Initial Release + * + * Reference: + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/eva-logik-in-wall-smart-switch.src/eva-logik-in-wall-smart-switch.groovy + * + * 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: "Min Smart Plug", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-switch", ocfDeviceType: "oic.d.smartplug") { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Configuration" + capability "Refresh" + capability "Health Check" + + attribute "firmwareVersion", "string" + attribute "syncStatus", "string" + + fingerprint mfr: "0312", prod: "C000", model: "C009", deviceJoinName: "Minoston Outlet" // old MP21Z + fingerprint mfr: "0312", prod: "FF00", model: "FF0C", deviceJoinName: "Minoston Outlet" //MP21Z Minoston Mini Smart Plug + } + + preferences { + configParams.each { + if (it.name) { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options:it.options + } + } + } + } +} + +def installed() { + logDebug "installed()..." + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +private static def getCheckInterval() { + // These are battery-powered devices, and it's not very critical + // to know whether they're online or not – 12 hrs + return (60 * 60 * 3) + (5 * 60) +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 5000)) { + state.lastUpdated = new Date().time + + logDebug "updated()..." + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + + runIn(5, executeConfigureCmds, [overwrite: true]) + } + return [] +} + +def configure() { + logDebug "configure()..." + + if (state.resyncAll == null) { + state.resyncAll = true + runIn(8, executeConfigureCmds, [overwrite: true]) + } else { + if (!pendingChanges) { + state.resyncAll = true + } + executeConfigureCmds() + } + return [] +} + +def executeConfigureCmds() { + runIn(6, refreshSyncStatus) + + def cmds = [] + + if (!device.currentValue("switch")) { + cmds << switchBinaryGetCmd() + } + + if (state.resyncAll || !device.currentValue("firmwareVersion")) { + cmds << secureCmd(zwave.versionV1.versionGet()) + } + + configParams.each { param -> + def storedVal = getParamStoredValue(param.num) + def paramVal = param.value + + if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { + logDebug "Changing ${param.name}(#${param.num}) from ${storedVal} to ${paramVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + + state.resyncAll = false + if (cmds) { + sendCommands(delayBetween(cmds, 500)) + } + return [] +} + +def ping() { + logDebug "ping()..." + + return [ switchBinaryGetCmd() ] +} + +def on() { + logDebug "on()..." + + return [ switchBinarySetCmd(0xFF) ] +} + +def off() { + logDebug "off()..." + + return [ switchBinarySetCmd(0x00) ] +} + +def refresh() { + logDebug "refresh()..." + + refreshSyncStatus() + + sendCommands([switchBinaryGetCmd()]) +} + +private sendCommands(cmds) { + if (cmds) { + def actions = [] + cmds.each { + actions << new physicalgraph.device.HubAction(it) + } + sendHubCommand(actions) + } + return [] +} + +private switchBinaryGetCmd() { + return secureCmd(zwave.switchBinaryV1.switchBinaryGet()) +} + +private switchBinarySetCmd(val) { + return secureCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: val)) +} + +private secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s") || ("0x98" in device?.rawDescription?.split(" "))) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + return cmd.format() + } +} + +def parse(String description) { + def result = [] + try { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result += zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + } catch (e) { + log.error "${e}" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + + def result = [] + if (encapsulatedCmd) { + result += zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + logTrace "${cmd}" + + sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) + runIn(4, refreshSyncStatus) + + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + logDebug "${param.name}(#${param.num}) = ${val}" + state["configVal${param.num}"] = val + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logTrace "VersionReport: ${cmd}" + + def subVersion = String.format("%02d", cmd.applicationSubVersion) + def fullVersion = "${cmd.applicationVersion}.${subVersion}" + + sendEvent(name: "firmwareVersion", value: fullVersion) + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + logTrace "${cmd}" + sendSwitchEvents(cmd.value, "physical") + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + logTrace "${cmd}" + sendSwitchEvents(cmd.value, "digital") + return [] +} + +private sendSwitchEvents(rawVal, type) { + sendEvent(name: "switch", value: (rawVal == 0xFF) ? "on" : "off", displayed: true, type: type) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" + return [] +} + +def refreshSyncStatus() { + def changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +private static getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x27: 1, // Switch All + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 + ] +} + +private getPendingChanges() { + return configParams.count { "${it.value}" != "${getParamStoredValue(it.num)}" } +} + +private getParamStoredValue(paramNum) { + return safeToInt(state["configVal${paramNum}"] , null) +} + +private getConfigParams() { + return [ + ledModeParam, + autoOffIntervalParam, + autoOnIntervalParam, + powerFailureRecoveryParam + ] +} + +private getLedModeParam() { + return getParam(1, "LED Indicator Mode", 1, 0, ledModeOptions) +} + +private getAutoOffIntervalParam() { + return getParam(2, "Auto Turn-Off Timer(0, Disabled; 1--60480 minutes)", 4, 0, null, "0..60480") +} + +private getAutoOnIntervalParam() { + return getParam(4, "Auto Turn-On Timer(0, Disabled; 1--60480 minutes)", 4, 0, null, "0..60480") +} + +private getPowerFailureRecoveryParam() { + return getParam(6, "Power Failure Recovery", 1, 0, powerFailureRecoveryOptions) +} + +private getParam(num, name, size, defaultVal, options=null, range=null) { + def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + + def map = [num: num, name: name, size: size, value: val] + if (options) { + map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value + map.options = setDefaultOption(options, defaultVal) + } + if (range) { + map.range = range + } + + return map +} + +private static setDefaultOption(options, defaultVal) { + return options?.collectEntries { k, v -> + if ("${k}" == "${defaultVal}") { + v = "${v} [DEFAULT]" + } + ["$k": "$v"] + } +} + +private static getLedModeOptions() { + return [ + "0":"On When On", + "1":"Off When On", + "2":"Always Off" + ] +} + +private static getPowerFailureRecoveryOptions() { + return [ + "0":"Turn Off", + "1":"Turn On", + "2":"Restore Last State" + ] +} + +private static safeToInt(val, defaultVal=0) { + return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal +} + +private static isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +private logDebug(msg) { + log.debug "$msg" +} + +private logTrace(msg) { + log.trace "$msg" +} \ No newline at end of file From 915ce7c6da1d98c12601293481b787ef13417f64 Mon Sep 17 00:00:00 2001 From: greens Date: Thu, 22 Jul 2021 11:07:33 -0700 Subject: [PATCH 015/184] BUG-3164 Overlapping lock events Lock events for devices for which we delay the sending of lock operation reports that happen too close together will cause incorrect state to temporarily be displayed. Overwriting the scheduled function call responsible for these events should be enough to essentially drop the "bad" event on the floor so it never has a chance to overwrite good state. --- .../zigbee-lock-without-codes.groovy | 2 +- devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy | 2 +- devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index 1844303ae48..36626a03291 100644 --- 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 @@ -213,7 +213,7 @@ private def parseAttributeResponse(String description) { with less info will be marked as not displayed */ log.debug "Lock attribute report received: ${responseMap.value}. Delaying event." - runIn(1, "delayLockEvent", [data : [map : responseMap]]) + runIn(1, "delayLockEvent", [overwrite: true, forceForLocallyExecuting: true, data: [map: responseMap]]) return [:] } } else { diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index cb71cefc23f..45cf8378873 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -506,7 +506,7 @@ private def parseAttributeResponse(String description) { with less info will be marked as not displayed */ log.debug "Lock attribute report received: ${responseMap.value}. Delaying event." - runIn(1, "delayLockEvent", [data : [map : responseMap]]) + runIn(1, "delayLockEvent", [overwrite: true, forceForLocallyExecuting: true, data: [map: responseMap]]) return [:] } } else if (clusterInt == CLUSTER_DOORLOCK && attrInt == DOORLOCK_ATTR_MIN_PIN_LENGTH && descMap.value) { diff --git a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy index 3a17e4763cb..4b654e85bbc 100644 --- a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy +++ b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy @@ -380,7 +380,7 @@ def zwaveEvent(DoorLockOperationReport cmd) { } if (generatesDoorLockOperationReportBeforeAlarmReport()) { // we're expecting lock events to come after notification events, but for specific yale locks they come out of order - runIn(3, "delayLockEvent", [data: [map: map]]) + runIn(3, "delayLockEvent", [overwrite: true, forceForLocallyExecuting: true, data: [map: map]]) return [:] } else { return result ? [createEvent(map), *result] : createEvent(map) From 8eabbad64ef7bcec1c2318d78ca74a6965df2eff Mon Sep 17 00:00:00 2001 From: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Date: Fri, 23 Jul 2021 22:30:51 +0200 Subject: [PATCH 016/184] [ICP-14234] Zigbee Window Shade - included lastLevel in methods scope as local variable (#69361) * Included lastLevel in methods scope as local variable * lastLevel -> priorLevel --- .../zigbee-window-shade.src/zigbee-window-shade.groovy | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 560d31ad23c..6bb2b707b3a 100755 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -132,9 +132,10 @@ def getLastLevel() { } def levelEventHandler(currentLevel) { - log.debug "levelEventHandle - currentLevel: ${currentLevel} lastLevel: ${lastLevel}" + def priorLevel = lastLevel + log.debug "levelEventHandle - currentLevel: ${currentLevel} priorLevel: ${priorLevel}" - if ((lastLevel == "undefined" || currentLevel == lastLevel) && state.invalidSameLevelEvent) { //Ignore invalid reports + if ((priorLevel == "undefined" || currentLevel == priorLevel) && state.invalidSameLevelEvent) { //Ignore invalid reports log.debug "Ignore invalid reports" } else { state.invalidSameLevelEvent = true @@ -145,9 +146,9 @@ def levelEventHandler(currentLevel) { if (currentLevel == 0 || currentLevel == 100) { sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") } else { - if (lastLevel < currentLevel) { + if (priorLevel < currentLevel) { sendEvent([name:"windowShade", value: "opening"]) - } else if (lastLevel > currentLevel) { + } else if (priorLevel > currentLevel) { sendEvent([name:"windowShade", value: "closing"]) } runIn(1, "updateFinalState", [overwrite:true]) From 088f6c714c13e0bd5599b4527dc341c52b537946 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Fri, 23 Jul 2021 16:24:56 -0700 Subject: [PATCH 017/184] DevWs for Smartenit, Inc containing containing Smartenit Zigbee MLC30 (#70915) * DevWs for Smartenit, Inc containing containing Smartenit Zigbee MLC30 * Removed events from commands, device name changed to Smartenit Switch, parse modifications * Parsing function return adjustments * Added null check for event --- ...tenit-metering-dual-load-controller.groovy | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy diff --git a/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy b/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy new file mode 100644 index 00000000000..b78e67d6099 --- /dev/null +++ b/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy @@ -0,0 +1,177 @@ +/** + * MLC30 + * + * Copyright 2021 Luis Contreras + * + * 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 groovy.transform.Field + import physicalgraph.zigbee.zcl.DataType + + @Field final CurrentLevel = 0x0000 + @Field final MoveToLevelWOnOff = 0x0004 + @Field final MeteringCurrentSummation = 0x0000 + @Field final MeteringInstantDemand = 0x0400 + @Field final EnergyDivisor = 100000 + @Field final CurrentDivisor = 100 + @Field final Current = 0x00f0 + @Field final Voltage = 0x00f1 + @Field final OnOff = 0x0000 + @Field final SmartenitMfrCode = 0x1075 + +metadata { + definition (name: "Smartenit Metering Dual Load Controller", namespace: "Smartenit", author: "Luis Contreras", mnmn: "SmartThingsCommunity", vid: "472dac67-bbdd-344e-944b-43abafeeb82b") { + capability "Actuator" + capability "Configuration" + capability "Refresh" + capability "Power Meter" + capability "Energy Meter" + capability "Health Check" + capability "Voltage Measurement" + capability "monthpublic25501.current" + capability "monthpublic25501.load1" + capability "monthpublic25501.load2" + capability "monthpublic25501.levelControl" + + fingerprint model: "ZBMLC30NC", manufacturer: "Smartenit, Inc", deviceJoinName: "Smartenit Switch" + fingerprint model: "ZBMLC30NO", manufacturer: "Smartenit, Inc", deviceJoinName: "Smartenit Switch" + } +} + +def getFPoint(String FPointHex){ + return (Float)Long.parseLong(FPointHex, 16) +} + +// Parse incoming device messages to generate events +def parse(String description) { + log.debug "Basic description: ${description}" + def event = zigbee.getEvent(description) + Map eventDescMap = zigbee.parseDescriptionAsMap(description) + + if (description?.startsWith("on/off")) { + def cmds = zigbee.readAttribute(zigbee.ONOFF_CLUSTER, OnOff) + zigbee.readAttribute(zigbee.ONOFF_CLUSTER, OnOff, [destEndpoint: 2]) + return cmds.collect { new physicalgraph.device.HubAction(it) } + } + + if (event && event.name != "switch") { + log.debug "Collecting event: ${event}, ${event.name}, ${event.value}" + if ((eventDescMap?.sourceEndpoint == "01") || (eventDescMap?.endpoint == "01")) { + if (event.name == "power") { + return createEvent(name: "power", value: (event.value/EnergyDivisor)) + } else { + return createEvent(event) + } + } else if ((eventDescMap?.sourceEndpoint == "03") || (eventDescMap?.endpoint == "03")) { + if (event.name == "level") { + log.debug "Creating level event" + return createEvent(name: "level", value: event.value) + } + } + } else { + def mapDescription = zigbee.parseDescriptionAsMap(description) + log.debug "mapDescription... : ${mapDescription}" + + if (mapDescription) { + if (mapDescription.clusterInt == zigbee.SIMPLE_METERING_CLUSTER) { + if (mapDescription.attrInt == MeteringCurrentSummation) { + return createEvent(name:"energy", value: getFPoint(mapDescription.value)/EnergyDivisor) + } else if (mapDescription.attrInt == MeteringInstantDemand) { + return createEvent(name:"power", value: getFPoint(mapDescription.value/EnergyDivisor)) + } else if (mapDescription.attrInt == Voltage) { + return createEvent(name:"voltage", value: getFPoint(mapDescription.value) / 100) + } else if (mapDescription.attrInt == Current) { + return createEvent(name:"current", value: getFPoint(mapDescription.value) / 100, unit: "A") + } + } else if (mapDescription.clusterInt == zigbee.ONOFF_CLUSTER) { + if (mapDescription.attrInt == OnOff) { + def nameVal = mapDescription.sourceEndpoint == "01" ? "loadone" : "loadtwo" + def status = mapDescription.value == "00" ? "off" : "on" + return createEvent(name:nameVal, value: status) + } else if (event) { + return createEvent(event) + } + } else if (mapDescription.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER) { + if (mapDescription.attrInt == CurrentLevel) { + log.debug "Received response for level control: ${eventDescMap?.value}" + long convertedValue = Long.parseLong(eventDescMap?.value, 16) + def ceilingVal = Math.ceil((convertedValue * 100) / 255.0 ) + return createEvent(name: "level", value: ceilingVal) + } + } + } + } +} + +def setLevel(val) { + log.debug "Setting level to ${val}" + int newval = 0 + if (val != 0) { + newval = (255.0 / (100.0 / val)) + } + + zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, MoveToLevelWOnOff, + DataType.pack(newval, DataType.UINT8, 1) + DataType.pack(0xffff, DataType.UINT16, 1), [destEndpoint: 3]) +} + +def setLoadone(val) { + log.debug "toggling load one to: ${val}" + + if (val == "on") { + zigbee.on() + } else if (val == "off") { + zigbee.off() + } +} + +def setLoadtwo(val) { + log.debug "Setting load two to: ${val}" + + if (val == "on") { + zigbee.command(zigbee.ONOFF_CLUSTER, 0x01, "", [destEndpoint: 2]) + } else if (val == "off") { + zigbee.command(zigbee.ONOFF_CLUSTER, 0x00, "", [destEndpoint: 2]) + } +} + +def refresh() { + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation) + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand) + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, Voltage, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, Current, [mfgCode: SmartenitMfrCode]) + + zigbee.readAttribute(zigbee.ONOFF_CLUSTER, OnOff) + + zigbee.readAttribute(zigbee.ONOFF_CLUSTER, OnOff, [destEndpoint: 2]) + + zigbee.readAttribute(zigbee.LEVEL_CONTROL_CLUSTER, CurrentLevel, [destEndpoint: 3]) +} + +def configure() { + log.debug "in configure()" + configureHealthCheck() + return (zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation, 0x25, 0, 600, 50) + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand, 0x2a, 0, 600, 50) + + zigbee.configureReporting(zigbee.ONOFF_CLUSTER, OnOff, 0x10, 0, 120, null, [destEndpoint: 1]) + + zigbee.configureReporting(zigbee.ONOFF_CLUSTER, OnOff, 0x10, 0, 120, null, [destEndpoint: 2]) + + refresh() + ) +} + +def configureHealthCheck() { + Integer hcIntervalMinutes = 10 + sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} + +def updated() { + log.debug "in updated()" + configureHealthCheck() +} + +def ping() { + return zigbee.readAttribute(zigbee.ONOFF_CLUSTER, ONOFF_ATTRIBUTE) + zigbee.readAttribute(zigbee.ONOFF_CLUSTER, OnOff, [destEndpoint: 2]) +} \ No newline at end of file From b524112b6a4f937038a7e7c928b25436ccfd4fda Mon Sep 17 00:00:00 2001 From: shingchen <85251891+shingchen@users.noreply.github.com> Date: Tue, 27 Jul 2021 16:15:00 -0700 Subject: [PATCH 018/184] DevWs for Ecolink Intelligent Technology containing containing Ecolink Chime+Siren (#67570) * DevWs for Ecolink Intelligent Technology containing containing Ecolink Chime+Siren * * 1.0 (07/15/2021) * - Initial Release * * 1.0.1 (07/25/2021) * - Changes requested by ST --- .../ecolink-chime-siren.groovy | 693 ++++++++++++++++++ 1 file changed, 693 insertions(+) create mode 100644 devicetypes/krlaframboise/ecolink-chime-siren.src/ecolink-chime-siren.groovy diff --git a/devicetypes/krlaframboise/ecolink-chime-siren.src/ecolink-chime-siren.groovy b/devicetypes/krlaframboise/ecolink-chime-siren.src/ecolink-chime-siren.groovy new file mode 100644 index 00000000000..ea59cd15d3a --- /dev/null +++ b/devicetypes/krlaframboise/ecolink-chime-siren.src/ecolink-chime-siren.groovy @@ -0,0 +1,693 @@ +/* + * Ecolink Chime+Siren v1.0.1 + * + * Changelog: + * + * 1.0.1 (07/25/2021) + * - Changes requested by ST + * + * 1.0 (07/15/2021) + * - Initial Release + * + * + * Copyright 2021 Ecolink + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x71: 3, // Notification v4 + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x79: 1, // Sound Switch + 0x7A: 2, // FirmwareUpdateMd + 0x80: 1, // Battery + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x87: 3, // Indicator + 0x8E: 2, // Multi Channel Association + 0x9F: 1 // Security S2 +] + +@Field static List sounds = [ + [number:1, name:"1. One long beep"], + [number:2, name:"2. Two beeps"], + [number:3, name:"3. E1 Beep"], + [number:4, name:"4. Tinker"], + [number:5, name:"5. Droplet"], + [number:6, name:"6. Rain"], + [number:7, name:"7. Marimba"], + [number:8, name:"8. Water dew"], + [number:9, name:"9. Phone"], + [number:10, name:"10. Pong"], + [number:11, name:"11. Error Sound"], + [number:12, name:"12. Chirp"], + [number:13, name:"13. Alarm Siren", type:"siren"], + [number:14, name:"14. Exit Delay", type:"siren"], + [number:15, name:"15. Entry Delay", type:"siren"], + [number:16, name:"16. Smoke Alarm", type:"siren"], + [number:17, name:"17. CO Alarm", type:"siren"], + [number:18, name:"18. Armed Away"], + [number:19, name:"19. Armed Stay"], + [number:20, name:"20. Disarmed"], + [number:21, name:"21. Front Door"], + [number:22, name:"22. Side Door"], + [number:23, name:"23. Back Door"], + [number:24, name:"24. Garage Door"], + [number:25, name:"25. Alarm Siren 2", type:"siren"], + [number:26, name:"26. Alarm Siren 3", type:"siren"], + [number:27, name:"27. Traditional Marimba"], + [number:28, name:"28. Westminster Piano"], + [number:29, name:"29. Forest"], + [number:30, name:"30. Garden Strings"], + [number:126, name:"Entry/Exit Delay (15 Seconds)", indicatorID:0x16], + [number:127, name:"Entry/Exit Delay (30 Seconds)", indicatorID:0x26], + [number:128, name:"Entry/Exit Delay (45 Seconds)", indicatorID:0x36], + [number:129, name:"Entry/Exit Delay (255 Seconds)", indicatorID:0xF6] +] + +@Field static int powerManagement = 8 +@Field static int powerDisconnected = 2 +@Field static int powerReconnected = 3 +@Field static int batteryCharging = 12 +@Field static int batteryFullyCharged = 13 +@Field static int chargeBatterySoon = 14 +@Field static int chargeBatteryNow = 15 +@Field static int batteryStatusDischarging = 0 +@Field static int batteryStatusCharging = 1 +@Field static int batteryStatusMaintaining = 2 +@Field static String batteryCC = "80" +@Field static String soundSwitchCC = "79" +@Field static String soundSwitchConfigurationSet = "7905" +@Field static String soundSwitchConfigurationGet = "7906" +@Field static String soundSwitchConfigurationReport = "7907" +@Field static String soundSwitchTonePlaySet = "7908" +@Field static String soundSwitchTonePlayGet = "7909" +@Field static String soundSwitchTonePlayReport = "790A" + + +metadata { + definition ( + name: "Ecolink Chime+Siren", + namespace: "krlaframboise", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "x.com.st.d.siren", + mnmn: "SmartThingsCommunity", + vid: "02a8f57f-6c7b-37f9-86c8-4705bf4faa6f" + ) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "platemusic11009.soundVolume" + capability "platemusic11009.ecoPlaySoundNumber" + capability "platemusic11009.ecoSirenSound" + capability "platemusic11009.sirenVolume" + capability "Alarm" + capability "platemusic11009.ecoChimeSound" + capability "platemusic11009.chimeVolume" + capability "Chime" + capability "Power Source" + capability "Battery" + capability "Refresh" + capability "Configuration" + capability "Health Check" + capability "platemusic11009.firmware" + + fingerprint mfr:"014A", prod:"0007", model: "3975", deviceJoinName:"Ecolink Chime+Siren" // zw:L type:0301 mfr:014A prod:0007 model:3975 ver:2.04 zwv:7.13 lib:03 cc:5E,85,59,80,70,5A,7A,87,72,8E,71,73,98,9F,79,6C,55,86 + } + + preferences { + [heartBeatParam, supervisionParam].each { param -> + if (param.options) { + input "configParam${param.num}", "enum", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input "configParam${param.num}", "number", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + + input "debugOutput", "enum", + title: "Enable Debug Logging?", + required: false, + displayDuringSetup: false, + defaultValue: 1, + options: [0:"No", 1:"Yes [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + + initialize() +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 2000)) { + state.lastUpdated = new Date().time + + logDebug "updated()..." + + initialize() + + runIn(2, executeConfigureCmds) + } +} + +void initialize() { + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((60 * 60) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + sendInitEvent("activeSoundNumber", 0) + sendInitEvent("soundVolume", 25, "%") + sendInitEvent("chimeSound", "1") + sendInitEvent("chimeVolume", 50, "%") + sendInitEvent("sirenSound", "13") + sendInitEvent("sirenVolume", 100, "%") + + state.debugLoggingEnabled = (safeToInt(settings?.debugOutput, 1) != 0) +} + +void sendInitEvent(String name, value, String unit="") { + if (device.currentValue(name) == null) { + sendEventIfNew(name, value, unit) + } +} + +def configure() { + logDebug "configure()..." + + executeConfigureCmds() + + runIn(15, refresh) +} + +void executeConfigureCmds() { + List cmds = [] + + if (!device.currentValue("battery")) { + cmds << batteryGetCmd() + } + + if (!device.currentValue("switch")) { + cmds << soundSwitchTonePlayGetCmd() + } + + configParams.each { param -> + if (param.value != null) { + Integer storedVal = getParamStoredValue(param.num) + if (storedVal != param.value) { + logDebug "Changing ${param.name}(#${param.num}) from ${storedVal} to ${param.value}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: param.value)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + } + sendCommands(cmds) +} + +def ping() { + logDebug "ping()..." + return [ batteryGetCmd() ] +} + +def setChimeVolume(chimeVolume) { + sendEventIfNew("chimeVolume", chimeVolume, "%") +} + +def setChimeSound(chimeSound) { + sendEventIfNew("chimeSound", chimeSound) +} + +def chime() { + logDebug "chime()..." + + int volume = safeToInt(device.currentValue("chimeVolume"), 50) + int sound = safeToInt(device.currentValue("chimeSound"), 1) + + state.pendingAction = "chime" + playSoundAtVolume(sound, volume) +} + +def setSoundVolume(soundVolume) { + sendEventIfNew("soundVolume", soundVolume, "%") +} + +def playSound(soundNumber) { + logDebug "playSound(${soundNumber})..." + + int volume = safeToInt(device.currentValue("soundVolume"), 25) + int sound = safeToInt(soundNumber, 1) + + state.pendingAction = soundNumber + playSoundAtVolume(sound, volume) +} + +def setSirenVolume(sirenVolume) { + sendEventIfNew("sirenVolume", sirenVolume, "%") +} + +def setSirenSound(sirenSound) { + sendEventIfNew("sirenSound", sirenSound) +} + +def both() { + siren() +} + +def strobe() { + siren() +} + +def siren() { + logDebug "siren()..." + + int volume = safeToInt(device.currentValue("sirenVolume"), 100) + int sound = safeToInt(device.currentValue("sirenSound"), 13) + + state.pendingAction = "siren" + playSoundAtVolume(sound, volume) +} + +void playSoundAtVolume(soundNumber, volume) { + logDebug "playSoundAtVolume(${soundNumber}, ${volume})..." + + Map sound = getSound(soundNumber) + state.lastSound = sound + + logDebug "Playing '${sound.name}' at ${volume}%..." + + List cmds = [ + soundSwitchConfigSetCmd(volume, 1) + ] + + if (sound.indicatorID) { + cmds << secureCmd(zwave.indicatorV1.indicatorSet(value: sound.indicatorID)) + } else { + cmds << soundSwitchTonePlaySetCmd(soundNumber) + } + + cmds << soundSwitchTonePlayGetCmd() + + sendCommands(cmds, 100) +} + +def on() { + chime() +} + +def off() { + logDebug "off()..." + return delayBetween([ + soundSwitchTonePlaySetCmd(0), + soundSwitchTonePlayGetCmd() + ]) +} + +def refresh() { + logDebug "refresh()..." + sendCommands([ + batteryGetCmd(), + secureCmd(zwave.versionV1.versionGet()), + soundSwitchTonePlayGetCmd() + ]) +} + +void sendCommands(List cmds, Integer delay=1000) { + if (cmds) { + def actions = [] + cmds.each { + actions << new physicalgraph.device.HubAction(it) + } + sendHubCommand(actions, delay) + } +} + +String batteryGetCmd() { + return secureCmd(zwave.batteryV1.batteryGet()) +} + +String secureCmd(cmd) { + if (isSecurityEnabled()) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +String soundSwitchConfigSetCmd(int volume, int tone) { + return soundSwitchCmd("${soundSwitchConfigurationSet}${intToHex(volume)}${intToHex(tone)}") +} + +String soundSwitchConfigGetCmd() { + return soundSwitchCmd(soundSwitchConfigurationGet) +} + +String soundSwitchTonePlaySetCmd(int tone) { + return soundSwitchCmd("${soundSwitchTonePlaySet}${intToHex(tone)}") +} + +String soundSwitchTonePlayGetCmd() { + return soundSwitchCmd(soundSwitchTonePlayGet) +} + +String soundSwitchCmd(cmd) { + if (isSecurityEnabled()) { + return "988100${cmd}" + } else { + return cmd + } +} + +boolean isSecurityEnabled() { + return zwaveInfo?.zw?.contains("s") +} + +def parse(String description) { + if ("${description}".contains("command: 9881, payload: 00 ${soundSwitchCC}") || "${description}".contains("command: ${soundSwitchCC}")) { + // SOUND SWITCH NOT SUPPORTED BY SMARTTHINGS + handleSoundSwitchEvent(description) + } else if ("${description}".contains("command: 9881, payload: 00 ${batteryCC}") || "${description}".contains("command: ${batteryCC}")) { + // BATTERY V2 NOT SUPPORTED BY SMARTTHINGS + handleBatteryReport(description) + } else { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + Map param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + Integer val = cmd.scaledConfigurationValue + logDebug "${param.name}(#${param.num}) = ${val}" + setParamStoredValue(param.num, val) + } + else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + sendEventIfNew("firmwareVersion", (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + sendEventIfNew("switch", (cmd.value ? "on" : "off")) +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationType == powerManagement) { + String powerSource = null + switch (cmd.event) { + case powerDisconnected: + logDebug "AC Mains Disconnected" + powerSource = "battery" + break + case powerReconnected: + logDebug "AC Mains Re-Connected" + powerSource = "mains" + break + case batteryCharging: + logDebug "Battery is charging" + break + case batteryFullyCharged: + logDebug "battery is fully charged" + break + case chargeBatterySoon: + logDebug "charge battery soon" + break + case chargeBatteryNow: + logDebug "charge battery now" + break + default: + logDebug "Unknown Power Management Event: ${cmd}" + } + if (powerSource) { + sendEventIfNew("powerSource", powerSource) + } + } else { + logDebug "Unknown notificationType: ${cmd}" + } +} + +void handleBatteryReport(String description) { + // BATTERY V2 NOT SUPPORTED BY SMARTTHINGS + + // The handler can't rely on the Power Management Notification Reports to determine the power source because of a firmware issue that occurs when the device is plugged back in after the battery gets low. + + Map cmd = parseCommand(description) + if (cmd?.payloadBytes?.size() >= 2) { + + int value = hexToInt(cmd.payloadBytes[0]) + + sendEvent(getEventMap("battery", (value == 0xFF ? 1 : value), "%")) + + try { + String powerSource = null + + int chargingStatus = Integer.parseInt(Integer.toBinaryString(hexToInt(cmd.payloadBytes[1])).padLeft(8, "0").substring(0, 2), 2) + + switch (chargingStatus) { + case batteryStatusDischarging: + powerSource = "battery" + break + case batteryStatusCharging: + powerSource = "mains" + break + case batteryStatusMaintaining: + powerSource = "mains" + break + } + + if (powerSource) { + sendEventIfNew("powerSource", powerSource) + } + } catch (ex) { + log.warn "Unable to parse battery charging status from ${description}" + } + } +} + +void handleSoundSwitchEvent(String description) { + // SOUND SWITCH CC NOT SUPPORTED BY SMARTTHINGS + Map cmd = parseCommand(description) + + switch (cmd?.command) { + case soundSwitchConfigurationReport: + handleSoundSwitchConfigurationReport(cmd.payloadBytes) + break + case soundSwitchTonePlayReport: + handleSoundSwitchTonePlayReport(cmd.payloadBytes) + break + default: + logDebug "Unknown Sound Switch Command: ${description}" + } +} + +void handleSoundSwitchConfigurationReport(List payloadBytes) { + if (payloadBytes?.size() == 2) { + int volume = hexToInt(payloadBytes[0]) + int tone = hexToInt(payloadBytes[1]) + logDebug "Tone: ${tone} - Volume: ${volume}" + } else { + log.warn "Sound Switch Configuration Report: Unexpected Payload '${payloadBytes}'" + } +} + +void handleSoundSwitchTonePlayReport(List payloadBytes) { + if (payloadBytes?.size() == 1) { + int soundNumber = hexToInt(payloadBytes[0]) + if (soundNumber) { + + Map sound = state.lastSound + if ((sound?.number != soundNumber) && !sound?.indicatorID) { + sound = getSound(soundNumber) + state.lastSound = sound + } else { + logDebug "Active Sound Number: ${soundNumber}" + } + + sendEventIfNew("switch", "on") + + switch (state.pendingAction) { + case "siren": + sendEventIfNew("alarm", "siren") + break + case "chime": + sendEventIfNew("chime", "chime") + break + default: + sendEvent(getEventMap("activeSoundNumber", soundNumber)) + } + state.pendingAction = null + } else { + if ("${state.pendingAction}".isNumber()) { + // Workaround for timeout error the mobile app throws when a user attempts to play an unsupported sound #. This workaround wouldn't be necessary if the device followed the z-wave specs and played the default sound. + log.warn "Sound #${state.pendingAction} Doesn't Exist" + sendEvent(getEventMap("activeSoundNumber", safeToInt(state.pendingAction))) + state.pendingAction = null + } + + sendEventIfNew("switch", "off") + sendEventIfNew("alarm", "off") + sendEventIfNew("chime", "off") + sendEventIfNew("activeSoundNumber", 0) + } + } else { + log.warn "Sound Switch Tone Play Report: Unexpected Payload '${payloadBytes}'" + } +} + +Map parseCommand(String description) { + Map cmd = description.split(", ").collectEntries { entry -> + def pair = entry.split(": ") + [(pair.first()): pair.last()] + } + + List payloadBytes = null + if (cmd?.payload) { + payloadBytes = cmd.payload.split(" ") + } + + cmd.payloadBytes = payloadBytes + return cmd +} + +Map getSound(int soundNumber) { + Map sound = sounds.find { it.number == soundNumber } + if (!sound) { + sound = [number: soundNumber, name:"${soundNumber}. Custom"] + } + return sound +} + +Integer getParamStoredValue(Integer paramNum) { + return safeToInt(state["configVal${paramNum}"] , null) +} + +void setParamStoredValue(Integer paramNum, Integer value) { + state["configVal${paramNum}"] = value +} + +List getConfigParams() { + return [ + heartBeatParam, + supervisionParam, + emergencySoundVolumeParam + ] +} + +Map getHeartBeatParam() { + return getParam(2, "Heartbeat Notification Timing (seconds)", 4, 3600, null, "120..86400") // seconds +} + +Map getSupervisionParam() { + return getParam(3, "Supervision Encapsulation", 1, 1, [0:"Disabled", 1:"Enabled [DEFAULT]"]) +} + +Map getEmergencySoundVolumeParam() { + return getParam(6, "Emergency Sound Volume Adjustable", 1, 1, [0:"Disabled", 1:"Enabled [DEFAULT]"]) +} + +Map getParam(Integer num, String name, Integer size, Integer defaultVal, Map options, range=null) { + Integer val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + + return [num: num, name: name, size: size, value: val, options: options, range: range, defaultVal: defaultVal] +} + +void sendEventIfNew(String name, value, String unit="") { + if (device.currentValue(name) != value) { + sendEvent(getEventMap(name, value, unit)) + } +} + +Map getEventMap(String name, value, String unit="") { + Map event = [ + name: name, + value: value, + displayed: true, + isStateChange: true, + descriptionText: "${name} is ${value}${unit}" + ] + if (unit) { + event.unit = unit + } + logDebug(event.descriptionText) + return event +} + +String intToHex(int value) { + return Integer.toHexString(value).padLeft(2, "0").toUpperCase() +} + +Integer hexToInt(String value) { + return Integer.parseInt(value, 16) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +boolean isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From d798a888ae58cef9b207ada2ec9452d52b5bc6c9 Mon Sep 17 00:00:00 2001 From: dbradmit Date: Thu, 29 Jul 2021 18:20:04 -0700 Subject: [PATCH 019/184] Setting ocfDeviceType to correct icon discrepancy. --- .../child-switch-health-power.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/child-switch-health-power.src/child-switch-health-power.groovy b/devicetypes/smartthings/child-switch-health-power.src/child-switch-health-power.groovy index 5da65abc46b..16d37fa0db3 100644 --- a/devicetypes/smartthings/child-switch-health-power.src/child-switch-health-power.groovy +++ b/devicetypes/smartthings/child-switch-health-power.src/child-switch-health-power.groovy @@ -12,7 +12,7 @@ * */ metadata { - definition(name: "Child Switch Health Power", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-switch-power") { + definition(name: "Child Switch Health Power", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.smartplug", mnmn: "SmartThings", vid: "generic-switch-power") { capability "Switch" capability "Actuator" capability "Sensor" From 4ae07ba1c92a88a26c99604c4c4f868c2e27492d Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 3 Aug 2021 05:36:19 +0800 Subject: [PATCH 020/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer (#69768) * DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer * delete dummy code for pull request. * 1.Uniform parameter organization; 2.restore codes about checkInterval except parameter offlinePingable. * change code as reviewer request. * 1.Syntax format compliance adjustment 2.delete dummy code * Syntax format compliance adjustment * 1.Syntax format compliance adjustment 2.Adjust the preferences interface prompts for SmartTings App 3.Simplify the process of calling sendHubCommand * fix a bug about sendHubCommand * fix a bug about temperature report threshold sync. * Syntax format compliance adjustment * 1. remove code about "Temperature Measurement" for release's product. 2. change "auto off interval" and "auto on interval" 's range for release's product. * add a fingerprint for a new device Co-authored-by: Winnie Wen --- .../min-smart-plug-dimmer.groovy | 451 ++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy new file mode 100644 index 00000000000..f17e80c487b --- /dev/null +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -0,0 +1,451 @@ +/** + * Min Smart Plug Dimmer v1.1.9 + * + * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) + * + * Author: + * winnie (sky-nie) + * + * Documentation: + * + * Changelog: + * + * 1.1.9 (07/29/2021) + * - add a fingerprint for a new device + * + * 1.1.8 (07/22/2021) + * - remove code about "Temperature Measurement" as beta product. + * - change "auto off interval" and "auto on interval" 's range + * + * 1.1.7 (07/22/2021) + * - fix a bug about temperature report threshold sync. + * + * 1.1.6 (07/13/2021) + * - Syntax format compliance adjustment + * - Adjust the preferences interface prompts for SmartTings App + * - Simplify the process of calling sendHubCommand + * + * 1.1.5 (07/13/2021) + * - Syntax format compliance adjustment + * - delete dummy code + * + * 1.1.4 (07/12/2021) + * 1.1.3 (07/07/2021) + * - delete dummy code + * + * 1.1.2 (06/30/2021) + * - Add new product supported + * + * 1.1.1 (05/06/2021) + * - 1.Solve the problem that the temperature cannot be displayed normally + * - 2.Synchronize some of the latest processing methods, refer to Minoston Door/Window Sensor + * + * 1.0.1 (03/17/2021) + * - Simplify the code, delete dummy code + * + * 1.0.0 (03/11/2021) + * - Initial Release + * + * Reference: + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/eva-logik-in-wall-smart-dimmer.src/eva-logik-in-wall-smart-dimmer.groovy + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/aeotec-trisensor.src/aeotec-trisensor.groovy + * + * 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: "Min Smart Plug Dimmer", namespace: "sky-nie", author: "winnie", ocfDeviceType: "oic.d.smartplug") { + capability "Actuator" + capability "Switch" + capability "Switch Level" + capability "Configuration" + capability "Refresh" + + attribute "firmwareVersion", "string" + attribute "lastCheckIn", "string" + attribute "syncStatus", "string" + + fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Dimmer Switch" //MP21ZD + fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Dimmer Switch" //MP22ZD + fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "Minoston Dimmer Switch" //N4002 + } + + preferences { + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options + } + } + } +} + +def installed() { + logDebug "installed()..." + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + state.refreshConfig = true +} + +private static def getCheckInterval() { + // These are battery-powered devices, and it's not very critical + // to know whether they're online or not – 12 hrs + return (60 * 60 * 3) + (5 * 60) +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 5000)) { + state.lastUpdated = new Date().time + + logDebug "updated()..." + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + + runIn(5, executeConfigureCmds, [overwrite: true]) + } + + return [] +} + +def configure() { + logDebug "configure()..." + + if (state.resyncAll == null) { + state.resyncAll = true + runIn(8, executeConfigureCmds, [overwrite: true]) + } else { + if (!pendingChanges) { + state.resyncAll = true + } + executeConfigureCmds() + } + return [] +} + +def executeConfigureCmds() { + runIn(6, refreshSyncStatus) + + def cmds = [] + + configParams.each { param -> + def storedVal = getParamStoredValue(param.num) + def paramVal = param.value + if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + + state.resyncAll = false + if (cmds) { + sendHubCommand(cmds, 500) + } + return [] +} + +def parse(String description) { + def result = [] + try { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result += zwaveEvent(cmd) + } else { + logDebug "Unable to parse description: $description" + } + + sendEvent(name: "lastCheckIn", value: convertToLocalTimeString(new Date()), displayed: false) + } catch (e) { + log.error "$e" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapCmd = cmd.encapsulatedCommand(commandClassVersions) + + def result = [] + if (encapCmd) { + result += zwaveEvent(encapCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + logTrace "ConfigurationReport ${cmd}" + + sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) + runIn(4, refreshSyncStatus) + + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + + logDebug "${param.name}(#${param.num}) = ${val}" + state["configParam${param.num}"] = val + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.configurationValue}" + } + return [] +} + +def refreshSyncStatus() { + def changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Ignored Command: $cmd" + return [] +} + +private secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s") || ("0x98" in device?.rawDescription?.split(" "))) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + log.error("caught exception", ex) + } +} + +private static getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x26: 3, // Switch Multilevel + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x71: 3, // Notification + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 + ] +} + +private getPendingChanges() { + return configParams.count { "${it.value}" != "${getParamStoredValue(it.num)}" } +} + +private getParamStoredValue(paramNum) { + return safeToInt(state["configParam${paramNum}"] , null) +} + +// Configuration Parameters +private getConfigParams() { + [ + ledModeParam, + autoOffIntervalParam, + autoOnIntervalParam, + nightLightParam, + powerFailureRecoveryParam, + pushDimmingDurationParam, + holdDimmingDurationParam, + minimumBrightnessParam, + maximumBrightnessParam + ] +} + +private getLedModeParam() { + return getParam(2, "LED Indicator Mode", 1, 0, ledModeOptions) +} + +private getAutoOffIntervalParam() { + return getParam(4, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getAutoOnIntervalParam() { + return getParam(6, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getNightLightParam() { + return getParam(7, "Night Light Settings(1 - 10:10% - 100%)", 1, 2, null, "1..10") +} + +private getPowerFailureRecoveryParam() { + return getParam(8, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) +} + +private getPushDimmingDurationParam() { + return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, 2, null, "0..10") +} + +private getHoldDimmingDurationParam() { + return getParam(10, "Hold Dimming Duration(1 - 10 Seconds)", 1, 4, null, "1..10") +} + +private getMinimumBrightnessParam() { + return getParam(11, "Minimum Brightness(0, Disabled; 1 - 99:1% - 99%)", 1, 10, null,"0..99") +} + +private getMaximumBrightnessParam() { + return getParam(12, "Maximum Brightness(0, Disabled; 1 - 99:1% - 99%)", 1, 99, null,"0..99") +} + +private getParam(num, name, size, defaultVal, options=null, range=null) { + def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + + def map = [num: num, name: name, size: size, value: val] + if (options) { + map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value + map.options = setDefaultOption(options, defaultVal) + } + if (range) { + map.range = range + } + + return map +} + +private static setDefaultOption(options, defaultVal) { + return options?.collectEntries { k, v -> + if ("${k}" == "${defaultVal}") { + v = "${v} [DEFAULT]" + } + ["$k": "$v"] + } +} + +private static getLedModeOptions() { + return [ + "0":"Off When On", + "1":"On When On", + "2":"Always Off", + "3":"Always On" + ] +} + +private static getPowerFailureRecoveryOptions() { + return [ + "0":"Turn Off", + "1":"Turn On", + "2":"Restore Last State" + ] +} + +private static validateRange(val, defaultVal, lowVal, highVal) { + val = safeToInt(val, defaultVal) + if (val > highVal) { + return highVal + } else if (val < lowVal) { + return lowVal + } else { + return val + } +} + +private static safeToInt(val, defaultVal=0) { + return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal +} + +private convertToLocalTimeString(dt) { + def timeZoneId = location?.timeZone?.ID + if (timeZoneId) { + return dt.format("MM/dd/yyyy hh:mm:ss a", TimeZone.getTimeZone(timeZoneId)) + } else { + return "$dt" + } +} + +private static isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +private logDebug(msg) { + log.debug "$msg" +} + +private logTrace(msg) { + log.trace "$msg" +} + +def on() { + logDebug "on()..." + + return [ basicSetCmd(0xFF) ] +} + +def off() { + logDebug "off()..." + + return [ basicSetCmd(0x00) ] +} + +def setLevel(level) { + logDebug "setLevel($level)..." + return setLevel(level, 1) +} + +def setLevel(level, duration) { + logDebug "setLevel($level, $duration)..." + if (duration > 30) { + duration = 30 + } + return [ switchMultilevelSetCmd(level, duration) ] +} + +private basicSetCmd(val) { + return secureCmd(zwave.basicV1.basicSet(value: val)) +} + +private switchMultilevelSetCmd(level, duration) { + def levelVal = validateRange(level, 99, 0, 99) + + def durationVal = validateRange(duration, 1, 0, 100) + + return secureCmd(zwave.switchMultilevelV3.switchMultilevelSet(dimmingDuration: durationVal, value: levelVal)) +} + +def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logTrace "VersionReport: ${cmd}" + + def subVersion = String.format("%02d", cmd.applicationSubVersion) + def fullVersion = "${cmd.applicationVersion}.${subVersion}" + + sendEvent(name: "firmwareVersion", value:fullVersion, displayed: true, type: null) + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + logTrace "${cmd}" + sendSwitchEvents(cmd.value, "physical") + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { + logTrace "${cmd}" + sendSwitchEvents(cmd.value, "digital") + return [] +} + +private sendSwitchEvents(rawVal, type) { + def switchVal = rawVal ? "on" : "off" + + sendEvent(name: "switch", value:switchVal, displayed: true, type: type) + + if (rawVal) { + sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") + } +} \ No newline at end of file From 3ea1ece8666a20ccd167c2a319badb5bb65048d6 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 3 Aug 2021 14:31:23 +0800 Subject: [PATCH 021/184] DevWs for NIE-TECH CO., LTD. containing containing Evalogik Door/Window Sensor (#71706) * DevWs for NIE-TECH CO., LTD. containing containing Evalogik Door/Window Sensor * 1.Syntax format compliance adjustment 2.fixed a bug for order repeated * Syntax format compliance adjustment * Simplify the process of calling sendHubCommand * Syntax format compliance adjustment * 1.Syntax format compliance adjustment 2.delete dummy code * omitted all the parameters related to associations group * remove the genericHandler and executeCommandsLocally flags Co-authored-by: Winnie Wen --- .../evalogik-door-window-sensor.groovy | 585 ++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 devicetypes/sky-nie/evalogik-door-window-sensor.src/evalogik-door-window-sensor.groovy diff --git a/devicetypes/sky-nie/evalogik-door-window-sensor.src/evalogik-door-window-sensor.groovy b/devicetypes/sky-nie/evalogik-door-window-sensor.src/evalogik-door-window-sensor.groovy new file mode 100644 index 00000000000..5d9d5797f46 --- /dev/null +++ b/devicetypes/sky-nie/evalogik-door-window-sensor.src/evalogik-door-window-sensor.groovy @@ -0,0 +1,585 @@ +/** + * Evalogik Door/Window Sensor v1.0.5 + * + * Models: MSE30Z + * + * Author: + * winnie (sky-nie) + * + * Documentation: + * + * Changelog: + * + * 1.0.5 (07/28/2021) + * - omitted all the parameters related to associations group + * + * 1.0.4 (07/16/2021) + * - Syntax format compliance adjustment + * - fixed a bug for order repeated + * + * 1.0.3 (07/16/2021) + * - change lastBatteryReport to record the time of fresh battery + * - add lastBattery to record the battery value + * + * 1.0.2 (07/15/2021) + * - update ConfigParams as product designed + * - update DTH name as product designed + * + * 1.0.1 (07/13/2021) + * - Syntax format compliance adjustment + * - delete dummy code + * + * 1.0.0 (04/26/2021) + * - Initial Release + * + * Reference: + * https://community.smartthings.com/t/release-aeotec-trisensor/140556?u=krlaframboise + * + * 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. + * + */ +final int NOTIFICATION_TYPE_ACCESS_CONTROL = 0x06 +final int NOTIFICATION_TYPE_HOME_SECURITY = 0x07 + +final int NOTIFICATION_EVENT_DOOR_WINDOW_OPEN = 0x16 +final int NOTIFICATION_EVENT_DOOR_WINDOW_CLOSED = 0x17 + +final int NOTIFICATION_EVENT_STATE_IDLE = 0x00 +final int NOTIFICATION_EVENT_INSTRUSION_WITH_LOCATION = 0x01 +final int NOTIFICATION_EVENT_INSTRUSION = 0x02 +final int NOTIFICATION_EVENT_TEMPERING = 0x03 + +metadata { + definition(name: "Evalogik Door/Window Sensor", namespace: "sky-nie", author: "winnie", ocfDeviceType: "x.com.st.d.sensor.contact") { + capability "Sensor" + capability "Contact Sensor" + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + capability "Battery" + capability "Configuration" + capability "Refresh" + capability "Health Check" + + attribute "lastCheckIn", "string" + attribute "pendingChanges", "string" + + fingerprint mfr: "0312", prod: "0713", model: "D100", deviceJoinName: "Minoston 3-in-1 Sensor"//MSE30Z + } + + preferences { + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options:it.options + } + } + } +} + +def installed() { + log.debug "installed()..." + state.refreshConfig = true + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +private static def getCheckInterval() { + // These are battery-powered devices, and it's not very critical + // to know whether they're online or not – 12 hrs + return (60 * 60 * 3) + (5 * 60) +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 5000)) { + state.lastUpdated = new Date().time + + log.trace "updated()" + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + + refreshPendingChanges() + + logForceWakeupMessage "Configuration changes will be sent to the device the next time it wakes up." + } +} + +def configure() { + log.trace "configure()" + + runIn(8, executeConfigure) +} + +def executeConfigure() { + def cmds = [ + sensorBinaryGetCmd(), + batteryGetCmd() + ] + + cmds += getConfigCmds() + sendHubCommand(cmds, 500) +} + +private getConfigCmds() { + def cmds = [] + configParams.each { param -> + def storedVal = getParamStoredValue(param.num) + if (state.refreshConfig) { + cmds << configGetCmd(param) + } else if ("${storedVal}" != "${param.value}") { + log.debug "Changing ${param.name}(#${param.num}) from ${storedVal} to ${param.value}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: param.value)) + cmds << configGetCmd(param) + + if (param.num == minTemperatureOffsetParam.num) { + cmds << "delay 3000" + cmds << sensorMultilevelGetCmd(tempSensorType) + } else if (param.num == minHumidityOffsetParam.num) { + cmds << "delay 3000" + cmds << sensorMultilevelGetCmd(lightSensorType) + } + } + } + state.refreshConfig = false + return cmds +} + +// Required for HealthCheck Capability, but doesn't actually do anything because this device sleeps. +def ping() { + log.debug "ping()" +} + +// Forces the configuration to be resent to the device the next time it wakes up. +def refresh() { + logForceWakeupMessage "The sensor data will be refreshed the next time the device wakes up." + state.lastBatteryReport = null + state.lastBattery = null + if (!state.refreshSensors) { + state.refreshSensors = true + } else { + state.refreshConfig = true + } + refreshPendingChanges() + return [] +} + +private logForceWakeupMessage(msg) { + log.debug "${msg} You can force the device to wake up immediately by holding the z-button for 2 seconds." +} + +def parse(String description) { + def result = [] + try { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result += zwaveEvent(cmd) + } else { + log.debug "Unable to parse description: $description" + } + + sendEvent(name: "lastCheckIn", value: convertToLocalTimeString(new Date()), displayed: false) + } catch (e) { + log.error "$e" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapCmd = cmd.encapsulatedCommand(commandClassVersions) + + def result = [] + if (encapCmd) { + result += zwaveEvent(encapCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { + log.debug "Device Woke Up" + + def cmds = [] + if (state.refreshConfig || pendingChanges > 0) { + cmds += getConfigCmds() + } + + if (canReportBattery()) { + cmds << batteryGetCmd() + } + + if (state.refreshSensors) { + cmds += [ + sensorBinaryGetCmd(), + sensorMultilevelGetCmd(tempSensorType), + sensorMultilevelGetCmd(lightSensorType) + ] + state.refreshSensors = false + } + + if (cmds) { + cmds = delayBetween(cmds, 1000) + cmds << "delay 3000" + } + cmds << secureCmd(zwave.wakeUpV1.wakeUpNoMoreInformation()) + return response(cmds) +} + +def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def val = (cmd.batteryLevel == 0xFF ? 1 : cmd.batteryLevel) + if (val > 100) { + val = 100 + } else if (val < 1) { + val = 1 + } + state.lastBatteryReport = new Date().time + state.lastBattery = val + log.debug "Battery ${val}%" + sendEvent(getEventMap("battery", val, null, null, "%")) + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + log.trace "SensorMultilevelReport: ${cmd}" + switch (cmd.sensorType) { + case tempSensorType: + def unit = cmd.scale ? "F" : "C" + def temp = convertTemperatureIfNeeded(cmd.scaledSensorValue, unit, cmd.precision) + sendEvent(getEventMap("temperature", temp, true, null, getTemperatureScale())) + break + case lightSensorType: + sendEvent(getEventMap( "humidity", cmd.scaledSensorValue, true, null, "%")) + break + default: + log.debug "Unknown Sensor Type: ${cmd.sensorType}" + } + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + log.trace "ConfigurationReport ${cmd}" + + runIn(4, refreshPendingChanges) + + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + + log.debug "${param.name}(#${param.num}) = ${val}" + state["configParam${param.num}"] = val + } else { + log.debug "Parameter #${cmd.parameterNumber} = ${cmd.configurationValue}" + } + return [] +} + +def refreshPendingChanges() { + sendEvent(name: "pendingChanges", value: "${pendingChanges} Pending Changes", displayed: false) +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + log.trace "NotificationReport: $cmd" + def result = [] + + if(cmd.notificationType == NOTIFICATION_TYPE_ACCESS_CONTROL){ + if(cmd.event == NOTIFICATION_EVENT_DOOR_WINDOW_OPEN){ + result << sensorValueEvent(1) + } else if(cmd.event == NOTIFICATION_EVENT_DOOR_WINDOW_CLOSED) { + result << sensorValueEvent(0) + } + } else if (cmd.notificationType == NOTIFICATION_TYPE_HOME_SECURITY) { + if (cmd.event == NOTIFICATION_EVENT_STATE_IDLE) { + result << createEvent(descriptionText: "$device.displayName covering was restored", isStateChange: true) + cmds = [zwave.batteryV1.batteryGet(), zwave.wakeUpV1.wakeUpNoMoreInformation()] + result << response(commands(cmds, 1000)) + } else if (cmd.event == NOTIFICATION_EVENT_INSTRUSION_WITH_LOCATION || cmd.event == NOTIFICATION_EVENT_INSTRUSION) { + result << sensorValueEvent(1) + } else if (cmd.event == NOTIFICATION_EVENT_TEMPERING) { + result << createEvent(descriptionText: "$device.displayName covering was removed", isStateChange: true) + } + } else if (cmd.notificationType) { + def text = "Notification $cmd.notificationType: event ${([cmd.event] + cmd.eventParameter).join(", ")}" + result << createEvent(name: "notification$cmd.notificationType", value: "$cmd.event", descriptionText: text, displayed: false) + } else { + def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive" + result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, displayed: false) + } + + result +} + +def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { + log.trace "SensorBinaryReport: $cmd" + def map = [:] + map.value = cmd.sensorValue ? "open" : "closed" + map.name = "contact" + if (map.value == "open") { + map.descriptionText = "${device.displayName} is open" + } else { + map.descriptionText = "${device.displayName} is closed" + } + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.indicatorv1.IndicatorReport cmd) { + log.trace "${cmd}" +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Ignored Command: $cmd" + return [] +} + +private getEventMap(name, value, displayed=null, desc=null, unit=null) { + def isStateChange = (device.currentValue(name) != value) + displayed = (displayed == null ? isStateChange : displayed) + def eventMap = [ + name: name, + value: value, + displayed: displayed, + isStateChange: isStateChange, + descriptionText: desc ?: "${device.displayName} ${name} is ${value}" + ] + + if (unit) { + eventMap.unit = unit + eventMap.descriptionText = "${eventMap.descriptionText}${unit}" + } + if (displayed) { + log.debug "${eventMap.descriptionText}" + } + return eventMap +} + +private batteryGetCmd() { + return secureCmd(zwave.batteryV1.batteryGet()) +} + +private sensorBinaryGetCmd() { + return secureCmd(zwave.sensorBinaryV2.sensorBinaryGet()) +} + +private sensorMultilevelGetCmd(sensorType) { + def scale = (sensorType == tempSensorType) ? 0 : 1 + return secureCmd(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: scale, sensorType: sensorType)) +} + +private configGetCmd(param) { + return secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) +} + +private secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s") || ("0x98" in device?.rawDescription?.split(" "))) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + throw new RuntimeException(ex) + } +} + +private static getCommandClassVersions() { + [ + 0x30: 2, // SensorBinary + 0x31: 5, // SensorMultilevel + 0x55: 1, // TransportServices + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x71: 3, // Notification + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x80: 1, // Battery + 0x84: 1, // WakeUp + 0x85: 2, // Association + 0x86: 1, // Version + 0x8E: 2, // MultChannelAssociation + 0x87: 1, // Indicator + 0x9F: 1 // Security 2 + ] +} + +private canReportBattery() { + return state.refreshSensors || (!isDuplicateCommand(state.lastBatteryReport, (12 * 60 * 60 * 1000))) +} + +private getPendingChanges() { + return configParams.count { "${it.value}" != "${getParamStoredValue(it.num)}" } +} + +private getParamStoredValue(paramNum) { + return safeToInt(state["configParam${paramNum}"] , null) +} + +// Sensor Types +private static getTempSensorType() { return 1 } +private static getLightSensorType() { return 5 } + +// Configuration Parameters +private getConfigParams() { + [ + batteryReportThresholdParam, + lowBatteryAlarmReportParam, + sensorModeWhenClosedParam, + delayReportSecondsWhenClosedParam, + delayReportSecondsWhenOpenedParam, + minTemperatureOffsetParam, + minHumidityOffsetParam, + temperatureUpperWatermarkParam, + temperatureLowerWatermarkParam, + humidityUpperWatermarkParam, + humidityLowerWatermarkParam, + switchTemperatureUnitParam, + temperatureOffsetParam, + humidityOffsetParam, + associationGroupSettingParam + ] +} + +private getBatteryReportThresholdParam() { + return getParam(1, "Battery report threshold(1% - 20%)", 1, 10, null,"1..20") +} + +private getLowBatteryAlarmReportParam() { + return getParam(2, "Low battery alarm report(5% - 20%)", 1, 5, null, "5..20") +} + +private getSensorModeWhenClosedParam() { + return getParam(3, "State of the sensor when the magnet closes the reed", 1, 0, sensorModeWhenCloseOptions) +} + +private getDelayReportSecondsWhenClosedParam() { + return getParam(4, "Delay in seconds with ON command report(door closed)", 2, 0, null, "0..3600") +} + +private getDelayReportSecondsWhenOpenedParam() { + return getParam(5, "Delay in seconds with OFF command report(door open)", 2, 0, null, "0..3600") +} + +private getMinTemperatureOffsetParam() { + return getParam(6, "Minimum Temperature change to report(0.5℃/0.9°F - 5.0℃/9°F)", 1, 10, null, "5..50") +} + +private getMinHumidityOffsetParam() { + return getParam(7, "Minimum Humidity change to report(5% - 20%)", 1, 10, null, "5..20") +} + +private getTemperatureUpperWatermarkParam() { + return getParam(8, "Temperature Upper Watermark value(0,Disabled; 1℃/33.8°F-50℃/122.0°F)", 2, 0, null, "0..50") +} + +private getTemperatureLowerWatermarkParam() { + return getParam(10, "Temperature Lower Watermark value(0,Disabled; 1℃/33.8°F - 50℃/122.0°F)", 2, 0, null, "0..50") +} + +private getHumidityUpperWatermarkParam() { + return getParam(12, "Humidity Upper Watermark value(0,Disabled; 1% - 100%)", 1, 0, null, "0..100") +} + +private getHumidityLowerWatermarkParam() { + return getParam(14, "Humidity Lower Watermark value(0,Disabled; 1%-100%)", 1, 0, null, "0..100") +} + +private getSwitchTemperatureUnitParam() { + return getParam(16, "Switch the unit of Temperature report", 1, 1, switchTemperatureUnitOptions) +} + +private getTemperatureOffsetParam() { + return getParam(17, "Offset value for temperature(-10℃/14.0°F - 10℃/50.0°F)", 1, 0, null, "-100..100") +} + +private getHumidityOffsetParam() { + return getParam(18, "Offset value for humidity (-20% - 20%)", 1, 0, null, "-20..20") +} + +private getAssociationGroupSettingParam() { + return getParam(19, "Association Group 2 Setting", 1, 1, associationGroupSettingOptions) +} + +private getParam(num, name, size, defaultVal, options=null, range=null) { + def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + + def map = [num: num, name: name, size: size, value: val] + if (options) { + map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value + map.options = setDefaultOption(options, defaultVal) + } + if (range) { + map.range = range + } + + return map +} + +private static setDefaultOption(options, defaultVal) { + return options?.collectEntries { k, v -> + if ("${k}" == "${defaultVal}") { + v = "${v} [DEFAULT]" + } + ["$k": "$v"] + } +} + +// Setting Options +private static getSwitchTemperatureUnitOptions() { + return [ + "0":"Celsius", + "1":"Fahrenheit" + ] +} + +private static getAssociationGroupSettingOptions() { + return [ + "0":"Disable completely", + "1":"Send Basic SET 0xFF when Magnet is away,and send Basic SET 0x00 when Magnet is near.", + "2":"Send Basic SET 0x00 when Magnet is away,and send Basic SET 0xFF when Magnet is near", + "3":"Only send Basic SET 0xFF when Magnet is away", + "4":"Only send Basic SET 0x00 when Magnet is near", + "5":"Only send Basic SET 0x00 when Magnet is away", + "6":"Only send Basic SET 0xFF when Magnet is near" + ] +} + +private static getSensorModeWhenCloseOptions() { + return [ + "0":"door/window closed", + "1":"door/window opened" + ] +} + +def sensorValueEvent(value) { + if (value) { + createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open") + } else { + createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed") + } +} + +private static safeToInt(val, defaultVal=0) { + return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal +} + +private convertToLocalTimeString(dt) { + def timeZoneId = location?.timeZone?.ID + if (timeZoneId) { + return dt.format("MM/dd/yyyy hh:mm:ss a", TimeZone.getTimeZone(timeZoneId)) + } else { + return "$dt" + } +} + +private static isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} \ No newline at end of file From 736f6e9e0dad5f5b5893f8b96abfe1d1a50f133f Mon Sep 17 00:00:00 2001 From: dparyani <37111386+dparyani@users.noreply.github.com> Date: Tue, 3 Aug 2021 08:34:19 +0200 Subject: [PATCH 022/184] Sensative's Strips Multi-Sensor Product's Device Handler. (#2898) * Sensative's Strips Multi-Sensor Product's Device Handler. * Changes based on review comments for Strips Guard-700. * Changes based on review comments for Strips Drip-700. * Revert "Sensative's Strips Multi-Sensor Product's Device Handler." This reverts commit 6f220a50c82b6c78201de3c23d1ee19b7ac52cf5. * Cosmetic changes as requested by SmartThings. * Remove updateLastCheckIn() and String convertToLocalTimeString(dt)functions based on review and Kevin's input Co-authored-by: Dhiraj Paryani --- .../sensative-strips-drip-700.groovy | 518 ++++++++++++++++++ .../sensative-strips-guard-700.groovy | 397 ++++++++++++++ 2 files changed, 915 insertions(+) create mode 100644 devicetypes/sensative/sensative-strips-drip-700.src/sensative-strips-drip-700.groovy create mode 100644 devicetypes/sensative/sensative-strips-guard-700.src/sensative-strips-guard-700.groovy diff --git a/devicetypes/sensative/sensative-strips-drip-700.src/sensative-strips-drip-700.groovy b/devicetypes/sensative/sensative-strips-drip-700.src/sensative-strips-drip-700.groovy new file mode 100644 index 00000000000..9e4a255e30b --- /dev/null +++ b/devicetypes/sensative/sensative-strips-drip-700.src/sensative-strips-drip-700.groovy @@ -0,0 +1,518 @@ +/* + * Sensative Strips Drip 700 v1.3 + * + * + * Changelog: + * + * 1.3 (26/07/2021) + * - Remove updateLastCheckIn() and String convertToLocalTimeString(dt)functions based on review and Kevin's input + * + * 1.2 (28/06/2021) + * - Requested Changes + * + * 1.1 (06/06/2021) + * - Requested Changes + * + * 1.0 (05/12/2021) + * - Initial Release + * + * + * Copyright 2021 Sensative + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x22: 1, // ApplicationStatus + 0x31: 5, // Sensor Multilevel (v7) + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 2, // Configuration + 0x71: 3, // Alarm v1 or Notification v4 + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x87: 1, // Indicator + 0x8E: 2, // Multi Channel Association + 0x9F: 1 // Security 2 +] + +@Field static int wakeUpIntervalSeconds = 43200 +@Field static int tempSensorType = 1 +@Field static int leakageCalibrationParamNum = 23 +@Field static int heatAlarm = 4 +@Field static int heatAlarmHigh = 2 +@Field static int heatAlarmLow = 6 +@Field static int waterAlarm = 5 +@Field static int waterAlarmWet = 2 +@Field static int homeSecurity = 7 +@Field static int homeSecurityTamper = 11 + +metadata { + definition ( + name: "Sensative Strips Drip 700", + namespace: "Sensative", + author: "Kevin LaFramboise", + ocfDeviceType:"x.com.st.d.sensor.moisture", + vid: "480ed59e-91d4-3cfc-a077-b06151590ef0", + mnmn: "SmartThingsCommunity" + ) { + capability "Sensor" + capability "Water Sensor" + capability "Temperature Measurement" + capability "Tamper Alert" + capability "Battery" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "platemusic11009.firmware" + capability "platemusic11009.temperatureAlarm" + + fingerprint mfr:"019A", prod:"0004", model:"000B", deviceJoinName: "Strips Drip 700" //Raw Description: zw:Ss2a type:2101 mfr:019A prod:0004 model:000B ver:8.1A zwv:7.13 lib:07 cc:5E,22,55,9F,6C sec:86,85,8E,59,72,31,5A,87,73,80,70,71,84,7A + } + + preferences { + configParams.each { param -> + if (param.options) { + input "configParam${param.num}", "enum", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + options: param.options + } else if (param.range) { + input "configParam${param.num}", "number", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + + input "debugLogging", "enum", + title: "Logging:", + required: false, + defaultValue: 1, + options: [0:"Disabled", 1:"Enabled [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + state.pendingRefresh = true + initialize() +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 1000)) { + state.lastUpdated = new Date().time + + logDebug "updated()..." + initialize() + + if (!getSettingValue(leakageCalibrationParamNum) && (state.leakageCalibrated != null)) { + // reset flag so that it performs calibration the next time it's set to true. + logDebug "Resetting leakage/moisture sensor calibration setting..." + state.leakageCalibrated = null + } + + if (pendingChanges) { + logForceWakeupMessage("The configuration changes will be sent to the device the next time it wakes up.") + } + } +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugOutput, 1) != 0) + + if (!device.currentValue("tamper")) { + sendEventIfNew("tamper", "clear") + } + + if (!device.currentValue("water")) { + sendEventIfNew("water", "dry") + } + + if (!device.currentValue("temperatureAlarm")) { + sendEventIfNew("temperatureAlarm", "normal") + } + + if (!device.currentValue("checkInterval")) { + sendEvent(name: "checkInterval", value: ((wakeUpIntervalSeconds * 2) + 300), displayed: falsle, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } +} + +def configure() { + logDebug "configure()..." + state.pendingRefresh = true + sendCommands(getConfigureCmds()) +} + +List getConfigureCmds() { + runIn(6, refreshSyncStatus) + + int changes = pendingChanges + if (changes) { + log.warn "Syncing ${changes} Change(s)" + } + + List cmds = [ ] + + if (state.pendingRefresh) { + cmds << batteryGetCmd() + cmds << secureCmd(zwave.versionV1.versionGet()) + cmds << secureCmd(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: tempSensorType)) + } + + if (state.pendingRefresh || (state.wakeUpInterval != wakeUpIntervalSeconds)) { + logDebug "Changing wake up interval to ${wakeUpIntervalSeconds} seconds" + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalSet(seconds:wakeUpIntervalSeconds, nodeid:zwaveHubNodeId)) + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + configParams.each { + Integer storedVal = getParamStoredValue(it.num) + Integer settingVal = getSettingValue(it.num) + + if (it.num != leakageCalibrationParamNum) { + if ((settingVal != null) && (settingVal != storedVal)) { + logDebug "CHANGING ${it.name}(#${it.num}) from ${storedVal} to ${settingVal}" + cmds << configSetCmd(it, settingVal) + cmds << configGetCmd(it) + } else if (state.pendingRefresh) { + cmds << configGetCmd(it) + } + } else { + if (settingVal && !state.leakageCalibrated) { + logDebug "Performing leakage/moisture sensor calibration..." + state.leakageCalibrated = false // Indicate that calibration has been started + cmds << configSetCmd(it, settingVal) + cmds << configGetCmd(it) + } + } + } + + state.pendingRefresh = false + return cmds +} + +// Required for HealthCheck Capability, but doesn't actually do anything because this device sleeps. +def ping() { + logDebug "ping()" +} + +def refresh() { + logDebug "refresh()..." + state.pendingRefresh = true + logForceWakeupMessage("The device will be refreshed the next time it wakes up.") +} + +void logForceWakeupMessage(String msg) { + log.warn "${msg} To force the device to wake up immediately, move the magnet towards the round end 3 times." +} + +String batteryGetCmd() { + return secureCmd(zwave.batteryV1.batteryGet()) +} + +String configSetCmd(Map param, int value) { + return secureCmd(zwave.configurationV2.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: value)) +} + +String configGetCmd(Map param) { + return secureCmd(zwave.configurationV2.configurationGet(parameterNumber: param.num)) +} + +String secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + return cmd.format() + } +} + +void sendCommands(List cmds, Integer delay=250) { + if (cmds) { + def actions = [] + cmds.each { + actions << new physicalgraph.device.HubAction(it) + } + sendHubCommand(actions, delay) + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + logDebug "Device Woke Up..." + List cmds = [] + + cmds += getConfigureCmds() + + if (cmds) { + cmds << "delay 1000" + } else { + cmds << batteryGetCmd() + } + + cmds << secureCmd(zwave.wakeUpV2.wakeUpNoMoreInformation()) + sendCommands(cmds) +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + logDebug "Wake Up Interval = ${cmd.seconds} seconds" + state.wakeUpInterval = cmd.seconds +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEventIfNew("firmwareVersion", (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + int val = (cmd.batteryLevel == 0xFF ? 1 : safeToInt(cmd.batteryLevel)) + if (val > 100) val = 100 + if (val < 1) val = 1 + + String desc = "${device.displayName}: battery is ${val}%" + logDebug(desc) + + sendEvent(name: "battery", value: val, unit: "%", isStateChange: true, descriptionText: desc) +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + + Map param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + logDebug "${param.name}(#${param.num}) = ${cmd.scaledConfigurationValue}" + setParamStoredValue(param.num, cmd.scaledConfigurationValue) + + if ((param.num == leakageCalibrationParamNum) && (state.leakageCalibrated == false) && !cmd.scaledConfigurationValue) { + state.leakageCalibrated = true // calibration was started so indicate it completed to prevent it from being run again. + logDebug "Leakage/moisture sensor calibration finished..." + } + } else { + logDebug "Unknown Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + logDebug "${cmd}" + if (cmd.sensorType == tempSensorType) { + def unit = cmd.scale == 1 ? "F" : "C" + def temp = convertTemperatureIfNeeded(cmd.scaledSensorValue, unit, cmd.precision) + sendEventIfNew("temperature", temp, true, temperatureScale) + } +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + logDebug "${cmd}" + switch (cmd.notificationType) { + case heatAlarm: + if ((cmd.event == heatAlarmHigh) || (cmd.eventParameter[0] == heatAlarmHigh)) { + sendEventIfNew("temperatureAlarm", ((cmd.event == heatAlarmHigh) ? "high" : "normal")) + } else if ((cmd.event == heatAlarmLow) || (cmd.eventParameter[0] == heatAlarmLow)) { + sendEventIfNew("temperatureAlarm", ((cmd.event == heatAlarmLow) ? "low" : "normal")) + } + break + case waterAlarm: + sendEventIfNew("water", ((cmd.event == waterAlarmWet) ? "wet" : "dry")) + break + case homeSecurity: + if ((cmd.event == homeSecurityTamper) || (cmd.eventParameter[0] == homeSecurityTamper)) { + sendEventIfNew("tamper", ((cmd.event == homeSecurityTamper) ? "detected" : "clear")) + } + break + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "${cmd}" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEventIfNew("syncStatus", (changes ? "${changes} Pending Changes" : "Synced"), false) +} + +int getPendingChanges() { + int configChanges = safeToInt(configParams.count { + ((it.num != leakageCalibrationParam.num) && (getSettingValue(it.num) != null) && (getSettingValue(it.num) != getParamStoredValue(it.num))) + }, 0) + return (configChanges + ((state.wakeUpInterval != wakeUpIntervalSeconds) ? 1 : 0)) +} + +Integer getSettingValue(int paramNum) { + return safeToInt((settings ? settings["configParam${paramNum}"] : null), null) +} + +Integer getParamStoredValue(int paramNum) { + return safeToInt(state["configVal${paramNum}"], null) +} + +void setParamStoredValue(int paramNum, int value) { + state["configVal${paramNum}"] = value +} + +void sendEventIfNew(String name, value, boolean displayed=true, String unit="") { + String desc = "${device.displayName}: ${name} is ${value}${unit}" + if (device.currentValue(name) != value) { + if (name != "syncStatus") { + logDebug(desc) + } + + Map evt = [ + name: name, + value: value, + descriptionText: desc, + displayed: displayed + ] + + if (unit) { + evt.unit = unit + } + sendEvent(evt) + } +} + +List getConfigParams() { + return [ + ledAlarmParam, + tempReportingTypeParam, + tempAlarmsParam, + highTempAlarmLevelParam, + lowTempAlarmLevelParam, + leakageAlarmParam, + leakageAlarmLevelParam, + leakageAlarmIntervalParam, + activateSupervisionParam, + leakageCalibrationParam, + tempOffsetParam, + tempReportingIntervalParam, + tempDeltaParam, + tempHysteresisParam + ] +} + +Map getLedAlarmParam() { + return [num:2, name:"LED alarm event reporting", size:1, options:[0:"Off", 1:"On [DEFAULT]"]] +} + +Map getTempReportingTypeParam() { + return [num:4, name:"Temperature reporting type", size:1, options:[ + 0:"Off [DEFAULT]", + 1:"Actual value on Temperature Delta change", + 2:"Actual value at Temperature Reporting Interval", + 3:"Average value every 12 hours" + ]] +} + +Map getTempAlarmsParam() { + return [num:6, name:"Temperature alarms", size:1, options:[0:"Off [DEFAULT]", 1:"On"]] +} + +Map getHighTempAlarmLevelParam() { + return [num:7, name:"High temperature alarm level (°C)", size:1, defaultVal: 40, range:"-20..80"] +} + +Map getLowTempAlarmLevelParam() { + return [num:8, name:"Low temperature alarm level (°C)", size:1, defaultVal: 5, range:"-20..60"] +} + +Map getLeakageAlarmParam() { + return [num:12, name:"Leakage/moisture alarm", size:1, options:[0:"Off", 1:"On [DEFAULT]"]] +} + +Map getLeakageAlarmLevelParam() { + return [num:13, name:"Leakage/moisture alarm level (1:almost dry ~ 100:wet)", size:1, defaultVal: 10, range:"1..100"] +} + +Map getLeakageAlarmIntervalParam() { + return [num:14, name:"Leakage/moisture reporting period (hours)", size:1, defaultVal:0, range:"0..120"] +} + +Map getActivateSupervisionParam() { + return [num:15, name:"Activate Supervision", size:1, options:[0:"Off", 1:"Alarm Report [DEFAULT]", 2:"All Reports"]] +} + +Map getLeakageCalibrationParam() { + return [num:23, name:"Leakage/moisture sensor calibration", size:1, options:[0:"Off [DEFAULT]", 1:"Perform calibration"]] +} + +Map getTempOffsetParam() { + return [num:24, name:"Temperature offset (-10.0°C ~ +10.0°C)", size:1, defaultVal:0, range:"-100..100"] +} + +Map getTempReportingIntervalParam() { + return [num:25, name:"Temperature reporting period (minutes)", size:2, range:"15..1440", defaultVal:1440] +} + +Map getTempDeltaParam() { + return [num:26, name:"Temperature delta (0.5°C ~ 10°C)", size:1, defaultVal: 20, range:"5..100"] +} + +Map getTempHysteresisParam() { + return [num:27, name:"Temperature hysteresis for temperature alarms (0.5°C ~ 10°C)", size:1, defaultVal: 20, range:"5..100"] +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +boolean isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file diff --git a/devicetypes/sensative/sensative-strips-guard-700.src/sensative-strips-guard-700.groovy b/devicetypes/sensative/sensative-strips-guard-700.src/sensative-strips-guard-700.groovy new file mode 100644 index 00000000000..4b6c00148c9 --- /dev/null +++ b/devicetypes/sensative/sensative-strips-guard-700.src/sensative-strips-guard-700.groovy @@ -0,0 +1,397 @@ +/* + * Sensative Strips Guard 700 v1.2 + * + * + * Changelog: + * + * 1.3 (26/07/2021) + * - Remove updateLastCheckIn() and String convertToLocalTimeString(dt)functions based on review and Kevin's input + * + * 1.2 (28/06/2021) + * - Requested Changes + * + * 1.1 (06/06/2021) + * - Requested Changes + * + * 1.0 (05/12/2021) + * - Initial Release + * + * + * Copyright 2021 Sensative + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x22: 1, // ApplicationStatus + 0x30: 1, // SensorBinary + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 2, // Configuration + 0x71: 3, // Alarm v1 or Notification v4 + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x87: 1, // Indicator + 0x8E: 2, // Multi Channel Association + 0x9F: 1 // Security 2 +] + +@Field static int accessControl = 6 +@Field static int accessControlOpen = 22 +@Field static int accessControlClosed = 23 +@Field static int homeSecurity = 7 +@Field static int homeSecurityOpen = 2 +@Field static int homeSecurityTamper = 11 +@Field static int wakeUpIntervalSeconds = 43200 + +metadata { + definition ( + name: "Sensative Strips Guard 700", + namespace: "Sensative", + author: "Kevin LaFramboise", + ocfDeviceType:"x.com.st.d.sensor.contact", + mnmn: "SmartThingsCommunity", + vid: "6d19b679-a36a-327f-809d-163f8b8d54d9" + ) { + capability "Sensor" + capability "Contact Sensor" + capability "Tamper Alert" + capability "Battery" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "platemusic11009.firmware" + + fingerprint mfr:"019A", prod:"0004", model:"0004", deviceJoinName: "Strips Guard 700" //Raw Description: zw:Ss2a type:0701 mfr:019A prod:0004 model:0004 ver:8.1A zwv:7.13 lib:07 cc:5E,22,55,9F,6C sec:86,85,8E,59,72,30,5A,87,73,80,70,71,84,7A + } + + preferences { + configParams.each { param -> + input "configParam${param.num}", "enum", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + options: param.options + } + + input "debugLogging", "enum", + title: "Logging:", + required: false, + defaultValue: 1, + options: [0:"Disabled", 1:"Enabled [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + state.pendingRefresh = true + initialize() +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 1000)) { + state.lastUpdated = new Date().time + + logDebug "updated()..." + initialize() + + if (pendingChanges) { + logForceWakeupMessage("The configuration changes will be sent to the device the next time it wakes up.") + } + } +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugOutput, 1) != 0) + + if (!device.currentValue("tamper")) { + sendEventIfNew("tamper", "clear") + } + + if (!device.currentValue("contact")) { + sendEventIfNew("contact", "open") + } + + if (!device.currentValue("checkInterval")) { + sendEvent(name: "checkInterval", value: ((wakeUpIntervalSeconds * 2) + 300), displayed: falsle, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } +} + +def configure() { + logDebug "configure()..." + state.pendingRefresh = true + sendCommands(getConfigureCmds()) +} + +List getConfigureCmds() { + runIn(6, refreshSyncStatus) + + int changes = pendingChanges + if (changes) { + log.warn "Syncing ${changes} Change(s)" + } + + List cmds = [ ] + + if (state.pendingRefresh) { + cmds << batteryGetCmd() + cmds << secureCmd(zwave.versionV1.versionGet()) + cmds << secureCmd(zwave.sensorBinaryV1.sensorBinaryGet()) + } + + if (state.pendingRefresh || (state.wakeUpInterval != wakeUpIntervalSeconds)) { + logDebug "Changing wake up interval to ${wakeUpIntervalSeconds} seconds" + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalSet(seconds:wakeUpIntervalSeconds, nodeid:zwaveHubNodeId)) + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + configParams.each { + Integer storedVal = getParamStoredValue(it.num) + Integer settingVal = getSettingValue(it.num) + + if ((settingVal != null) && (settingVal != storedVal)) { + logDebug "CHANGING ${it.name}(#${it.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV2.configurationSet(parameterNumber: it.num, size: it.size, scaledConfigurationValue: settingVal)) + cmds << configGetCmd(it) + } else if (state.pendingRefresh) { + cmds << configGetCmd(it) + } + } + + state.pendingRefresh = false + return cmds +} + +// Required for HealthCheck Capability, but doesn't actually do anything because this device sleeps. +def ping() { + logDebug "ping()" +} + +def refresh() { + logDebug "refresh()..." + state.pendingRefresh = true + logForceWakeupMessage("The device will be refreshed the next time it wakes up.") +} + +void logForceWakeupMessage(String msg) { + log.warn "${msg} To force the device to wake up immediately, move the magnet towards the round end 3 times." +} + +String batteryGetCmd() { + return secureCmd(zwave.batteryV1.batteryGet()) +} + +String configGetCmd(Map param) { + return secureCmd(zwave.configurationV2.configurationGet(parameterNumber: param.num)) +} + +String secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + return cmd.format() + } +} + +void sendCommands(List cmds, Integer delay=100) { + if (cmds) { + def actions = [] + cmds.each { + actions << new physicalgraph.device.HubAction(it) + } + sendHubCommand(actions, delay) + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + logDebug "Device Woke Up..." + List cmds = [] + cmds += getConfigureCmds() + + if (cmds) { + cmds << "delay 500" + } else { + cmds << batteryGetCmd() + } + + cmds << secureCmd(zwave.wakeUpV2.wakeUpNoMoreInformation()) + sendCommands(cmds) +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + logDebug "Wake Up Interval = ${cmd.seconds} seconds" + state.wakeUpInterval = cmd.seconds +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEventIfNew("firmwareVersion", (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + int val = (cmd.batteryLevel == 0xFF ? 1 : safeToInt(cmd.batteryLevel)) + if (val > 100) val = 100 + if (val < 1) val = 1 + + String desc = "${device.displayName}: battery is ${val}%" + logDebug(desc) + + sendEvent(name: "battery", value: val, unit: "%", isStateChange: true, descriptionText: desc) +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + + Map param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + logDebug "${param.name}(#${param.num}) = ${cmd.scaledConfigurationValue}" + setParamStoredValue(param.num, cmd.scaledConfigurationValue) + } else { + logDebug "Unknown Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) { + logDebug "${cmd}" + sendContactEvent(cmd.sensorValue) +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + logDebug "${cmd}" + switch (cmd.notificationType) { + case accessControl: + if ((cmd.event == accessControlOpen) || (cmd.event == accessControlClosed)) { + sendContactEvent(cmd.event == accessControlOpen) + } + break + case homeSecurity: + if ((cmd.event == homeSecurityTamper) || (cmd.eventParameter[0] == homeSecurityTamper)) { + sendTamperEvent(cmd.event == homeSecurityTamper) + } else if ((cmd.event == homeSecurityOpen) || (cmd.eventParameter[0] == homeSecurityOpen)) { + sendContactEvent(cmd.event == homeSecurityOpen) + } + break + } +} + +void sendContactEvent(rawVal) { + sendEventIfNew("contact", (rawVal ? "open" : "closed")) +} + +void sendTamperEvent(rawVal) { + sendEventIfNew("tamper", (rawVal ? "detected" : "clear")) +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "${cmd}" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEventIfNew("syncStatus", (changes ? "${changes} Pending Changes" : "Synced"), false) +} + +int getPendingChanges() { + return safeToInt(configParams.count { ((getSettingValue(it.num) != null) && (getSettingValue(it.num) != getParamStoredValue(it.num))) }) + ((state.wakeUpInterval != wakeUpIntervalSeconds) ? 1 : 0) +} + +Integer getSettingValue(int paramNum) { + return safeToInt((settings ? settings["configParam${paramNum}"] : null), null) +} + +Integer getParamStoredValue(int paramNum) { + return safeToInt(state["configVal${paramNum}"], null) +} + +void setParamStoredValue(int paramNum, int value) { + state["configVal${paramNum}"] = value +} + +void sendEventIfNew(String name, value, boolean displayed=true) { + String desc = "${device.displayName}: ${name} is ${value}" + if (device.currentValue(name) != value) { + if (name != "syncStatus") { + logDebug(desc) + } + sendEvent(name: name, value: value, descriptionText: desc, displayed: displayed) + } +} + +List getConfigParams() { + return [ + ledAlarmParam, + activateSupervisionParam + ] +} + +Map getLedAlarmParam() { + return [num: 2, name: "LED alarm event reporting", size: 1, options: [0: "Turns off LED for door open events", 1:"On [DEFAULT]"]] +} + +Map getActivateSupervisionParam() { + return [num:15, name:"Activate Supervision", size:1, options:[0:"Off", 1:"Alarm Report [DEFAULT]", 2:"All Reports"]] +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +boolean isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From 77af4b9bb2fc6614ddaade317adb25c4eb778e25 Mon Sep 17 00:00:00 2001 From: natec007 Date: Tue, 17 Aug 2021 13:40:33 -0700 Subject: [PATCH 023/184] Update fingerprint (#73965) --- .../spruce-controller.src/spruce-controller.groovy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy index c2a6159c6df..e013806a53a 100644 --- a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy +++ b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy @@ -11,6 +11,9 @@ * for the specific language governing permissions and limitations under the License. * +Version v3.8 + * remove zigbeeNodeType: "ROUTER" from fingerprint + Version v3.7 * update add zoneOn, zoneOff commands for external integration * move zone status update to parse @@ -64,7 +67,7 @@ import groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType //dth version -def getVERSION() {'v3.7 6-2021'} +def getVERSION() {'v3.8 8-2021'} def getDEBUG() {false} def getHC_INTERVAL_MINS() {60} //zigbee cluster, attribute, identifiers @@ -105,7 +108,7 @@ metadata { command "settingsMap" //new release - fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01", zigbeeNodeType: "ROUTER", deviceJoinName: "Spruce Irrigation Controller" + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01", deviceJoinName: "Spruce Irrigation Controller" } preferences { From 41eaa7e48eb15ff0e55d988602ff0e4b83ffa0df Mon Sep 17 00:00:00 2001 From: natec007 Date: Tue, 17 Aug 2021 13:41:24 -0700 Subject: [PATCH 024/184] update fingerprint to correct join issue (#73948) --- .../plaidsystems/spruce-sensor.src/spruce-sensor.groovy | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy index 6d20eb83694..54ff1c8f713 100644 --- a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy +++ b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy @@ -15,6 +15,9 @@ -------6/2021 Updates-------- - Update for 2021 Samsung SmartThings App + + -------8/2021 Updates-------- + - remove zigbeeNodeType from fingerprints */ @@ -43,9 +46,9 @@ metadata { attribute "reportingInterval", "NUMBER" //new release - fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor - fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor - fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", zigbeeNodeType: "SLEEPY_END_DEVICE", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", deviceJoinName: "Spruce Irrigation" //Spruce Sensor } preferences { From af08e5ad44a0d605339f6fcf8a2fef90e244f79f Mon Sep 17 00:00:00 2001 From: Eric Barnett Date: Thu, 19 Aug 2021 18:45:29 -0500 Subject: [PATCH 025/184] DevWs for HAB Home Intelligence containing containing Z-Wave Window Shade --- devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy b/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy index cfc352d7fdc..eecb8a466e7 100644 --- a/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy +++ b/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy @@ -28,6 +28,7 @@ metadata { fingerprint mfr:"0287", prod:"0003", model:"000D", deviceJoinName: "iBlinds Window Treatment" fingerprint mfr:"0287", prod:"0004", model:"0071", deviceJoinName: "iBlinds Window Treatment" + fingerprint mfr:"0287", prod:"0004", model:"0072", deviceJoinName: "iBlinds Window Treatment" } simulator { @@ -354,4 +355,4 @@ def getBattery() { def isV3Device() { zwaveInfo.mfr == "0287" && zwaveInfo.prod == "0004" && zwaveInfo.model == "0071" -} +} \ No newline at end of file From 278499267fcdfa41f3c58a6baa58e08d38cf4e07 Mon Sep 17 00:00:00 2001 From: dwd-kwon <59678391+dwd-kwon@users.noreply.github.com> Date: Mon, 23 Aug 2021 17:04:48 +0900 Subject: [PATCH 026/184] Update zigbee-metering-plug-power-consumption-report.groovy --- .../zigbee-metering-plug-power-consumption-report.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy b/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy index 7b95c8e18e6..1e147e010a9 100644 --- a/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy @@ -81,7 +81,7 @@ def parse(String description) { map.value = zigbee.convertHexToInt(it.value)/getEnergyDiv() map.unit = "kWh" - def currentEnergy = map.value + def currentEnergy = zigbee.convertHexToInt(it.value) def currentPowerConsumption = device.currentState("powerConsumption")?.value Map previousMap = currentPowerConsumption ? new groovy.json.JsonSlurper().parseText(currentPowerConsumption) : [:] def deltaEnergy = calculateDelta (currentEnergy, previousMap) From ff0f4cee31a9f4ccbb2f6d8a974ae80aabfd663e Mon Sep 17 00:00:00 2001 From: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Date: Tue, 24 Aug 2021 08:11:06 +0200 Subject: [PATCH 027/184] [WWST-6928] Z-Wave Mold Detector DTH (#74134) * Z-Wave Mold detector handler * Removed wakeUpIntervalSet --- .../zwave-mold-detector.groovy | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 devicetypes/smartthings/zwave-mold-detector.src/zwave-mold-detector.groovy diff --git a/devicetypes/smartthings/zwave-mold-detector.src/zwave-mold-detector.groovy b/devicetypes/smartthings/zwave-mold-detector.src/zwave-mold-detector.groovy new file mode 100644 index 00000000000..d57ebe26150 --- /dev/null +++ b/devicetypes/smartthings/zwave-mold-detector.src/zwave-mold-detector.groovy @@ -0,0 +1,204 @@ +/** + * Copyright 2020 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. + * + * Generic Z-Wave Water/Temp/Humidity Sensor + * + * Author: SmartThings + * Date: 2020-07-22 + */ + +metadata { + definition(name: "Z-Wave Mold Detector", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-mold", ocfDeviceType: "oic.d.thermostat") { + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + capability "Dew Point" + capability "Mold Health Concern" + capability "Battery" + capability "Sensor" + capability "Health Check" + + // Aeotec Aerq Temperature and Humidity Sensor + fingerprint mfr:"0371", prod:"0002", model:"0009", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-temp-humidity" //EU + fingerprint mfr:"0371", prod:"0102", model:"0009", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-temp-humidity" //US + fingerprint mfr:"0371", prod:"0202", model:"0009", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-temp-humidity" //AU + // POPP Mold Detector + fingerprint mfr:"0154", prod:"0004", model:"0014", deviceJoinName: "POPP Multipurpose Sensor" //EU + } + + tiles(scale: 2) { + multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState "temperature", label: '${currentValue}°', + backgroundColors: [ + [value: 31, 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"] + ] + } + } + valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) { + state "humidity", label: '${currentValue}% humidity', unit: "" + } + valueTile("dewPoint", "device.dewPoint", inactiveLabel: false, width: 2, height: 2) { + state "dewPoint", label: '${currentValue}° dewPoint', unit: "" + } + 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 "temperature", "humidity", "dewPoint" + details(["temperature", "humidity", "dewPoint", "battery"]) + } +} + +def installed() { + sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 10 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // device doesn't send it on inclusion by itslef, so event is needed to populate plugin + sendEvent(name: "moldHealthConcern", value: "good", displayed: false) + + def cmds = [ + secure(zwave.batteryV1.batteryGet()), + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05)), // humidity + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)), // temperature + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x0B)), // dew point + secure(zwave.wakeUpV2.wakeUpNoMoreInformation()) + ] + + response(cmds) +} + +def parse(String description) { + def results = [] + + if (description.startsWith("Err")) { + results += createEvent(descriptionText: description, displayed: true) + } else { + def cmd = zwave.parse(description) + if (cmd) { + results += zwaveEvent(cmd) + } + } + + log.debug "parse() result ${results.inspect()}" + + return results +} + +def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + log.debug "Wake Up Interval Report: ${cmd}" +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + log.debug "Event: ${cmd.event}, Notification type: ${cmd.notificationType}" + + def value + def description + + if (cmd.notificationType == 0x10) { // Mold Environment Detection + switch (cmd.event) { + case 0x00: + value = "good" + description = "Mold environment not detected" + break + case 0x02: + value = "unhealthy" + description = "Mold environment detected" + break + default: + log.warn "Not handled event type for Mold Environment Detection: ${cmd.event}" + return + } + + createEvent(name: "moldHealthConcern", value: value, descriptionText: description, isStateChange: true, displayed: true) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def map = [name: "battery", unit: "%", isStateChange: true] + state.lastbatt = now() + + if (cmd.batteryLevel == 0xFF) { + map.value = 1 + map.descriptionText = "$device.displayName battery is low!" + } else { + map.value = cmd.batteryLevel + } + + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + + switch (cmd.sensorType) { + case 0x01: + map.name = "temperature" + map.unit = temperatureScale + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision) + map.displayed = true + map.isStateChange = true + break + case 0x05: + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + map.displayed = true + map.isStateChange = true + break + case 0x0B: + map.name = "dewpoint" + map.unit = temperatureScale + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision) + map.displayed = true + map.isStateChange = true + break + default: + map.descriptionText = cmd.toString() + } + + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + def cmds = [] + def result = createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) + + if (!state.lastbatt || (now() - state.lastbatt) >= 10 * 60 * 60 * 1000) { + cmds += [ + "delay 1000", + secure(zwave.batteryV1.batteryGet()), + "delay 2000" + ] + } + cmds += secure(zwave.wakeUpV2.wakeUpNoMoreInformation()) + + [result, response(cmds)] +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.warn "Unhandled command: ${cmd}" +} + +private secure(cmd) { + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} From baedfcbfff71000ba1b56e6138d38c9a890204f5 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 24 Aug 2021 17:50:38 +0800 Subject: [PATCH 028/184] DevWs for NIE-TECH CO., LTD. containing Minoston Wallmote (#74138) * DevWs for NIE-TECH CO., LTD. containing containing Aeotec Wallmote * pull down the last version from public master branch,then add my change. * Syntax format compliance adjustment for PR review. * add "pushed_3x" to SupportedButtonValues, as product designed. * Syntax format compliance adjustment Co-authored-by: Winnie Wen --- .../aeotec-wallmote.src/aeotec-wallmote.groovy | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy index 61e3d0cfa70..f04b9d09bd3 100644 --- a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy +++ b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy @@ -27,6 +27,7 @@ metadata { fingerprint mfr: "0086", model: "0081", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Aeotec Wallmote fingerprint mfr: "0060", model: "0003", deviceJoinName: "Everspring Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Everspring Wall Switch fingerprint mfr: "0371", model: "0016", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Aeotec illumino Wallmote 7 + fingerprint mfr: "0312", model: "D001", deviceJoinName: "Minoston Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Minoston Wallmote } tiles(scale: 2) { @@ -45,7 +46,7 @@ metadata { } def getNumberOfButtons() { - def modelToButtons = ["0082" : 4, "0081": 2, "0003": 2, "0016": 2] + def modelToButtons = ["D001" : 4, "0082" : 4, "0081": 2, "0003": 2, "0016": 2] return modelToButtons[zwaveInfo.model] ?: 1 } @@ -172,6 +173,8 @@ def getChildDevice(button) { private getSupportedButtonValues() { if (isEverspring()) { return ["pushed", "held", "double"] + } else if (isMinoston()) { + return ["pushed", "held", "double", "pushed_3x"] } else if (isWallMote7()) { return ["pushed", "held", "double", "pushed_3x", "pushed_4x", "pushed_5x"] } else { @@ -184,6 +187,11 @@ private getButtonAttributesMap() { 0: "pushed", 2: "held", 3: "double" + ]} else if (isMinoston()) {[ + 0: "pushed", + 2: "held", + 3: "double", + 4: "pushed_3x" ]} else if (isWallMote7()) {[ 0: "pushed", 2: "held", @@ -201,6 +209,10 @@ private isEverspring() { zwaveInfo.model.equals("0003") } +private isMinoston() { + zwaveInfo.model.equals("D001") +} + private isWallMote7() { zwaveInfo.model.equals("0016") } \ No newline at end of file From b3aa851e2910825e88c12c1f3724ea827e3e4b78 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 25 Aug 2021 17:40:11 +0800 Subject: [PATCH 029/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug (#74612) * DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug * update base on the last publish version Co-authored-by: Winnie Wen --- .../sky-nie/min-smart-plug.src/min-smart-plug.groovy | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy index 1c07abef3bd..0d4a00d1dc5 100644 --- a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy +++ b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy @@ -55,6 +55,7 @@ metadata { fingerprint mfr: "0312", prod: "C000", model: "C009", deviceJoinName: "Minoston Outlet" // old MP21Z fingerprint mfr: "0312", prod: "FF00", model: "FF0C", deviceJoinName: "Minoston Outlet" //MP21Z Minoston Mini Smart Plug + fingerprint mfr: "0312", prod: "AC01", model: "4001", deviceJoinName: "New One Outlet" // N4001 New One Mini Smart Plug } preferences { @@ -63,7 +64,7 @@ metadata { if (it.range) { input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range } else { - input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options:it.options + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options } } } @@ -143,27 +144,22 @@ def executeConfigureCmds() { def ping() { logDebug "ping()..." - return [ switchBinaryGetCmd() ] } def on() { logDebug "on()..." - return [ switchBinarySetCmd(0xFF) ] } def off() { logDebug "off()..." - return [ switchBinarySetCmd(0x00) ] } def refresh() { logDebug "refresh()..." - refreshSyncStatus() - sendCommands([switchBinaryGetCmd()]) } @@ -322,11 +318,11 @@ private getLedModeParam() { } private getAutoOffIntervalParam() { - return getParam(2, "Auto Turn-Off Timer(0, Disabled; 1--60480 minutes)", 4, 0, null, "0..60480") + return getParam(2, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getAutoOnIntervalParam() { - return getParam(4, "Auto Turn-On Timer(0, Disabled; 1--60480 minutes)", 4, 0, null, "0..60480") + return getParam(4, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getPowerFailureRecoveryParam() { From 22e7cfbbad2dec1978f58c8567254bd5351bb220 Mon Sep 17 00:00:00 2001 From: Nixx-deyi <83563017+Nixx-deyi@users.noreply.github.com> Date: Wed, 25 Aug 2021 21:20:07 +0800 Subject: [PATCH 030/184] DevWs for Deyi smart home containing containing ZigBee Window Shade Battery (#71072) * DevWs for Deyi smart home containing containing ZigBee Window Shade Battery * Use the new version of the DTH * Remove extra spaces * Add one empty line between those two methods. * Fix spacing and add space before || * Add space before || --- .../zigbee-window-shade-battery.groovy | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy index 174eceb9e44..a67d14754f7 100644 --- a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy +++ b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy @@ -36,6 +36,9 @@ metadata { // Yookee yooksmart fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Yookee", model: "D10110", deviceJoinName: "Yookee Window Treatment" fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "yooksmart", model: "D10110", deviceJoinName: "yooksmart Window Treatment" + + // SMARTWINGS + fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Smartwings", model: "WM25/L-Z", deviceJoinName: "Smartwings Window Treatment" } preferences { @@ -280,7 +283,7 @@ def configure() { } def usesLocalGroupBinding() { - isIkeaKadrilj() || isIkeaFyrtur() + isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() } private def parseBindingTableMessage(description) { @@ -311,15 +314,15 @@ private List readDeviceBindingTable() { } def supportsLiftPercentage() { - isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() + isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() } def shouldInvertLiftPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() + return isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() } def reportsBatteryPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() + return isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() } def isIkeaKadrilj() { @@ -333,3 +336,7 @@ def isIkeaFyrtur() { def isYooksmartOrYookee() { device.getDataValue("model") == "D10110" } + +def isSmartwings() { + device.getDataValue("model") == "WM25/L-Z" +} \ No newline at end of file From e12d3f07c8f65abafa4c2135e08cbef211f5349b Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 25 Aug 2021 23:54:48 +0800 Subject: [PATCH 031/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer (#74613) Co-authored-by: Winnie Wen --- .../min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index f17e80c487b..299436c6a13 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -78,7 +78,7 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Dimmer Switch" //MP21ZD fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Dimmer Switch" //MP22ZD - fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "Minoston Dimmer Switch" //N4002 + fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Dimmer Switch" //N4002 } preferences { @@ -193,7 +193,6 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport def param = configParams.find { it.num == cmd.parameterNumber } if (param) { def val = cmd.scaledConfigurationValue - logDebug "${param.name}(#${param.num}) = ${val}" state["configParam${param.num}"] = val } else { From 53dd83f6adb0a0f3c76f5312ea69feab2c36bd9d Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Fri, 27 Aug 2021 11:55:11 +0800 Subject: [PATCH 032/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer --- .../min-smart-plug-dimmer.groovy | 245 +++++++++++++++--- 1 file changed, 210 insertions(+), 35 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 299436c6a13..89f80b3ed0b 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v1.1.9 + * Min Smart Plug Dimmer v2.0.1 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,13 @@ * * Changelog: * + * 2.0.1 (08/27/2021) + * - Syntax format compliance adjustment + * - fix some bugs + * + * 2.0.0 (07/30/2021) + * - add some fingerprint for new devices + * * 1.1.9 (07/29/2021) * - add a fingerprint for a new device * @@ -48,7 +55,6 @@ * * Reference: * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/eva-logik-in-wall-smart-dimmer.src/eva-logik-in-wall-smart-dimmer.groovy - * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/aeotec-trisensor.src/aeotec-trisensor.groovy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,6 +69,7 @@ * limitations under the License. * */ +import groovy.json.JsonOutput metadata { definition (name: "Min Smart Plug Dimmer", namespace: "sky-nie", author: "winnie", ocfDeviceType: "oic.d.smartplug") { @@ -71,6 +78,7 @@ metadata { capability "Switch Level" capability "Configuration" capability "Refresh" + capability "Health Check" attribute "firmwareVersion", "string" attribute "lastCheckIn", "string" @@ -79,21 +87,139 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Dimmer Switch" //MP21ZD fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Dimmer Switch" //MP22ZD fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Dimmer Switch" //N4002 + fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS11ZS Minoston Smart Dimmer Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS13ZS Minoston Smart Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31S Evalogik Smart Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31TS Evalogik Smart Toggle Dimmer Switch } preferences { - configParams.each { - if (it.range) { - input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range - } else { - input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options - } + getConfigParamInput(ledModeParam) + getConfigParamInput(autoOffIntervalParam) + getConfigParamInput(autoOnIntervalParam) + getConfigParamInput(powerFailureRecoveryParam) + getConfigParamInput(pushDimmingDurationParam) + getConfigParamInput(holdDimmingDurationParam) + getConfigParamInput(minimumBrightnessParam) + input "disclaimer", "paragraph", + title: "WARNING", + description: "Configuring for 'Night Light Settings' is only valid for the devices with product number of MP21ZD、MP22ZD、N4002(one of them)", + required: false + getConfigParamInput(nightLightParam) + input "disclaimer", "paragraph", + title: "WARNING", + description: "Configuring for 'createButton'、'Maximum Brightness' and 'Paddle Control' are only valid for the devices with product number of MS11ZS、MS13ZS、ZW31S、ZW31TS(one of them)", + required: false + getConfigParamInput(maximumBrightnessParam) + getConfigParamInput(paddleControlParam) + input(type: "enum", name: "createButton", required: false, title: "Create Button for Paddles?", options: ["No", "Yes"], defaultValue:"Yes") + } +} + +private getConfigParamInput(param) { + if (param.range) { + input "configParam${param.num}", "number", title: "${param.name}:", required: false, defaultValue: "${param.value}", range: param.range + } else { + input "configParam${param.num}", "enum", title: "${param.name}:", required: false, defaultValue: "${param.value}", options: param.options + } +} + +private initialize() { + if (state.createButtonEnabled && !childDevices) { + try { + def child = addChildButton() + child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } catch (ex) { + log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) } + } else if (!state.createButtonEnabled && childDevices) { + removeChildButton(childDevices[0]) } } +private addChildButton() { + log.warn "Creating Button Device" + def child = addChildDevice( + "smartthings", + "Child Button", + "${device.deviceNetworkId}-2", + device.getHub().getId(), + [ + completedSetup: true, + isComponent: false, + label: "plugButton", + componentLabel: "${device.displayName[0..-8]} Button" + ] + ) + child?.sendEvent(name:"supportedButtonValues", value:JsonOutput.toJson(["pushed", "down", "down_2x", "up", "up_2x"]), displayed:false) + child?.sendEvent(name:"numberOfButtons", value:1, displayed:false) + sendButtonEvent("pushed") + return child +} + +private removeChildButton(child) { + try { + log.warn "Removing ${child.displayName}} " + deleteChildDevice(child.deviceNetworkId) + } catch (ex) { + log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.",ex) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd){ + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + logTrace "${cmd}" + def paddle = (cmd.sceneNumber == 1) ? "down" : "up" + def btnVal + switch (cmd.keyAttributes){ + case 0: + btnVal = paddle + break + case 1: + logDebug "Button released not supported" + break + case 2: + logDebug "Button held not supported" + break + case 3: + btnVal = paddle + "_2x" + break + } + + if (btnVal) { + sendButtonEvent(btnVal) + } + } + return [] +} + +private sendButtonEvent(value) { + if (childDevices) { + childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) + } +} + +def ping() { + logDebug "ping()..." + return [ switchMultilevelGetCmd() ] +} + +def refresh() { + logDebug "refresh()..." + refreshSyncStatus() + return [ switchMultilevelGetCmd() ] +} + +private switchMultilevelGetCmd() { + return secureCmd(zwave.switchMultilevelV3.switchMultilevelGet()) +} + def installed() { logDebug "installed()..." + if (isButtonAvailable()) { + state.createButtonEnabled = true + } sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) state.refreshConfig = true } @@ -113,6 +239,10 @@ def updated() { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } + if (isButtonAvailable()) { + state.createButtonEnabled = (safeToInt(settings?.createButton) != 0) + initialize() + } runIn(5, executeConfigureCmds, [overwrite: true]) } @@ -142,6 +272,11 @@ def executeConfigureCmds() { configParams.each { param -> def storedVal = getParamStoredValue(param.num) def paramVal = param.value + if (isButtonAvailable()) { + if ((param == paddleControlParam) && state.createButtonEnabled && (param.value == 2)) { + log.warn "Only 'pushed', 'up_2x', and 'down_2x' button events are supported when Paddle Control is set to Toggle." + } + } if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) @@ -225,22 +360,24 @@ private secureCmd(cmd) { private static getCommandClassVersions() { [ - 0x20: 1, // Basic - 0x26: 3, // Switch Multilevel - 0x55: 1, // Transport Service - 0x59: 1, // AssociationGrpInfo - 0x5A: 1, // DeviceResetLocally - 0x71: 3, // Notification - 0x6C: 1, // Supervision - 0x70: 1, // Configuration - 0x7A: 2, // FirmwareUpdateMd - 0x72: 2, // ManufacturerSpecific - 0x73: 1, // Powerlevel - 0x85: 2, // Association - 0x86: 1, // Version (2) - 0x8E: 2, // Multi Channel Association - 0x98: 1, // Security S0 - 0x9F: 1 // Security S2 + 0x20: 1, // Basic + 0x26: 3, // Switch Multilevel + 0x5B: 1, // CentralScene (3) + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x71: 3, // Notification + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 ] } @@ -263,10 +400,23 @@ private getConfigParams() { pushDimmingDurationParam, holdDimmingDurationParam, minimumBrightnessParam, - maximumBrightnessParam + maximumBrightnessParam, + paddleControlParam ] } +private static getPaddleControlOptions() { + return [ + "0":"Normal", + "1":"Reverse", + "2":"Toggle" + ] +} + +private getPaddleControlParam() { + return getParam(1, "Paddle Control", 1, 0, paddleControlOptions) +} + private getLedModeParam() { return getParam(2, "LED Indicator Mode", 1, 0, ledModeOptions) } @@ -284,11 +434,13 @@ private getNightLightParam() { } private getPowerFailureRecoveryParam() { - return getParam(8, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) + def defaultVal = isButtonAvailable()? 0:2 + return getParam(8, "Power Failure Recovery", 1, defaultVal, powerFailureRecoveryOptions) } private getPushDimmingDurationParam() { - return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, 2, null, "0..10") + def defaultVal = isButtonAvailable()? 1:2 + return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, defaultVal, null, "0..10") } private getHoldDimmingDurationParam() { @@ -382,13 +534,11 @@ private logTrace(msg) { def on() { logDebug "on()..." - return [ basicSetCmd(0xFF) ] } def off() { logDebug "off()..." - return [ basicSetCmd(0x00) ] } @@ -411,18 +561,14 @@ private basicSetCmd(val) { private switchMultilevelSetCmd(level, duration) { def levelVal = validateRange(level, 99, 0, 99) - def durationVal = validateRange(duration, 1, 0, 100) - return secureCmd(zwave.switchMultilevelV3.switchMultilevelSet(dimmingDuration: durationVal, value: levelVal)) } def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { logTrace "VersionReport: ${cmd}" - def subVersion = String.format("%02d", cmd.applicationSubVersion) def fullVersion = "${cmd.applicationVersion}.${subVersion}" - sendEvent(name: "firmwareVersion", value:fullVersion, displayed: true, type: null) return [] } @@ -441,10 +587,39 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelR private sendSwitchEvents(rawVal, type) { def switchVal = rawVal ? "on" : "off" - sendEvent(name: "switch", value:switchVal, displayed: true, type: type) - if (rawVal) { sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") } + if(isButtonAvailable()) { + def paddlesReversed = (paddleControlParam.value == 1) + if (state.createButtonEnabled && (type == "physical") && childDevices) { + if (paddleControlParam.value == 2) { + sendButtonEvent("pushed") + } else { + def btnVal = ((rawVal && !paddlesReversed) || (!rawVal && paddlesReversed)) ? "up" : "down" + def oldSwitch = device.currentValue("switch") + def oldLevel = device.currentValue("level") + if ((oldSwitch == "on") && (btnVal == "up") && (oldLevel > rawVal)) { + btnVal = "down" + } + sendButtonEvent(btnVal) + } + } + } +} + +private isButtonAvailable() { + if(device == null){ + log.error "isButtonAvailable device = null" + return true + }else{ + log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" + def v20 = "${device.rawDescription}".contains("model:EE02") + def v21 = "${device.rawDescription}".contains("model:EE04") + def v22 = "${device.rawDescription}".contains("model:BB02") + def v23 = "${device.rawDescription}".contains("model:BB04") + def v2 = v20||v21||v22||v23 + return v2 + } } \ No newline at end of file From acd639ec8da1ca6f1266b4356ea2dd14ef9dd985 Mon Sep 17 00:00:00 2001 From: "SmartThings, Inc" Date: Mon, 30 Aug 2021 15:32:21 -0700 Subject: [PATCH 033/184] DevWs for Sinope Technologies containing containing VA4200WZ-VA4200ZB Sinope Valve (#73935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aldéric Bourdeau-Guilbault --- .../va4200wz-va4200zb-sinope-valve.groovy | 322 ++++++++++-------- 1 file changed, 172 insertions(+), 150 deletions(-) diff --git a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy index 1cc0172b0e3..160c2a03334 100644 --- a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy +++ b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy @@ -1,6 +1,6 @@ /** Copyright Sinopé Technologies -1.3.0 +1.3.2 SVN-571 * 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. @@ -11,88 +11,88 @@ import physicalgraph.zigbee.zcl.DataType metadata { preferences { - input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") + input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") // input("logFilter", "number", title: "Trace level", range: "1..5", // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") - } - - definition (name: "VA4200WZ-VA4200ZB Sinope Valve", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.watervalve") { - capability "Configuration" - capability "Refresh" - capability "Actuator" - capability "Valve" - capability "Battery" - capability "Power Source" - capability "Health Check" - - fingerprint manufacturer: "Sinope Technologies", model: "VA4200WZ", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4200WZ - fingerprint manufacturer: "Sinope Technologies", model: "VA4200ZB", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4200ZB - fingerprint manufacturer: "Sinope Technologies", model: "VA4220ZB", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4220ZB - } - - tiles(scale: 2) { - multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){ - tileAttribute ("device.valve", key: "PRIMARY_CONTROL") { - attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" - attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" - attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" - attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" - } - tileAttribute ("powerSource", key: "SECONDARY_CONTROL") { - attributeState "powerSource", label:'Power Source: ${currentValue}' - } - } - - 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(["valve"]) - details(["valve", "battery", "refresh"]) - } + } + + definition (name: "VA4200WZ-VA4200ZB Sinope Valve", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.watervalve") { + capability "Configuration" + capability "Refresh" + capability "Actuator" + capability "Valve" + capability "Battery" + capability "Power Source" + capability "Health Check" + + fingerprint manufacturer: "Sinope Technologies", model: "VA4200WZ", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4200WZ + fingerprint manufacturer: "Sinope Technologies", model: "VA4200ZB", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4200ZB + fingerprint manufacturer: "Sinope Technologies", model: "VA4220ZB", deviceJoinName: "Sinope Valve", mnmn:"SmartThings", vid:"SmartThings-smartthings-ZigBee_Valve" //VA4220ZB + } + + tiles(scale: 2) { + multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute ("device.valve", key: "PRIMARY_CONTROL") { + attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" + attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" + attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" + attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" + } + tileAttribute ("powerSource", key: "SECONDARY_CONTROL") { + attributeState "powerSource", label:'Power Source: ${currentValue}' + } + } + + 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(["valve"]) + details(["valve", "battery", "refresh"]) + } } def open() { - zigbee.on() + zigbee.on() } def close() { - zigbee.off() + zigbee.off() } def refresh() { - traceEvent(settings.logFilter, "refresh called", settings.trace, get_LOG_DEBUG()) - def cmds = [] - cmds += zigbee.readAttribute(0x0006, 0x0000)//refresh on/off - cmds += zigbee.readAttribute(0x0000, 0x0007)//refresh power source - cmds += zigbee.readAttribute(0x0001, 0x0021)//refresh battery percentage remaining - cmds += zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null)//configure reporting on/off min: 0sec, max 600sec - cmds += zigbee.configureReporting(0x0001, 0x0021, 0x20, 60, 60*60, 1)//configure reporting battery percentage remaining min: 6sec, max 1hour - return sendZigbeeCommands(cmds) + traceEvent(settings.logFilter, "refresh called", settings.trace, get_LOG_DEBUG()) + def cmds = [] + cmds += zigbee.readAttribute(0x0006, 0x0000)//refresh on/off + cmds += zigbee.readAttribute(0x0000, 0x0007)//refresh power source + cmds += zigbee.readAttribute(0x0001, 0x0020)//refresh battery voltage remaining + cmds += zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null)//configure reporting on/off min: 0sec, max 600sec + cmds += zigbee.configureReporting(0x0001, 0x0020, 0x20, 60, 60*60, 1)//configure reporting battery voltage remaining min: 6sec, max 1hour + return sendZigbeeCommands(cmds) } def configure() { - traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) + traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) - //allow 15 minutes withour receiving on/off state + //allow 15 minutes withour receiving on/off state sendEvent(name: "checkInterval", value: 15*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - refresh() + refresh() } def installed() { traceEvent(settings.logFilter, "installed>Device is now Installed", settings.trace) initialize() } -def initialize(){ +def initialize() { traceEvent(settings.logFilter, "device is initializing", settings.trace) runEvery15Minutes(refreshPowerSource)//the POWER_SOURCE attribute is not reportable. - runIn(10,refreshPowerSource) - refresh() + runIn(10,refreshPowerSource) + refresh() } /** @@ -105,42 +105,42 @@ def ping() { // Parse incoming device messages to generate events def parse(String description) { - traceEvent(settings.logFilter, "description is $description", settings.trace, get_LOG_DEBUG()) - def result = [] - def event = zigbee.getEvent(description) - if(event){ - if(event.name == "switch") { - event.name = "valve" - if(event.value == "on") { - event.value = "open" - } - else if(event.value == "off") { - event.value = "closed" - } - sendEvent(name: "checkInterval", value: 15*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - } - sendEvent(event) - } - else{ - Map map = [:] - if (description?.startsWith('catchall:')) { - map = parseCatchAllMessage(description) - } - else if (description?.startsWith('read attr -')) { - map = parseReportAttributeMessage(description) - } - - if(map){ - result += createEvent(map) - if(map.additionalAttrs){ - def additionalAttrs = map.additionalAttrs - additionalAttrs.each{allMaps -> - result += createEvent(allMaps) - } - } - } - } - + traceEvent(settings.logFilter, "description is $description", settings.trace, get_LOG_DEBUG()) + def result = [] + def event = zigbee.getEvent(description) + if (event) { + if (event.name == "switch") { + event.name = "valve" + if (event.value == "on") { + event.value = "open" + } + else if (event.value == "off") { + event.value = "closed" + } + sendEvent(name: "checkInterval", value: 15*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + } + sendEvent(event) + } + else { + Map map = [:] + if (description?.startsWith('catchall:')) { + map = parseCatchAllMessage(description) + } + else if (description?.startsWith('read attr -')) { + map = parseReportAttributeMessage(description) + } + + if (map) { + result += createEvent(map) + if (map.additionalAttrs) { + def additionalAttrs = map.additionalAttrs + additionalAttrs.each{allMaps -> + result += createEvent(allMaps) + } + } + } + } + return result } @@ -148,29 +148,29 @@ private Map parseCatchAllMessage(String description) { Map resultMap = [:] def cluster = zigbee.parse(description) if (shouldProcessMessage(cluster)) { - traceEvent(settings.logFilter, "parseCatchAllMessage > $cluster", settings.trace) + traceEvent(settings.logFilter, "parseCatchAllMessage > $cluster", settings.trace) switch(cluster.clusterId) { - case 0x0000://power source - // 0x07 - configure reporting - if (cluster.command != 0x07) { + case 0x0000://power source + // 0x07 - configure reporting + if (cluster.command != 0x07) { resultMap = getPowerSourceResult(cluster.data.last()) } - break + break case 0x0001://battery percentage remaining // 0x07 - configure reporting if (cluster.command != 0x07) { resultMap = getBatteryResult(cluster.data.last()) } break - case 0x0006://on/off - //0x07 - configure reporting - if (cluster.command != 0x07) { + case 0x0006://on/off + //0x07 - configure reporting + if (cluster.command != 0x07 && cluster.data.length) { resultMap = getOnOffResult(cluster.data.last()) } - break - } - } - return resultMap + break + } + } + return resultMap } private boolean shouldProcessMessage(cluster) { @@ -182,84 +182,79 @@ private boolean shouldProcessMessage(cluster) { } private Map parseReportAttributeMessage(String description) { - Map descMap = zigbee.parseDescriptionAsMap(description) + Map descMap = zigbee.parseDescriptionAsMap(description) traceEvent(settings.logFilter, "Desc Map: $descMap" + cluster, settings.trace, get_LOG_DEBUG()) Map resultMap = [:] if (descMap.cluster == "0000" && descMap.attrId == "0007") { resultMap = getPowerSourceResult(descMap.value) } - else if (descMap.cluster == "0001" && descMap.attrId == "0021") { - resultMap = getBatteryResult(zigbee.convertHexToInt(descMap.value)) + else if (descMap.cluster == "0001" && descMap.attrId == "0020") { + resultMap = getBatteryResult(zigbee.convertHexToInt(descMap.value)) } - else if (descMap.cluster == "0006" && descMap.attrId == "0000") { - resultMap = getOnOffResult(descMap.value) + else if (descMap.cluster == "0006" && descMap.attrId == "0000") { + resultMap = getOnOffResult(descMap.value) } return resultMap } private Map getBatteryResult(rawValue) { - traceEvent(settings.logFilter, "Battery rawValue = ${rawValue}" + cluster, settings.trace, get_LOG_DEBUG()) + traceEvent(settings.logFilter, "Battery rawValue = ${rawValue}" + cluster, settings.trace, get_LOG_DEBUG()) def result = [:] - result.name = 'battery' - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - - int batteryPercent = rawValue / 2 - result.value = Math.min(100, batteryPercent) + result.name = 'battery' + result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" + result.value = convertVoltToPercent(rawValue) return result } private Map getOnOffResult(rawValue) { - traceEvent(settings.logFilter, "On/Off rawValue = ${rawValue}" + cluster, settings.trace, get_LOG_DEBUG()) + traceEvent(settings.logFilter, "On/Off rawValue = ${rawValue}" + cluster, settings.trace, get_LOG_DEBUG()) Map result = [:] - result.name = 'valve' - result.descriptionText = "{{ device.displayName }} state was {{ value }}" - if(rawValue == "0000"){ - result.value == "off" - } - else{ - result.value == "on" - } - - List addAttribsList = [] - Map addAttrib = [:] - - addAttrib.name = 'valve' + result.name = 'valve' + result.descriptionText = "{{ device.displayName }} state was {{ value }}" + if (rawValue == "0000") { + result.value == "off" + } + else { + result.value == "on" + } + + List addAttribsList = [] + Map addAttrib = [:] + + addAttrib.name = 'valve' addAttrib.descriptionText = "{{ device.displayName }} state was {{ value }}" addAttrib.value = result.value addAttribsList += addAttrib result.additionalAttrs = addAttribsList - + return result } private Map getPowerSourceResult(rawValue) { traceEvent(settings.logFilter, "powerSource rawValue = ${rawValue}" + cluster, settings.trace, get_LOG_DEBUG()) def result = [:] - result.name = 'powerSource' - result.translatable = true - result.descriptionText = "{{ device.displayName }} powerSource was {{ value }}%" - if(rawValue == "0081" || rawValue == "0082"){ - result.value = "mains" - } - else if(rawValue == "0003"){ - result.value = "battery" - } - else if(rawValue == "0004"){ - result.value = "dc" - } - else{ - result.value = "unknown" - } + result.name = 'powerSource' + result.translatable = true + result.descriptionText = "{{ device.displayName }} powerSource was {{ value }}%" + if (rawValue == "0081" || rawValue == "0082") { + result.value = "mains" + } else if (rawValue == "0003") { + result.value = "battery" + } else if (rawValue == "0004") { + result.value = "dc" + } else { + result.value = "unknown" + } return result } -def refreshPowerSource(){ - def cmds = [] - cmds += zigbee.readAttribute(0x0000, 0x0007)//read power source attribute +def refreshPowerSource() { + def cmds = [] + cmds += zigbee.readAttribute(0x0000, 0x0007)//read power source attribute return sendZigbeeCommands(cmds) } @@ -286,6 +281,33 @@ private int get_LOG_TRACE() { return 5 } +private def convertVoltToPercent(value) { + def levelValue; + def levelsTable = [0, 20000, 40000, 60000, 80000, 100000]; + def anglesTable = [30, 55, 56, 57, 58.5, 60]; + + if (value > anglesTable[anglesTable.size - 1]) { // if the value of the angle is greater than the maximum + value = anglesTable[anglesTable.size - 1]; // use the maximum value instead + } + + def index = 1; + + while ( value > anglesTable[index]) { index++ } + + def ratioBetweenPointXandY = (levelsTable[index] - levelsTable[index - 1]) / (anglesTable[index] - anglesTable[index - 1]); + def angleToAdd = levelsTable[index] - (anglesTable[index] * ratioBetweenPointXandY); + def levelWithFactor = (ratioBetweenPointXandY * value) + angleToAdd; + def roundedLevelValue = Math.round(levelWithFactor / 1000); + + if (roundedLevelValue > 100) { + return 100 + } else if (roundedLevelValue < 0) { + return 0 + } else { + return roundedLevelValue; + } +} + def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMessage = true) { int LOG_ERROR = get_LOG_ERROR() int LOG_WARN = get_LOG_WARN() From c6e496cbe0956068a97688f7231b826baf2f3ed3 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Wed, 1 Sep 2021 03:37:37 -0400 Subject: [PATCH 034/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZSE42 XS Water Leak Sensor (#74778) * DevWs for Zooz (The Smartest House) containing containing Zooz ZSE42 XS Water Leak Sensor * Added fingerprint for Zooz ZSE42 XS Water Leak Sensor * Delete zooz-zse42-xs-water-leak-sensor.groovy * Moved raw description above fingerprint --- .../zwave-water-sensor.groovy | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy b/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy index 86e57ec9995..47b6a39d7c6 100644 --- a/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy +++ b/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy @@ -33,6 +33,8 @@ metadata { fingerprint mfr: "000C", prod: "0201", model: "000A", deviceJoinName: "HomeSeer Water Leak Sensor" //HomeSeer LS100+ Water Sensor //zw:Ss2 type:0701 mfr:0173 prod:4C47 model:4C44 ver:1.10 zwv:4.61 lib:03 cc:5E,55,98,9F sec:86,71,85,59,72,5A,6C,7A,84,80 fingerprint mfr: "0173", prod: "4C47", model: "4C44", deviceJoinName: "Leak Gopher Water Leak Sensor" //Leak Intelligence Leak Gopher Z-Wave Leak Detector + //zw:Ss2a type:0701 mfr:027A prod:7000 model:E002 ver:1.05 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,87,73,80,71,30,70,84,7A + fingerprint mfr: "027A", prod: "7000", model: "E002", deviceJoinName: "Zooz Water Leak Sensor" //Zooz ZSE42 XS Water Leak Sensor } simulator { @@ -60,8 +62,8 @@ metadata { } def initialize() { - if (isAeotec() || isNeoCoolcam() || isDome() || isLeakGopher()) { - // 8 hour (+ 2 minutes) ping for Aeotec, NEO Coolcam, Dome, Leak Gopher + if (isAeotec() || isNeoCoolcam() || isDome() || isLeakGopher() || isZooz()) { + // 8 hour (+ 2 minutes) ping for Aeotec, NEO Coolcam, Dome, Leak Gopher, Zooz sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } else { // 12 hours (+ 2 minutes) for other devices @@ -92,8 +94,8 @@ def configure() { // Tell sensor to send us battery information instead of USB power information commands << encap(zwave.configurationV1.configurationSet(parameterNumber: 0x5E, scaledConfigurationValue: 1, size: 1)) response(delayBetween(commands, 1000) + ["delay 20000", encap(zwave.wakeUpV1.wakeUpNoMoreInformation())]) - } else if (isNeoCoolcam() || isDome() || isLeakGopher()) { - // wakeUpInterval set to 4 h for NEO Coolcam, Dome, Leak Gopher + } else if (isNeoCoolcam() || isDome() || isLeakGopher() || isZooz()) { + // wakeUpInterval set to 4 h for NEO Coolcam, Dome, Leak Gopher, Zooz zwave.wakeUpV1.wakeUpIntervalSet(seconds: 4 * 3600, nodeid: zwaveHubNodeId).format() } } @@ -332,4 +334,8 @@ private isAeotec() { private isLeakGopher() { zwaveInfo.mfr == "0173" && zwaveInfo.model == "4C44" +} + +private isZooz() { + zwaveInfo.mfr == "027A" && zwaveInfo.model == "E002" } \ No newline at end of file From 5970bf2a4128e8edc4e445e9aa682647e1540392 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Wed, 1 Sep 2021 03:38:29 -0400 Subject: [PATCH 035/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZSE41 XS Open Close Sensor (#74779) * DevWs for Zooz (The Smartest House) containing containing Zooz ZSE41 XS Open Close Sensor * Added fingerprint for Zooz ZSE41 XS Open | Close Sensor * Delete zooz-zse41-xs-open-close-sensor.groovy * Moved raw description above fingerprint --- .../zwave-door-window-sensor.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 0afaf53a7ea..53a98366159 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 @@ -64,6 +64,8 @@ metadata { fingerprint mfr: "0371", prod: "0202", model: "000C", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //AU //Aeotec Door/Window Sensor 7 Pro fingerprint mfr: "0371", prod: "0002", model: "000B", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //EU //Aeotec Door/Window Sensor 7 zw:Ss2a type:0701 mfr:0371 prod:0002 model:000B ver:1.01 zwv:7.12 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,87,73,80,70,71,84,7A fingerprint mfr: "0371", prod: "0102", model: "000B", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //US //Aeotec Door/Window Sensor 7 zw:Ss2a type:0701 mfr:0371 prod:0102 model:000B ver:1.01 zwv:7.12 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,87,73,80,70,71,84,7A + //zw:Ss2a type:0701 mfr:027A prod:7000 model:E001 ver:1.05 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,87,73,80,71,30,70,84,7A + fingerprint mfr: "027A", prod: "7000", model: "E001", deviceJoinName: "Zooz Open/Closed Sensor" //Zooz ZSE41 XS Open Close Sensor } // simulator metadata @@ -384,4 +386,4 @@ private isEnerwave() { def clearTamper() { sendEvent(name: "tamper", value: "clear") -} +} \ No newline at end of file From 413e2049eebb2548b546d16593bbe3c7ebd1fd37 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Wed, 1 Sep 2021 03:42:05 -0400 Subject: [PATCH 036/184] DevWs for Zooz (The Smartest House) containing containing Fortrezz Water Valve (#74860) * DevWs for Zooz (The Smartest House) containing containing Fortrezz Water Valve * Added raw description to Zooz fingerprint * Moved raw description above fingerprint --- .../fortrezz-water-valve.src/fortrezz-water-valve.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy b/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy index 6b91427a1d9..abfd74f546a 100644 --- a/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy +++ b/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy @@ -21,6 +21,8 @@ metadata { fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70", deviceJoinName: "FortrezZ Valve" fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Valve" //FortrezZ Water Valve + //zw:Ls2a type:1000 mfr:027A prod:0101 model:0036 ver:1.07 zwv:7.13 lib:03 cc:5E,55,98,9F,6C,22 sec:25,85,8E,59,71,86,72,5A,87,73,7A,31,70,80 + fingerprint mfr:"027A", prod:"0101", model:"0036", deviceJoinName: "Zooz Valve" //Zooz ZAC36 Titan Valve Actuator } // simulator metadata @@ -114,4 +116,4 @@ def createEventWithDebug(eventMap) { def event = createEvent(eventMap) log.debug "Event created with ${event?.name}:${event?.value} - ${event?.descriptionText}" return event -} +} \ No newline at end of file From f60379c389aafcc2f78935189c28a1a030a51273 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:46:58 -0700 Subject: [PATCH 037/184] DevWs for Smartenit, Inc containing containing Smartenit Open/Closed Sensor (#71536) * DevWs for Smartenit, Inc containing containing Smartenit Open/Closed Sensor * Adding Smartenit fingerprint to smartsense DTH * Added raw description to Smartenit finger print --- .../smartsense-open-closed-sensor.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy index 1428c938e98..dc680d8b68f 100644 --- a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy +++ b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy @@ -45,6 +45,8 @@ metadata { fingerprint inClusters: "0000, 0003, 0006, 0500", outClusters: "0003, 0019", manufacturer: "DAWON_DNS", model: "SS-B100-ZB", deviceJoinName: "Dawon Signal Interlock", mnmn: "0AIg", vid: "dawon-zigbee-signal-interlock2" fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,000F,0020,0500", outClusters: "000A,0019", manufacturer: "frient A/S", model :"WISZB-120", deviceJoinName: "frient Open/Closed Sensor" fingerprint manufacturer: "frient A/S", model :"WISZB-121", deviceJoinName: "frient Open/Closed Sensor", mnmn: "SmartThingsCommunity", vid: "aaca16c3-fade-3cb3-b742-e2237f4ffd76" // Raw description: 23 0104 0402 00 06 0000 0001 0003 000F 0020 0500 02 000A 0019 + //Smartenit + fingerprint manufacturer: "Compacta", model :"ZBWDS", deviceJoinName: "Smartenit Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact" // Raw description: 01 0104 0000 00 04 0000 0001 0003 0007 01 0006 } simulator { @@ -245,4 +247,4 @@ private Boolean isBoschRadionMultiSensor() { private Boolean isFrientSensor() { device.getDataValue("manufacturer") == "frient A/S" -} +} \ No newline at end of file From 8c943970299c2c97e73dcb6a15b2ecef8714a91b Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:49:26 -0700 Subject: [PATCH 038/184] DevWs for Smartenit, Inc containing containing Smartenit Motion Sensor (#71621) * DevWs for Smartenit, Inc containing containing Smartenit Motion Sensor * Adding Smartenit fingerprint to smartsense motion sensor DTH * Added raw description to Smartenit motion sensor model --- .../smartsense-motion-sensor.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) 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 9f7746c193e..4ccddb0f3b5 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -46,6 +46,8 @@ metadata { fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "AduroSmart Eria", model: "VMS_ADUROLIGHT", deviceJoinName: "ERIA Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2" //ERIA Motion Sensor V2.1 fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,000F,0020,0500", outClusters: "000A,0019", manufacturer: "frient A/S", model :"MOSZB-140", deviceJoinName: "frient Motion Sensor" fingerprint manufacturer: "frient A/S", model :"MOSZB-141", deviceJoinName: "frient Motion Sensor", mnmn: "SmartThingsCommunity", vid: "87753fce-8cd6-3b91-8bde-2483e564252d" // Raw description: 22 0104 0107 00 03 0000 0003 0406 00 + //Smartenit + fingerprint manufacturer: "Compacta", model: "ZBMS3-1", deviceJoinName: "Smartenit Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" // Raw description: 01 0104 0402 00 07 0000 0001 0003 0015 0500 0020 0B05 00 } simulator { @@ -324,6 +326,8 @@ def configure() { if (isFrientSensor()) { configCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 30, 300, 0x64, [destEndpoint: 0x26]) + } else if (isCompactaSensor()) { + configCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 30, 300, 0x64, [destEndpoint: 0x0003]) } else { configCmds += zigbee.temperatureConfig(30, 300) } @@ -355,3 +359,7 @@ private shouldUseOldBatteryReporting() { private Boolean isFrientSensor() { device.getDataValue("manufacturer") == "frient A/S" } + +private Boolean isCompactaSensor() { + device.getDataValue("manufacturer") == "Compacta" +} \ No newline at end of file From e979df75b9a3b4c0ee859da0d9916121da4063fa Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:51:57 -0700 Subject: [PATCH 039/184] DevWs for Smartenit, Inc containing containing Smartenit Valve (#72090) * DevWs for Smartenit, Inc containing containing Smartenit Valve * Adding Smartenit fingerprint to Zigbee Valve DTH * Added Raw Description for Smartenit model/fixed spacing issue. --- devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy b/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy index a60797ac468..3fac110ab18 100644 --- a/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy +++ b/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy @@ -27,6 +27,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0006, 0020, 0B02, FC02", outClusters: "0019", manufacturer: "WAXMAN", model: "leakSMART Water Valve v2.10", deviceJoinName: "leakSMART Valve" //leakSMART Valve fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0006, 0008, 000F, 0020, 0B02", outClusters: "0003, 0019", manufacturer: "WAXMAN", model: "House Water Valve - MDL-TBD", deviceJoinName: "Waxman Valve" //Waxman House Water Valve fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006, 0500", outClusters: "0019", manufacturer: "", model: "E253-KR0B0ZX-HA", deviceJoinName: "Valve" //Smart Gas Valve Actuator + fingerprint manufacturer: "Compacta", model: "ZBVC1(1023A)", deviceJoinName: "Smartenit Valve" // Raw Description: 01 0104 0002 00 06 0000 0003 0004 0005 0006 0015 00 } // simulator metadata @@ -153,4 +154,4 @@ def installed() { def ping() { zigbee.onOffRefresh() -} +} \ No newline at end of file From 7abc94d90c71852cd082f0689b02226e14c9ba50 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:55:48 -0700 Subject: [PATCH 040/184] DevWs for Smartenit, Inc containing containing ZBALRM (#71537) * DevWs for Smartenit, Inc containing containing ZBALRM * Adding Smartenit fingerprint to Ozom siren DTH * Added raw description to Smartenit model --- .../ozom-smart-siren.groovy | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy b/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy index 9f2d044d2c7..e52f9b25d7b 100644 --- a/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy +++ b/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy @@ -28,6 +28,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000,0003,0500,0502", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "SRAC_00.00.00.16TC", mnmn: "SmartThings", vid: "generic-siren-8", deviceJoinName: "Ozom Siren" // Ozom Siren - SRAC-23ZBS //Ozom Smart Siren fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0009,0500,0502", outClusters: "0003,0019", manufacturer: "Heiman", model: "WarningDevice", mnmn: "SmartThings", vid: "generic-siren-8", deviceJoinName: "HEIMAN Siren" //HEIMAN Smart Siren fingerprint manufacturer: "frient A/S", model :"SIRZB-110", deviceJoinName: "frient Siren", mnmn: "SmartThingsCommunity", vid: "33d3bbac-144c-3a31-b022-0fc5c74240a3" // frient Smart Siren, 2B 0104 0403 00 05 0000 0003 0502 0500 0001 02 000A 0019 + fingerprint model: "ZBALRM", manufacturer: "Compacta", deviceJoinName: "Smartenit Alarm", mnmn: "SmartThings" // Raw Description: 01 0104 0403 00 07 0000 0001 0003 0015 0500 0502 0B05 00 } tiles { @@ -54,7 +55,9 @@ private getCOMMAND_DEFAULT_RESPONSE() { 0x0B } private getMODE_SIREN() { "13" } private getMODE_STROBE() { "04" } +private getMODE_SMARTENIT_STROBE() { "DF" } private getMODE_BOTH() { "17" } +private getMODE_SMARTENIT_BOTH() { "1A" } private getMODE_OFF() { "00" } private getSTROBE_DUTY_CYCLE() { "40" } private getSTROBE_LEVEL() { "03" } @@ -179,11 +182,23 @@ def startCmd(cmd) { paramDutyCycle = BASIC_DUTY_CYCLE paramStrobeLevel = BASIC_LEVEL } else if (cmd == ALARM_STROBE) { - paramMode = isFrientSiren() ? FRIENT_MODE_SIREN : MODE_STROBE + if (isFrientSiren()) { + paramMode = FRIENT_MODE_SIREN + } else if (isCompactaSiren()) { + paramMode = MODE_SMARTENIT_STROBE + } else { + paramMode = MODE_STROBE + } paramDutyCycle = isFrientSiren() ? BASIC_DUTY_CYCLE : STROBE_DUTY_CYCLE paramStrobeLevel = isFrientSiren() ? BASIC_LEVEL : STROBE_LEVEL } else if (cmd == ALARM_BOTH) { - paramMode = isFrientSiren() ? FRIENT_MODE_SIREN : MODE_BOTH + if (isFrientSiren()) { + paramMode = FRIENT_MODE_SIREN + } else if (isCompactaSiren()) { + paramMode = MODE_SMARTENIT_BOTH + } else { + paramMode = MODE_BOTH + } paramDutyCycle = isFrientSiren() ? BASIC_DUTY_CYCLE : STROBE_DUTY_CYCLE paramStrobeLevel = isFrientSiren() ? BASIC_LEVEL : STROBE_LEVEL } @@ -215,3 +230,7 @@ private isOzomSiren() { private Boolean isFrientSiren() { device.getDataValue("manufacturer") == "frient A/S" } + +private Boolean isCompactaSiren() { + device.getDataValue("manufacturer") == "Compacta" +} \ No newline at end of file From 4b42c34eb0fc12753ea143f00cea244465174696 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Thu, 2 Sep 2021 22:50:21 +0900 Subject: [PATCH 041/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#74527) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * A unnecessary empty tab was deleted * Changed parse method for analoginput(DataType.FLOAT4) value. --- .../sihas-multipurpose-sensor.groovy | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index 2a2e83616df..e193f5b6e30 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -28,11 +28,13 @@ metadata { capability "Health Check" capability "Sensor" capability "Contact Sensor" - + capability "afterguide46998.peopleCounter" + fingerprint inClusters: "0000,0001,0003,0020,0400,0402,0405,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "USM-300Z", deviceJoinName: "SiHAS MultiPurpose Sensor", mnmn: "SmartThings", vid: "generic-motion-6" fingerprint inClusters: "0000,0001,0003,0020,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "OSM-300Z", deviceJoinName: "SiHAS Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2", ocfDeviceType: "x.com.st.d.sensor.motion" fingerprint inClusters: "0000,0003,0402,0001,0405", outClusters: "0004,0003,0019", manufacturer: "ShinaSystem", model: "TSM-300Z", deviceJoinName: "SiHAS Temperature/Humidity Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Temp/Humidity_Sensor", ocfDeviceType: "oic.d.thermostat" fingerprint inClusters: "0000,0001,0003,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "DSM-300Z", deviceJoinName: "SiHAS Contact Sensor", mnmn: "SmartThings", vid: "generic-contact-3", ocfDeviceType: "x.com.st.d.sensor.contact" + fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "b4e6d6e1-65e2-3f2e-8167-8ddd820f578e", ocfDeviceType: "x.com.st.d.sensor.motion" } preferences { section { @@ -44,11 +46,13 @@ metadata { private getILLUMINANCE_MEASUREMENT_CLUSTER() { 0x0400 } private getOCCUPANCY_SENSING_CLUSTER() { 0x0406 } +private getANALOG_INPUT_BASIC_CLUSTER() { 0x000C } private getPOWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE() { 0x0020 } private getTEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 } private getRALATIVE_HUMIDITY_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 } private getILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 } private getOCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE() { 0x0000 } +private getANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE() { 0x0055 } private List collectAttributes(Map descMap) { List descMaps = new ArrayList() @@ -79,6 +83,8 @@ def parse(String description) { map = translateZoneStatus(zs) } else if (descMap?.clusterInt == OCCUPANCY_SENSING_CLUSTER && descMap.attrInt == OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE && descMap?.value) { map = getMotionResult(descMap.value == "01" ? "active" : "inactive") + } else if (descMap?.clusterInt == ANALOG_INPUT_BASIC_CLUSTER && descMap.attrInt == ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE && descMap?.value) { + map = getAnalogInputResult(Integer.parseInt(descMap.value,16)) } } else if (description?.startsWith('illuminance:')) { //parse illuminance map = parseCustomMessage(description) @@ -191,6 +197,18 @@ private Map getContactResult(value) { ] } +private Map getAnalogInputResult(value) { + Float f = Float.intBitsToFloat(value.intValue()) + int pc = f.round(0) + String descriptionText = "${device.displayName} : $pc" + return [ + name : 'peopleCounter', + value : pc, + descriptionText: descriptionText, + translatable : true + ] +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ @@ -257,9 +275,12 @@ def configure() { } if (isDSM300()) { - configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE, DataType.UINT8, 30, 21600, 0x01/*100mv*1*/) configCmds += zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 0, 0xffff, null) } + + if (isCSM300()) { + configCmds += zigbee.configureReporting(ANALOG_INPUT_BASIC_CLUSTER, ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE, DataType.FLOAT4, 1, 600, 1) + } return refresh() + configCmds } @@ -279,3 +300,7 @@ private Boolean isOSM300() { private Boolean isDSM300() { device.getDataValue("model") == "DSM-300Z" } + +private Boolean isCSM300() { + device.getDataValue("model") == "CSM-300Z" +} From b32d855a24d0533638bfce590750665061255b89 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Fri, 3 Sep 2021 09:09:07 +0800 Subject: [PATCH 042/184] * - Syntax format compliance adjustment * - fix some bugs --- .../child-button.src/child-button.groovy | 53 +++++++++++++++++++ .../min-smart-plug-dimmer.groovy | 52 +++++------------- 2 files changed, 67 insertions(+), 38 deletions(-) create mode 100644 devicetypes/sky-nie/child-button.src/child-button.groovy diff --git a/devicetypes/sky-nie/child-button.src/child-button.groovy b/devicetypes/sky-nie/child-button.src/child-button.groovy new file mode 100644 index 00000000000..a3e0c370ceb --- /dev/null +++ b/devicetypes/sky-nie/child-button.src/child-button.groovy @@ -0,0 +1,53 @@ +/** + * Child Button v1.0 (CHILD DEVICE) + * + * Author: + * winnie (sky-nie) + * + * Changelog: + * + * 1.0 (03/16/2020) + * - Initial Release + * + * Reference: + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/component-button.src/component-button.groovy + * + * 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: "Child Button", namespace: "sky-nie", author: "winnie", ocfDeviceType: "x.com.st.d.remotecontroller") { + capability "Button" + capability "Sensor" + } + + tiles(scale: 2) { + multiAttributeTile(name: "button", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.button", key: "PRIMARY_CONTROL") { + attributeState "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff" + } + } + main "button" + details(["button"]) + } +} + +def installed() { + log.debug "installed()..." +} + +def updated() { + log.debug "updated()..." +} + +def uninstalled() { + log.warn "uninstalled()..." +} \ No newline at end of file diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 89f80b3ed0b..4cbf1e48e73 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v2.0.1 + * Min Smart Plug Dimmer v2.0.2 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,7 @@ * * Changelog: * + * 2.0.2 (09/02/2021) * 2.0.1 (08/27/2021) * - Syntax format compliance adjustment * - fix some bugs @@ -74,6 +75,7 @@ import groovy.json.JsonOutput metadata { definition (name: "Min Smart Plug Dimmer", namespace: "sky-nie", author: "winnie", ocfDeviceType: "oic.d.smartplug") { capability "Actuator" + capability "Sensor" capability "Switch" capability "Switch Level" capability "Configuration" @@ -87,8 +89,8 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Dimmer Switch" //MP21ZD fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Dimmer Switch" //MP22ZD fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Dimmer Switch" //N4002 - fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS11ZS Minoston Smart Dimmer Switch - fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS13ZS Minoston Smart Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS11ZS Minoston Smart Dimmer Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS13ZS Minoston Smart Toggle Dimmer Switch fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31S Evalogik Smart Dimmer Switch fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31TS Evalogik Smart Toggle Dimmer Switch } @@ -132,15 +134,13 @@ private initialize() { } catch (ex) { log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) } - } else if (!state.createButtonEnabled && childDevices) { - removeChildButton(childDevices[0]) } } private addChildButton() { log.warn "Creating Button Device" def child = addChildDevice( - "smartthings", + "sky-nie", "Child Button", "${device.deviceNetworkId}-2", device.getHub().getId(), @@ -157,31 +157,16 @@ private addChildButton() { return child } -private removeChildButton(child) { - try { - log.warn "Removing ${child.displayName}} " - deleteChildDevice(child.deviceNetworkId) - } catch (ex) { - log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.",ex) - } -} - -def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd){ +def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { if (state.lastSequenceNumber != cmd.sequenceNumber) { state.lastSequenceNumber = cmd.sequenceNumber logTrace "${cmd}" def paddle = (cmd.sceneNumber == 1) ? "down" : "up" def btnVal - switch (cmd.keyAttributes){ + switch (cmd.keyAttributes) { case 0: btnVal = paddle break - case 1: - logDebug "Button released not supported" - break - case 2: - logDebug "Button held not supported" - break case 3: btnVal = paddle + "_2x" break @@ -233,7 +218,6 @@ private static def getCheckInterval() { def updated() { if (!isDuplicateCommand(state.lastUpdated, 5000)) { state.lastUpdated = new Date().time - logDebug "updated()..." if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) @@ -245,7 +229,6 @@ def updated() { } runIn(5, executeConfigureCmds, [overwrite: true]) } - return [] } @@ -331,7 +314,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport logDebug "${param.name}(#${param.num}) = ${val}" state["configParam${param.num}"] = val } else { - logDebug "Parameter #${cmd.parameterNumber} = ${cmd.configurationValue}" + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" } return [] } @@ -457,7 +440,6 @@ private getMaximumBrightnessParam() { private getParam(num, name, size, defaultVal, options=null, range=null) { def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) - def map = [num: num, name: name, size: size, value: val] if (options) { map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value @@ -466,7 +448,6 @@ private getParam(num, name, size, defaultVal, options=null, range=null) { if (range) { map.range = range } - return map } @@ -591,7 +572,7 @@ private sendSwitchEvents(rawVal, type) { if (rawVal) { sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") } - if(isButtonAvailable()) { + if (isButtonAvailable()) { def paddlesReversed = (paddleControlParam.value == 1) if (state.createButtonEnabled && (type == "physical") && childDevices) { if (paddleControlParam.value == 2) { @@ -610,16 +591,11 @@ private sendSwitchEvents(rawVal, type) { } private isButtonAvailable() { - if(device == null){ + if (device == null) { log.error "isButtonAvailable device = null" return true - }else{ + } else { log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" - def v20 = "${device.rawDescription}".contains("model:EE02") - def v21 = "${device.rawDescription}".contains("model:EE04") - def v22 = "${device.rawDescription}".contains("model:BB02") - def v23 = "${device.rawDescription}".contains("model:BB04") - def v2 = v20||v21||v22||v23 - return v2 + return "${device.rawDescription}".contains("model:EE02") || "${device.rawDescription}".contains("model:EE04") ||"${device.rawDescription}".contains("model:BB02") || "${device.rawDescription}".contains("model:BB04") } -} \ No newline at end of file +} From 2b2190378c37bcb6d5c4c76ccebf273eb41b5ea4 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Fri, 3 Sep 2021 09:28:23 +0800 Subject: [PATCH 043/184] Syntax format compliance adjustment --- .../min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 4cbf1e48e73..ef95d05c65c 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -596,6 +596,6 @@ private isButtonAvailable() { return true } else { log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" - return "${device.rawDescription}".contains("model:EE02") || "${device.rawDescription}".contains("model:EE04") ||"${device.rawDescription}".contains("model:BB02") || "${device.rawDescription}".contains("model:BB04") + return "${device.rawDescription}".contains("model:EE02") || "${device.rawDescription}".contains("model:EE04") || "${device.rawDescription}".contains("model:BB02") || "${device.rawDescription}".contains("model:BB04") } } From 99c246b0d7bf7a4d075461fc1f2efec74caf6c20 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Fri, 3 Sep 2021 10:55:28 +0800 Subject: [PATCH 044/184] 1.restore removeChildButton; 2.Simplify the code --- .../min-smart-plug-dimmer.groovy | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index ef95d05c65c..cf824d1b3cb 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -127,12 +127,24 @@ private getConfigParamInput(param) { } private initialize() { - if (state.createButtonEnabled && !childDevices) { - try { - def child = addChildButton() - child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - } catch (ex) { - log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + if (isButtonAvailable()) { + state.createButtonEnabled = (safeToInt(settings?.createButton) != 0) + if (state.createButtonEnabled && !childDevices) { + try { + def child = addChildButton() + child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } catch (ex) { + log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) + } + } else if (!state.createButtonEnabled && childDevices) { + removeChildButton(childDevices[0]) + } + } else { + if (childDevices) { + removeChildButton(childDevices[0]) } } } @@ -206,7 +218,22 @@ def installed() { state.createButtonEnabled = true } sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - state.refreshConfig = true +} + +def uninstalled() { + logger("debug", "uninstalled()") + if (childDevices) { + removeChildButton(childDevices[0]) + } +} + +private removeChildButton(child) { + try { + log.warn "Removing ${child.displayName}} " + deleteChildDevice(child.deviceNetworkId) + } catch (ex) { + log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.", ex) + } } private static def getCheckInterval() { @@ -219,14 +246,7 @@ def updated() { if (!isDuplicateCommand(state.lastUpdated, 5000)) { state.lastUpdated = new Date().time logDebug "updated()..." - if (device.latestValue("checkInterval") != checkInterval) { - sendEvent(name: "checkInterval", value: checkInterval, displayed: false) - } - - if (isButtonAvailable()) { - state.createButtonEnabled = (safeToInt(settings?.createButton) != 0) - initialize() - } + initialize() runIn(5, executeConfigureCmds, [overwrite: true]) } return [] From 0c0229847c75a960824b51563bf4177e8cf2f608 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Sat, 4 Sep 2021 14:14:08 +0800 Subject: [PATCH 045/184] * - remove the preferences item "createButton", Fixedly create a child button * Restrict its use based on fingerprints-because the child buttons are not visible to the user . * - Simplify the code, Syntax format compliance adjustment --- .../min-smart-plug-dimmer.groovy | 103 +++++++----------- 1 file changed, 38 insertions(+), 65 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index cf824d1b3cb..73e1382aef1 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v2.0.2 + * Min Smart Plug Dimmer v2.1.0 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,11 @@ * * Changelog: * + * 2.1.0 (09/04/2021) + * - remove the preferences item "createButton", Fixedly create a child button + * Restrict its use based on fingerprints-because the child buttons are not visible to the user . + * - Simplify the code, Syntax format compliance adjustment + * * 2.0.2 (09/02/2021) * 2.0.1 (08/27/2021) * - Syntax format compliance adjustment @@ -110,11 +115,10 @@ metadata { getConfigParamInput(nightLightParam) input "disclaimer", "paragraph", title: "WARNING", - description: "Configuring for 'createButton'、'Maximum Brightness' and 'Paddle Control' are only valid for the devices with product number of MS11ZS、MS13ZS、ZW31S、ZW31TS(one of them)", + description: "Configuring for 'Maximum Brightness' and 'Paddle Control' are only valid for the devices with product number of MS11ZS、MS13ZS、ZW31S、ZW31TS(one of them)", required: false getConfigParamInput(maximumBrightnessParam) getConfigParamInput(paddleControlParam) - input(type: "enum", name: "createButton", required: false, title: "Create Button for Paddles?", options: ["No", "Yes"], defaultValue:"Yes") } } @@ -126,29 +130,6 @@ private getConfigParamInput(param) { } } -private initialize() { - if (device.latestValue("checkInterval") != checkInterval) { - sendEvent(name: "checkInterval", value: checkInterval, displayed: false) - } - if (isButtonAvailable()) { - state.createButtonEnabled = (safeToInt(settings?.createButton) != 0) - if (state.createButtonEnabled && !childDevices) { - try { - def child = addChildButton() - child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - } catch (ex) { - log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) - } - } else if (!state.createButtonEnabled && childDevices) { - removeChildButton(childDevices[0]) - } - } else { - if (childDevices) { - removeChildButton(childDevices[0]) - } - } -} - private addChildButton() { log.warn "Creating Button Device" def child = addChildDevice( @@ -170,6 +151,7 @@ private addChildButton() { } def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + logTrace "CentralSceneNotification: ${cmd}" if (state.lastSequenceNumber != cmd.sequenceNumber) { state.lastSequenceNumber = cmd.sequenceNumber logTrace "${cmd}" @@ -192,9 +174,7 @@ def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotificat } private sendButtonEvent(value) { - if (childDevices) { - childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) - } + childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) } def ping() { @@ -214,17 +194,18 @@ private switchMultilevelGetCmd() { def installed() { logDebug "installed()..." - if (isButtonAvailable()) { - state.createButtonEnabled = true + try { + def child = addChildButton() + child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } catch (ex) { + log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) } sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } def uninstalled() { logger("debug", "uninstalled()") - if (childDevices) { - removeChildButton(childDevices[0]) - } + removeChildButton(childDevices[0]) } private removeChildButton(child) { @@ -246,7 +227,9 @@ def updated() { if (!isDuplicateCommand(state.lastUpdated, 5000)) { state.lastUpdated = new Date().time logDebug "updated()..." - initialize() + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } runIn(5, executeConfigureCmds, [overwrite: true]) } return [] @@ -254,7 +237,6 @@ def updated() { def configure() { logDebug "configure()..." - if (state.resyncAll == null) { state.resyncAll = true runIn(8, executeConfigureCmds, [overwrite: true]) @@ -275,11 +257,6 @@ def executeConfigureCmds() { configParams.each { param -> def storedVal = getParamStoredValue(param.num) def paramVal = param.value - if (isButtonAvailable()) { - if ((param == paddleControlParam) && state.createButtonEnabled && (param.value == 2)) { - log.warn "Only 'pushed', 'up_2x', and 'down_2x' button events are supported when Paddle Control is set to Toggle." - } - } if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) @@ -302,7 +279,6 @@ def parse(String description) { } else { logDebug "Unable to parse description: $description" } - sendEvent(name: "lastCheckIn", value: convertToLocalTimeString(new Date()), displayed: false) } catch (e) { log.error "$e" @@ -311,8 +287,8 @@ def parse(String description) { } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + logTrace "SecurityMessageEncapsulation: ${cmd}" def encapCmd = cmd.encapsulatedCommand(commandClassVersions) - def result = [] if (encapCmd) { result += zwaveEvent(encapCmd) @@ -323,11 +299,9 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { - logTrace "ConfigurationReport ${cmd}" - + logTrace "ConfigurationReport: ${cmd}" sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) runIn(4, refreshSyncStatus) - def param = configParams.find { it.num == cmd.parameterNumber } if (param) { def val = cmd.scaledConfigurationValue @@ -345,7 +319,7 @@ def refreshSyncStatus() { } def zwaveEvent(physicalgraph.zwave.Command cmd) { - logDebug "Ignored Command: $cmd" + logDebug "Unhandled zwaveEvent: $cmd" return [] } @@ -357,7 +331,8 @@ private secureCmd(cmd) { return cmd.format() } } catch (ex) { - log.error("caught exception", ex) + log.error("secureCmd exception", ex) + return cmd.format() } } @@ -458,7 +433,7 @@ private getMaximumBrightnessParam() { return getParam(12, "Maximum Brightness(0, Disabled; 1 - 99:1% - 99%)", 1, 99, null,"0..99") } -private getParam(num, name, size, defaultVal, options=null, range=null) { +private getParam(num, name, size, defaultVal, options = null, range = null) { def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) def map = [num: num, name: name, size: size, value: val] if (options) { @@ -508,7 +483,7 @@ private static validateRange(val, defaultVal, lowVal, highVal) { } } -private static safeToInt(val, defaultVal=0) { +private static safeToInt(val, defaultVal = 0) { return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal } @@ -575,13 +550,13 @@ def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { - logTrace "${cmd}" + logTrace "BasicReport: ${cmd}" sendSwitchEvents(cmd.value, "physical") return [] } def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { - logTrace "${cmd}" + logTrace "SwitchMultilevelReport: ${cmd}" sendSwitchEvents(cmd.value, "digital") return [] } @@ -592,20 +567,18 @@ private sendSwitchEvents(rawVal, type) { if (rawVal) { sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") } - if (isButtonAvailable()) { - def paddlesReversed = (paddleControlParam.value == 1) - if (state.createButtonEnabled && (type == "physical") && childDevices) { - if (paddleControlParam.value == 2) { - sendButtonEvent("pushed") - } else { - def btnVal = ((rawVal && !paddlesReversed) || (!rawVal && paddlesReversed)) ? "up" : "down" - def oldSwitch = device.currentValue("switch") - def oldLevel = device.currentValue("level") - if ((oldSwitch == "on") && (btnVal == "up") && (oldLevel > rawVal)) { - btnVal = "down" - } - sendButtonEvent(btnVal) + if (isButtonAvailable() && type == "physical") { + if (paddleControlParam.value == 2) { + sendButtonEvent("pushed") + } else { + def paddlesReversed = (paddleControlParam.value == 1) + def btnVal = ((rawVal && !paddlesReversed) || (!rawVal && paddlesReversed)) ? "up" : "down" + def oldSwitch = device.currentValue("switch") + def oldLevel = device.currentValue("level") + if ((oldSwitch == "on") && (btnVal == "up") && (oldLevel > rawVal)) { + btnVal = "down" } + sendButtonEvent(btnVal) } } } From e16906e271ed6c6bb9b250e0dfe588858d1c91b5 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Sat, 4 Sep 2021 14:22:14 +0800 Subject: [PATCH 046/184] Syntax format compliance adjustment --- .../min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 73e1382aef1..be5244bdc4d 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -12,7 +12,7 @@ * * 2.1.0 (09/04/2021) * - remove the preferences item "createButton", Fixedly create a child button - * Restrict its use based on fingerprints-because the child buttons are not visible to the user . + * Restrict its use based on fingerprints-because the child buttons is not visible to the user . * - Simplify the code, Syntax format compliance adjustment * * 2.0.2 (09/02/2021) From 5a0e2d4ca0a9c6cdc7a66cf10f75f951ac5fe9dc Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Mon, 6 Sep 2021 21:37:59 +0800 Subject: [PATCH 047/184] Delete devicetypes/sky-nie/child-button.src directory The file will be merged from another branch, so delete in this branch --- .../child-button.src/child-button.groovy | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 devicetypes/sky-nie/child-button.src/child-button.groovy diff --git a/devicetypes/sky-nie/child-button.src/child-button.groovy b/devicetypes/sky-nie/child-button.src/child-button.groovy deleted file mode 100644 index a3e0c370ceb..00000000000 --- a/devicetypes/sky-nie/child-button.src/child-button.groovy +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Child Button v1.0 (CHILD DEVICE) - * - * Author: - * winnie (sky-nie) - * - * Changelog: - * - * 1.0 (03/16/2020) - * - Initial Release - * - * Reference: - * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/component-button.src/component-button.groovy - * - * 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: "Child Button", namespace: "sky-nie", author: "winnie", ocfDeviceType: "x.com.st.d.remotecontroller") { - capability "Button" - capability "Sensor" - } - - tiles(scale: 2) { - multiAttributeTile(name: "button", type: "generic", width: 6, height: 4, canChangeIcon: true) { - tileAttribute("device.button", key: "PRIMARY_CONTROL") { - attributeState "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff" - } - } - main "button" - details(["button"]) - } -} - -def installed() { - log.debug "installed()..." -} - -def updated() { - log.debug "updated()..." -} - -def uninstalled() { - log.warn "uninstalled()..." -} \ No newline at end of file From 5a8b41393b1b7c3e843b2d1ebdbdd0a91713cccc Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Tue, 7 Sep 2021 00:42:03 +0800 Subject: [PATCH 048/184] * - Syntax format compliance adjustment * - delete dummy code --- .../min-smart-plug-dimmer.groovy | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index be5244bdc4d..3aae44fc02e 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v2.1.0 + * Min Smart Plug Dimmer v2.1.1 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,10 @@ * * Changelog: * + * 2.1.1 (09/07/2021) + * - Syntax format compliance adjustment + * - delete dummy code + * * 2.1.0 (09/04/2021) * - remove the preferences item "createButton", Fixedly create a child button * Restrict its use based on fingerprints-because the child buttons is not visible to the user . @@ -86,6 +90,7 @@ metadata { capability "Configuration" capability "Refresh" capability "Health Check" + capability "Button" attribute "firmwareVersion", "string" attribute "lastCheckIn", "string" @@ -179,13 +184,15 @@ private sendButtonEvent(value) { def ping() { logDebug "ping()..." - return [ switchMultilevelGetCmd() ] + sendHubCommand(switchMultilevelGetCmd()) + return [] } def refresh() { logDebug "refresh()..." refreshSyncStatus() - return [ switchMultilevelGetCmd() ] + sendHubCommand(switchMultilevelGetCmd()) + return [] } private switchMultilevelGetCmd() { @@ -203,20 +210,6 @@ def installed() { sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } -def uninstalled() { - logger("debug", "uninstalled()") - removeChildButton(childDevices[0]) -} - -private removeChildButton(child) { - try { - log.warn "Removing ${child.displayName}} " - deleteChildDevice(child.deviceNetworkId) - } catch (ex) { - log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.", ex) - } -} - private static def getCheckInterval() { // These are battery-powered devices, and it's not very critical // to know whether they're online or not – 12 hrs @@ -510,12 +503,14 @@ private logTrace(msg) { def on() { logDebug "on()..." - return [ basicSetCmd(0xFF) ] + sendHubCommand(basicSetCmd(0xFF)) + return [] } def off() { logDebug "off()..." - return [ basicSetCmd(0x00) ] + sendHubCommand(basicSetCmd(0x00)) + return [] } def setLevel(level) { @@ -528,7 +523,8 @@ def setLevel(level, duration) { if (duration > 30) { duration = 30 } - return [ switchMultilevelSetCmd(level, duration) ] + sendHubCommand(switchMultilevelSetCmd(level, duration)) + return [] } private basicSetCmd(val) { From 2dfa9f5656215806aba07dc70a23b5ef113c8047 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Tue, 7 Sep 2021 09:43:38 +0800 Subject: [PATCH 049/184] add removeChildButton in updated() when isButtonAvailable() return false --- .../min-smart-plug-dimmer.groovy | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 3aae44fc02e..074f8a451ec 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -210,6 +210,15 @@ def installed() { sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } +private removeChildButton(child) { + try { + log.warn "Removing ${child.displayName}} " + deleteChildDevice(child.deviceNetworkId) + } catch (ex) { + log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.", ex) + } +} + private static def getCheckInterval() { // These are battery-powered devices, and it's not very critical // to know whether they're online or not – 12 hrs @@ -223,6 +232,9 @@ def updated() { if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } + if(!isButtonAvailable() && childDevices){ + removeChildButton(childDevices[0]) + } runIn(5, executeConfigureCmds, [overwrite: true]) } return [] From 9009786f6f41389ae782427771f597631029d394 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Tue, 7 Sep 2021 11:04:24 +0800 Subject: [PATCH 050/184] restore addChildButton in updated() when it' needed. --- .../min-smart-plug-dimmer.groovy | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 074f8a451ec..433e3baf2fb 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -179,7 +179,9 @@ def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotificat } private sendButtonEvent(value) { - childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) + if (childDevices) { + childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) + } } def ping() { @@ -201,24 +203,9 @@ private switchMultilevelGetCmd() { def installed() { logDebug "installed()..." - try { - def child = addChildButton() - child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - } catch (ex) { - log.error("Unable to create button device because the 'Child Button' DTH is not installed",ex) - } sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } -private removeChildButton(child) { - try { - log.warn "Removing ${child.displayName}} " - deleteChildDevice(child.deviceNetworkId) - } catch (ex) { - log.error("Unable to remove ${child.displayName}! Make sure that the device is not being used by any SmartApps.", ex) - } -} - private static def getCheckInterval() { // These are battery-powered devices, and it's not very critical // to know whether they're online or not – 12 hrs @@ -232,8 +219,14 @@ def updated() { if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } - if(!isButtonAvailable() && childDevices){ - removeChildButton(childDevices[0]) + + if (isButtonAvailable() && !childDevices) { + try { + def child = addChildButton() + child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } catch (ex) { + log.error("Unable to create button device because the 'Child Button' DTH is not installed", ex) + } } runIn(5, executeConfigureCmds, [overwrite: true]) } From 24b2652c824467720337f0a30e71a070e69a2275 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Tue, 7 Sep 2021 18:09:56 +0800 Subject: [PATCH 051/184] * - Syntax format compliance adjustment * - delete dummy code --- .../min-smart-plug-dimmer.groovy | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 433e3baf2fb..5ff2149f18f 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -186,15 +186,13 @@ private sendButtonEvent(value) { def ping() { logDebug "ping()..." - sendHubCommand(switchMultilevelGetCmd()) - return [] + return [ switchMultilevelGetCmd() ] } def refresh() { logDebug "refresh()..." refreshSyncStatus() - sendHubCommand(switchMultilevelGetCmd()) - return [] + return [ switchMultilevelGetCmd() ] } private switchMultilevelGetCmd() { @@ -219,11 +217,9 @@ def updated() { if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } - - if (isButtonAvailable() && !childDevices) { + if (isButtonAvailable() && !childDevices) { try { - def child = addChildButton() - child?.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + addChildButton() } catch (ex) { log.error("Unable to create button device because the 'Child Button' DTH is not installed", ex) } @@ -508,14 +504,12 @@ private logTrace(msg) { def on() { logDebug "on()..." - sendHubCommand(basicSetCmd(0xFF)) - return [] + return [ basicSetCmd(0xFF) ] } def off() { logDebug "off()..." - sendHubCommand(basicSetCmd(0x00)) - return [] + return [ basicSetCmd(0x00) ] } def setLevel(level) { @@ -528,8 +522,7 @@ def setLevel(level, duration) { if (duration > 30) { duration = 30 } - sendHubCommand(switchMultilevelSetCmd(level, duration)) - return [] + return [ switchMultilevelSetCmd(level, duration) ] } private basicSetCmd(val) { From 8069f29f19f245a88938b8727f1ee0a6e132b1a2 Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Fri, 10 Sep 2021 09:54:34 +0800 Subject: [PATCH 052/184] Syntax format compliance adjustment as PR review --- .../min-smart-plug-dimmer.groovy | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 5ff2149f18f..4f5a9fbc634 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -82,7 +82,7 @@ import groovy.json.JsonOutput metadata { - definition (name: "Min Smart Plug Dimmer", namespace: "sky-nie", author: "winnie", ocfDeviceType: "oic.d.smartplug") { + definition (name: "Min Smart Plug Dimmer", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-dimmer") { capability "Actuator" capability "Sensor" capability "Switch" @@ -90,19 +90,18 @@ metadata { capability "Configuration" capability "Refresh" capability "Health Check" - capability "Button" attribute "firmwareVersion", "string" attribute "lastCheckIn", "string" attribute "syncStatus", "string" - fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Dimmer Switch" //MP21ZD - fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Dimmer Switch" //MP22ZD - fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Dimmer Switch" //N4002 - fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS11ZS Minoston Smart Dimmer Switch - fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //MS13ZS Minoston Smart Toggle Dimmer Switch - fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31S Evalogik Smart Dimmer Switch - fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", mnmn: "SmartThings", vid:"generic-dimmer" //ZW31TS Evalogik Smart Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Smart Plug Dimmer", ocfDeviceType: "oic.d.smartplug" //MP21ZD + fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Outdoor Dimmer", ocfDeviceType: "oic.d.smartplug" //MP22ZD + fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Smart Plug Dimmer", ocfDeviceType: "oic.d.smartplug" //N4002 + fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS11ZS Minoston Smart Dimmer Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS13ZS Minoston Smart Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31S Evalogik Smart Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31TS Evalogik Smart Toggle Dimmer Switch } preferences { @@ -140,7 +139,7 @@ private addChildButton() { def child = addChildDevice( "sky-nie", "Child Button", - "${device.deviceNetworkId}-2", + "${device.deviceNetworkId}:2", device.getHub().getId(), [ completedSetup: true, From 1d1faa5c4326f56007dd4edf8ec663b5bfbcf8f1 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Mon, 13 Sep 2021 14:27:01 -0400 Subject: [PATCH 053/184] DevWs for Zooz (The Smartest House) containing containing Zooz Double Switch ZEN30 (#74859) * DevWs for Zooz (The Smartest House) containing containing Zooz Double Switch ZEN30 * made requested changes * Moved raw description above fingerprint --- .../zooz-double-switch-zen30.groovy | 482 ++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 devicetypes/zooz/zooz-double-switch-zen30.src/zooz-double-switch-zen30.groovy diff --git a/devicetypes/zooz/zooz-double-switch-zen30.src/zooz-double-switch-zen30.groovy b/devicetypes/zooz/zooz-double-switch-zen30.src/zooz-double-switch-zen30.groovy new file mode 100644 index 00000000000..5310dc07a2e --- /dev/null +++ b/devicetypes/zooz/zooz-double-switch-zen30.src/zooz-double-switch-zen30.groovy @@ -0,0 +1,482 @@ +/* + * Zooz Double Switch ZEN30 + * + * Changelog: + * + * 2021-08-30 + * - Requested changes + * 2021-08-28 + * - Publication Release + * + * Copyright 2021 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x25: 1, // SwitchBinary + 0x26: 3, // SwitchMultilevel + 0x55: 1, // TransportService + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5B: 1, // CentralScene + 0x5E: 2, // ZwaveplusInfo + 0x60: 3, // MultiChannel + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version + 0x8E: 2, // MultiChannelAssociation + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 +] + +@Field static int supervisionCC = 108 +@Field static int upperPaddle = 1 +@Field static int lowerPaddle = 2 +@Field static int relayButton = 3 +@Field static int btnPushed = 0 +@Field static int btnReleased = 1 +@Field static int btnHeld = 2 +@Field static Map endpoints = [dimmer: 0, relay: 1] + +@Field static List supportedButtonValues = ["pushed","held","pushed_2x","pushed_3x","pushed_4x","pushed_5x","down","down_hold","down_2x","down_3x","down_4x","down_5x","up","up_hold","up_2x","up_3x","up_4x","up_5x"] + +@Field static Map configParams = [ + powerFailureParam: [num:12, title:"On Off Status After Power Failure", size:1, defaultVal:3, options:[0:"Dimmer Off / Relay Off", 1:"Dimmer Off / Relay On", 2:"Dimmer On / Relay Off", 3:"Dimmer Remember / Relay Remember [DEFAULT]", 4:"Dimmer Remember / Relay On", 5:"Dimmer Remember / Relay Off", 6:"Dimmer On / Relay Remember", 7:"Dimmer Off / Relay Remember", 8:"Dimmer On / Relay On"]], + ledSceneControlParam: [num:7, title:"LED Indicator Mode for Scene Control", size:1, defaultVal:1, options:[0:"LED Enabled", 1:"LED Disabled [DEFAULT]"]], + relayLedModeParam: [num:2, title:"Relay LED Indicator Mode", size:1, defaultVal:0, options:[0:"On When Off [DEFAULT]", 1:"On When On", 2:"Always Off", 3:"Always On"]], + relayLedColorParam: [num:4, title:"Relay LED Indicator Color", size:1, defaultVal:0, options:[0:"White [DEFAULT]", 1:"Blue", 2:"Green", 3:"Red"]], + relayLedBrightnessParam: [num:6, title:"Relay LED Indicator Brightness", size:1, defaultVal:1, options:[0:"100%", 1:"60% [DEFAULT]", 2:"30%"]], + relayAutoOffParam: [num:10, title:"Relay Auto Turn-Off Timer (Minutes)", size:4, defaultVal:0, range:"0..65535"], + relayAutoOnParam: [num:11, title:"Relay Auto Turn-On Timer (Minutes)", size:4, defaultVal:0, range:"0..65535"], + relayLoadControlParam: [num:20, title:"Relay Load Control", size:1, defaultVal:1, options:[0:"Physical Disabled", 1:"Physical / Digital Enabled [DEFAULT]", 2:"Physical / Digital Disabled"]], + relayPhysicalDisabledBehaviorParam: [num:25, title:"Relay Physical Disabled Behavior [FIRMWARE >= 1.05]", size:1, defaultVal:0, options:[0:"Change Status/LED [DEFAULT]", 1:"Don't Change Status/LED"], minFirmware: 1.05], + dimmerLedModeParam: [num:1, title:"Dimmer LED Indicator Mode", size:1, defaultVal:0, options:[0:"On When Off [DEFAULT]", 1:"On When On", 2:"Always Off", 3:"Always On"]], + dimmerLedColorParam: [num:3, title:"Dimmer LED Indicator Color", size:1, defaultVal:0, options:[0:"White [DEFAULT]", 1:"Blue", 2:"Green", 3:"Red"]], + dimmerLedBrightnessParam: [num:5, title:"Dimmer LED Indicator Brightness", size:1, defaultVal:1, options:[0:"100%", 1:"60% [DEFAULT]", 2:"30%"]], + dimmerAutoOffParam: [num:8, title:"Dimmer Auto Turn-Off Timer (Minutes)", size:4, defaultVal:0, range:"0..65535"], + dimmerAutoOnParam: [num:9, title:"Dimmer Auto Turn-On Timer (Minutes)", size:4, defaultVal:0, range:"0..65535"], + dimmerRampRateParam: [num:13, title:"Dimmer Physical Ramp Rate (Seconds)", size:1, defaultVal:1, range:"0..99"], + dimmerPaddleHeldRampRateParam: [num:21, title:"Dimming Speed when Paddle is Held (Seconds)", size:1, defaultVal:4, range:"1..99"], + dimmerMinimumBrightnessParam: [num:14, title:"Dimmer Minimum Brightness (%)", size:1, defaultVal:1, range:"1..99"], + dimmerMaximumBrightnessParam: [num:15, title:"Dimmer Maximum Brightness (%)", size:1, defaultVal:99, range:"1..99"], + dimmerCustomBrightnessParam: [num:23, title:"Custom Brightness (%)", size:1, defaultVal:0, range:"0..99"], + dimmerBrightnessControlParam: [num:18, title:"Dimmer Brightness Control", size:1, defaultVal:0, options:[0:"Double Tap Maximum [DEFAULT]", 1:"Single Tap Custom", 2:"Single Tap Maximum"]], + dimmerDoubleTapFunctionParam: [num:17, title:"Dimmer Double Tap Function", size:1, defaultVal:0, options:[0:"Turn on Full Brightness [DEFAULT]", 1:"Turn on Maximum Brightness"]], + dimmerLoadControlParam: [num:19, title:"Dimmer Load Control", size:1, defaultVal:1, options:[0:"Physical Disabled", 1:"Physical / Digital Enabled [DEFAULT]", 2:"Physical / Digital Disabled"]], + dimmerPhysicalDisabledBehaviorParam: [num:24, title:"Dimmer Physical Disabled Behavior [FIRMWARE >= 1.05]", size:1, defaultVal:0, options:[0:"Change Status/LED [DEFAULT]", 1:"Don't Change Status/LED"], minFirmware:1.05], + dimmerNightModeBrightnessParam: [num:26, title:"Night Mode Brightness (%) [FIRMWARE >= 1.05]", size:1, defaultVal:20, range:"0..99", minFirmware:1.05], + dimmerPaddleControlParam: [num:27, title:"Paddle Orientation for Dimmer [FIRMWARE >= 1.05]", size:1, defaultVal:0, options:[0:"Normal [DEFAULT]", 1:"Reverse", 2:"Toggle"], minFirmware:1.05] +] + +metadata { + definition ( + name: "Zooz Double Switch ZEN30", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "oic.d.light", + mnmn: "SmartThingsCommunity", + vid: "8e189c52-eb8b-36e4-b9e2-2ba459caa6af" + ) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Switch Level" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "Button" + capability "platemusic11009.firmware" + capability "platemusic11009.syncStatus" + + //zw:Ls2 type:1101 mfr:027A prod:A000 model:A008 ver:2.00 zwv:5.03 lib:03 cc:5E,6C,55,9F sec:86,26,25,85,8E,59,72,5A,73,5B,60,70,7A epc:1 + fingerprint mfr: "027A", prod: "A000", model: "A008", deviceJoinName: "Zooz Switch" //Zooz Double Switch ZEN30 + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input name, "number", + title: param.title, + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + + input "debugLogging", "enum", + title: "Logging:", + required: false, + defaultValue: "1", + options: ["0":"Disabled", "1":"Enabled [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + initialize() +} + +def updated() { + logDebug "updated()..." + initialize() + configure() +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugLogging, 1) != 0) + + refreshSyncStatus() + + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((60 * 60 * 3) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + if (!device.currentValue("supportedButtonValues")) { + sendEvent(name:"supportedButtonValues", value:supportedButtonValues.encodeAsJSON(), displayed:false) + } + + if (!device.currentValue("numberOfButtons")) { + sendEvent(name:"numberOfButtons", value:1, displayed:false) + } + + if (!device.currentValue("button")) { + sendButtonEvent("pushed") + } + + if (!childDevices) { + addChildDevice( + "smartthings", + "Child Switch", + "${device.deviceNetworkId}:${endpoints.relay}", + null, + [ + completedSetup: true, + label: "${device.displayName} Relay", + isComponent: false + ] + ) + refresh() + } +} + +def configure() { + logDebug "configure()..." + List cmds = [] + BigDecimal firmware = safeToDec(device.currentValue("firmwareVersion"), 0.0) + + if (device.currentValue("firmwareVersion") == null) { + cmds << secureCmd(zwave.versionV1.versionGet()) + } + + configParams.each { name, param -> + if (firmwareSupportsParam(firmware, param)) { + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + logDebug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + } + if (cmds) { + sendHubCommand(cmds, 500) + } +} + +def ping() { + logDebug "ping()..." + return [ multiChannelCmdEncapCmd(zwave.switchMultilevelV3.switchMultilevelGet(), endpoints.dimmer) ] +} + +def on() { + logDebug "on()..." + return getSetLevelCmds(state.lastLevel) +} + +def off() { + logDebug "off()..." + return getSetLevelCmds(0x00) +} + +def setLevel(level, duration=null) { + logDebug "setLevel($level, $duration)..." + return getSetLevelCmds(level, duration) +} + +List getSetLevelCmds(level, duration=null) { + state.expectedLevel = level + def levelVal = validateRange(level, 99, 0, 99) + def durationVal = validateRange(duration, 1, 0, 30) + return [ + multiChannelCmdEncapCmd(zwave.switchMultilevelV3.switchMultilevelSet(dimmingDuration: durationVal, value: levelVal), endpoints.dimmer) + ] +} + +def refresh() { + logDebug "refresh()..." + refreshSyncStatus() + + if (device.currentValue("syncStatus") != "Synced") { + configure() + } + + return sendHubCommand([ + multiChannelCmdEncapCmd(zwave.switchMultilevelV3.switchMultilevelGet(), endpoints.dimmer), + multiChannelCmdEncapCmd(zwave.switchBinaryV1.switchBinaryGet(), endpoints.relay), + secureCmd(zwave.versionV1.versionGet()) + ], 500) +} + +def childOn(dni) { + logDebug "childOn(${dni})..." + sendHubCommand([ + multiChannelCmdEncapCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF), endpoints.relay) + ]) +} + +def childOff(dni) { + logDebug "childOff(${dni})..." + sendHubCommand([ + multiChannelCmdEncapCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00), endpoints.relay) + ]) +} + +String multiChannelCmdEncapCmd(cmd, endpoint) { + if (endpoint) { + return secureCmd(zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:safeToInt(endpoint)).encapsulate(cmd)) + } else { + return secureCmd(cmd) + } +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + // Workaround that was added to all SmartThings Multichannel DTHs. + if ((cmd.commandClass == supervisionCC) && (cmd.parameter.size >= 4)) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint) + } else { + logDebug "Unable to get encapsulated command: $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + state[name] = val + logDebug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEvent(name: "firmwareVersion", value: (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint=0) { + logDebug "${cmd} (${endpoint})" + sendSwitchEvents(cmd.value, endpoint) +} + +void zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint=0) { + logDebug "${cmd} (${endpoint})" + sendSwitchEvents(cmd.value, endpoint) +} + +void zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, endpoint=0) { + logDebug "${cmd} (${endpoint})" + sendSwitchEvents(cmd.value, endpoint) +} + +void sendSwitchEvents(rawVal, Integer endpoint) { + String switchVal = rawVal ? "on" : "off" + if (endpoint == endpoints.dimmer) { + logDebug "switch is ${switchVal}" + sendEvent(name: "switch", value: switchVal) + + int level = (state.expectedLevel == 100 ? 100 : rawVal) + sendEvent(name: "level", value: level, unit: "%") + if (level > 0) { + state.lastLevel = level + } + state.expectedLevel = null + } else { + def child = childDevices[0] + if ((child != null) && (child.currentValue("switch") != switchVal)) { + logDebug "${child.displayName} switch is ${switchVal}" + child.sendEvent(name: "switch", value: switchVal) + } + } +} + +void zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + + String actionType + String btnVal + String displayName = "" + + switch (cmd.sceneNumber) { + case upperPaddle: + actionType = "up" + break + case lowerPaddle: + actionType = "down" + break + case relayButton: + actionType = "pushed" + displayName = "${childDevices[0]?.displayName} " + } + + switch (cmd.keyAttributes){ + case btnPushed: + btnVal = actionType + break + case btnReleased: + // btnVal = (cmd.sceneNumber == relayButton) ? "released" : "${actionType}_released" + logDebug "Button Value 'released' is not supported by SmartThings" + break + case btnHeld: + btnVal = (actionType == "pushed") ? "held" : "${actionType}_hold" + break + default: + btnVal = "${actionType}_${cmd.keyAttributes - 1}x" + } + + if (btnVal) { + logDebug "${displayName} Button ${btnVal}" + sendButtonEvent(btnVal) + } + } +} + +void sendButtonEvent(String value) { + sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +Integer getPendingChanges() { + BigDecimal firmware = safeToDec(device.currentValue("firmwareVersion"), 0.0) + return configParams.count { name, param -> + ((firmwareSupportsParam(firmware, param)) && (getSettingVal(name) != getStoredVal(name))) + } +} + +Integer getSettingVal(String name) { + return (settings ? safeToInt(settings[name], null) : null) +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +boolean firmwareSupportsParam(BigDecimal firmware, Map param) { + return (firmware >= safeToDec(param.minFirmware, 0.0)) +} + +Integer validateRange(val, Integer defaultVal, Integer lowVal, Integer highVal) { + Integer intVal = safeToInt(val, defaultVal) + if (intVal > highVal) { + return highVal + } else if (intVal < lowVal) { + return lowVal + } else { + return intVal + } +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +BigDecimal safeToDec(val, BigDecimal defaultVal=0) { + return "${val}"?.isBigDecimal() ? "${val}".toBigDecimal() : defaultVal +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From d5821c36ba4d45037a0e27a2618601fc2587b9fe Mon Sep 17 00:00:00 2001 From: Aeotec-ccheng <63321041+Aeotec-ccheng@users.noreply.github.com> Date: Mon, 13 Sep 2021 13:17:41 -0700 Subject: [PATCH 054/184] MS7 and MS6 have different sizes for parameter 101/102 MultiSensor 7 uses size 1 for parameter 101/102 MultiSensor 6 uses size 4 for parameter 101/102 Having Parameter 101/102 sent with size 1 for both sensor causes configuration issues for MultiSensor 6. This fixes the issue in regards to MultiSensor 6 configuration. --- .../aeon-multisensor-6.groovy | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy index aca2b1b55cf..d11c01618d8 100644 --- a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy +++ b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy @@ -407,15 +407,6 @@ def configure() { //1. set association groups for hub - 2 groups are used to set battery refresh interval different than sensor report interval request << zwave.associationV1.associationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId) - //2. automatic report flags - // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 15 ultraviolet sensor, 1 battery sensor - // set value 241 (default for 101) to get all reports. Set value 0 for no reports (default for 102-103) - //association group 1 - request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 1, scaledConfigurationValue: 240) - - //association group 2 - request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 1, scaledConfigurationValue: 1) - // Expedite this if we know this info so that we can execute the code below if (!state.MSR && zwaveInfo?.mfr && zwaveInfo.prod && zwaveInfo.model) { state.MSR = "${zwaveInfo.mfr}-${zwaveInfo.prod}-${zwaveInfo.model}" @@ -425,6 +416,15 @@ def configure() { case "0086-0002-0064": // MultiSensor 6 EU case "0086-0102-0064": // MultiSensor 6 US case "0086-0202-0064": // MultiSensor 6 AU + //2. automatic report flags + // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 15 ultraviolet sensor, 1 battery sensor + // set value 241 (default for 101) to get all reports. Set value 0 for no reports (default for 102-103) + //association group 1 + request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 240) + + //association group 2 + request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1) + //3. no-motion report x seconds after motion stops (default 20 secs) request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 20) @@ -445,6 +445,15 @@ def configure() { case "0371-0002-0018": // MultiSensor 7 EU case "0371-0102-0018": // MultiSensor 7 US case "0371-0202-0018": // MultiSensor 7 AU + //2. automatic report flags + // param 101 -103 [4 bytes] 128: light sensor, 64 humidity, 32 temperature sensor, 15 ultraviolet sensor, 1 battery sensor + // set value 241 (default for 101) to get all reports. Set value 0 for no reports (default for 102-103) + //association group 1 + request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 1, scaledConfigurationValue: 240) + + //association group 2 + request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 1, scaledConfigurationValue: 1) + //3. no-motion report x seconds after motion stops (default 30 secs) request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 30) From 33537e590fcb4cea4b13d491bea1da4f82fbc7a6 Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Thu, 16 Sep 2021 07:09:06 +0900 Subject: [PATCH 055/184] WWST-5862, added FP for the SAMSUNG LED(Fan lightings) (#68445) * Update zigbee-rgbw-bulb.groovy * Create .st-ignore 2021.06.18 Ceiling fan light added * Create README.md 2021.06.18 first report * Create led-fan-lightings.groovy 2021.06.18 create first main lightings file * Create itm-fan-child.groovy 2021.06.18 first time : create a child device(fan) file * Delete .st-ignore 20210708 delete * Update itm-fan-child.groovy 20210728 clean code update * Update led-fan-lightings.groovy 20210727 clean code update * Update led-fan-lightings.groovy Edit code style * Update led-fan-lightings.groovy Edit code style * Update itm-fan-child.groovy Edit code style * Update led-fan-lightings.groovy Edit code style * Update led-fan-lightings.groovy Edit code style * Update itm-fan-child.groovy Edit code style * Update led-fan-lightings.groovy change code style * Update led-fan-lightings.groovy Change code style * Update led-fan-lightings.groovy Update code style * Update led-fan-lightings.groovy Edit code style * Update led-fan-lightings.groovy Change code style * Update led-fan-lightings.groovy Change point (4 codes) "${device.deviceNetworkId}-Fan" to "${device.deviceNetworkId}:1" * Update itm-fan-child.groovy Change code - Add capability "Switch Level" - Add function setLevel * Update led-fan-lightings.groovy Change code style * Update itm-fan-child.groovy Change code style * Update itm-fan-child.groovy Add a comment for capability "Switch Level" * Update itm-fan-child.groovy Code update * Update led-fan-lightings.groovy Code update * Update itm-fan-child.groovy Align codes. * Update led-fan-lightings.groovy Edit codes * Update led-fan-lightings.groovy Clean up the codes * Update itm-fan-child.groovy Clean up the codes * Update itm-fan-child.groovy Fix the codes * Update itm-fan-child.groovy Clean up the codes * Update led-fan-lightings.groovy Edit the name of zigbeeMap.name * Update led-fan-lightings.groovy Edit codes * Update led-fan-lightings.groovy Edit code * Update led-fan-lightings.groovy Edit codes * Update itm-fan-child.groovy Edit year * Update led-fan-lightings.groovy Edit year * Update led-fan-lightings.groovy Edit code * Update itm-fan-child.groovy Edit code * Update itm-fan-child.groovy Edit code * Update itm-fan-child.groovy Align codes * Update led-fan-lightings.groovy Align codes * Update itm-fan-child.groovy Align codes * Update led-fan-lightings.groovy Align codes * Update itm-fan-child.groovy Align code * Update led-fan-lightings.groovy Edit code * Update led-fan-lightings.groovy Fix codes * Update led-fan-lightings.groovy Fix codes * Update led-fan-lightings.groovy Delete log.bebug * * Update itm-fan-child.groovy Delete log.debug * * Update led-fan-lightings.groovy Fix the configure function * Update led-fan-lightings.groovy Edit codes * Update itm-fan-child.groovy Clear codes * Update itm-fan-child.groovy Clear codes * Update led-fan-lightings.groovy Fix the code * Update itm-fan-child.groovy Clear codes * Update zigbee-rgbw-bulb.groovy Add the finger print for ABL Juno connect E-series * Update led-fan-lightings.groovy Edit addChildFan function * Update led-fan-lightings.groovy Clear codes --- .../zigbee-ceiling-fan-light.src/README.md | 29 ++++ .../itm-fan-child.groovy | 67 +++++++ .../led-fan-lightings.groovy | 163 ++++++++++++++++++ .../zigbee-rgbw-bulb.groovy | 3 + 4 files changed, 262 insertions(+) create mode 100644 devicetypes/smartthings/zigbee-ceiling-fan-light.src/README.md create mode 100644 devicetypes/smartthings/zigbee-ceiling-fan-light.src/itm-fan-child.groovy create mode 100644 devicetypes/smartthings/zigbee-ceiling-fan-light.src/led-fan-lightings.groovy diff --git a/devicetypes/smartthings/zigbee-ceiling-fan-light.src/README.md b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/README.md new file mode 100644 index 00000000000..d22c4562f2c --- /dev/null +++ b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/README.md @@ -0,0 +1,29 @@ +# ZigBee Ceiling Fan Light + +Cloud Execution + +Works with: + +* Samsung ITM + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) + +## Capabilities + +* **Actuator** - represents that a Device has commands* +* **Configuration** - _configure()_ command called when device is installed or device preferences updated. +* **Refresh** - _refresh()_ command for status updates +* **Switch** - can detect state (possible values: on/off) +* **Switch Level** - represents current light level, usually 0-100 in percent +* **Health Check** - indicates ability to get device health notifications +* **Fan Speed** - represents current fan speed, 0 - 4(Off, Low, Mid, High, Max) + +## Device Health + +Zigbee Bulb with reporting interval of 5 mins. +SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE` + +*__12min__ checkInterval diff --git a/devicetypes/smartthings/zigbee-ceiling-fan-light.src/itm-fan-child.groovy b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/itm-fan-child.groovy new file mode 100644 index 00000000000..78c1847496d --- /dev/null +++ b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/itm-fan-child.groovy @@ -0,0 +1,67 @@ +/* + * Copyright 2021 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. + * + * ZigBee Ceiling Fan Light + * + * Author: SAMSUNG LED + * Date: 2021-06-30 + */ + +import physicalgraph.zigbee.zcl.DataType +import groovy.json.JsonOutput + +metadata { + definition(name: "ITM Fan Child", namespace: "SAMSUNG LED", author: "SAMSUNG LED", ocfDeviceType: "oic.d.fan") { + capability "Actuator" + capability "Configuration" + capability "Refresh" + capability "Switch" + /* Capability "Switch Level" is used to control fan speed for platforms don't support capability "Fan speed" + * when you connect other platforms via SmartThings cloud to cloud connection. */ + capability "Switch Level" + capability "Fan Speed" + } +} + +def off() { + setFanSpeed(0x00) +} + +def on() { + setFanSpeed(0x01) +} + +def setLevel(value) { + if (value <= 1) { + setFanSpeed(0x00) + } else if (value <= 25) { + setFanSpeed(0x01) + } else if (value <= 50) { + setFanSpeed(0x02) + } else if (value <= 75) { + setFanSpeed(0x03) + } else if (value <= 100) { + setFanSpeed(0x04) + } +} + +def setFanSpeed(speed) { + parent.sendFanSpeed(speed) +} + +void refresh() { + parent.refresh() +} + +def ping() { + parent.ping() +} diff --git a/devicetypes/smartthings/zigbee-ceiling-fan-light.src/led-fan-lightings.groovy b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/led-fan-lightings.groovy new file mode 100644 index 00000000000..c4126cef2c0 --- /dev/null +++ b/devicetypes/smartthings/zigbee-ceiling-fan-light.src/led-fan-lightings.groovy @@ -0,0 +1,163 @@ +/* + * Copyright 2021 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. + * + * ZigBee Ceiling Fan Light + * + * Author: SAMSUNG LED + * Date: 2021-06-30 + */ + +import physicalgraph.zigbee.zcl.DataType +import groovy.json.JsonOutput + +metadata { + definition (name: "LED FAN lightings", namespace: "SAMSUNG LED", author: "SAMSUNG LED") { + capability "Actuator" + capability "Configuration" + capability "Health Check" + capability "Refresh" + capability "Switch" + capability "Switch Level" + + // Samsung LED + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-003", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-003" + } + + // UI 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: "off", icon: "st.switches.light.on", backgroundColor: "#00A0DC", nextState: "turningOff" + attributeState "off", label: '${name}', action: "on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "off", icon: "st.switches.light.on", backgroundColor: "#00A0DC", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action: "switch level.setLevel" + } + } + + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + main(["switch"]) + details(["switch", "refresh", "switchLevel"]) + } +} + +private getFAN_CLUSTER_VALUE() { 0x0202 } +private getFAN_STATUS_VALUE() { 0x0000 } +private getON_OFF_CLUSTER_VALUE() { 0x0006 } + +def parse(String description) { + // Parse incoming device messages to generate events + def event = zigbee.getEvent(description) + if (event) { + sendEvent(event) + } else if (description?.startsWith('read attr -')) { + def zigbeeMap = zigbee.parseDescriptionAsMap(description) + if (zigbeeMap.clusterInt == FAN_CLUSTER_VALUE && + zigbeeMap.attrInt == FAN_STATUS_VALUE) { + def childDevice = childDevices.find { + //find light child device + it.device.deviceNetworkId == "${device.deviceNetworkId}:1" + } + def fanSpeedEvent = createEvent(name: "fanSpeed", value: zigbeeMap.value as Integer) + childDevice.sendEvent(fanSpeedEvent) + if (fanSpeedEvent.value == 0) { + childDevice.sendEvent(name: "switch", value: "off") + childDevice.sendEvent(name: "level", value: 0) // For cloud to cloud device UI update + } else { + childDevice.sendEvent(name: "switch", value: "on") + def int_v = fanSpeedEvent.value + int_v = int_v * 25 + int_v = int_v > 100 ? 100 : int_v + childDevice.sendEvent(name: "level", value: int_v) // For cloud to cloud device UI update + } + } + } else { + def cluster = zigbee.parse(description) + if (cluster && + cluster.clusterInt == ON_OFF_CLUSTER_VALUE && + cluster.command == 0x07) { + if (cluster.data[0] == 0x00) { + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + } + } + } +} + +def off() { + zigbee.off() +} + +def on() { + zigbee.on() +} + +def setLevel(value, duration) { + zigbee.setLevel(value) +} + +def sendFanSpeed(val) { + delayBetween([zigbee.writeAttribute(FAN_CLUSTER_VALUE, FAN_STATUS_VALUE, DataType.ENUM8, val), zigbee.readAttribute(FAN_CLUSTER_VALUE, FAN_STATUS_VALUE)], 100) +} + +def ping() { + // PING is used by Device-Watch in attempt to reach the Device + return zigbee.onOffRefresh() + + zigbee.readAttribute(FAN_CLUSTER_VALUE, FAN_STATUS_VALUE) +} + +def refresh() { + zigbee.onOffRefresh() + + zigbee.levelRefresh() + + zigbee.readAttribute(FAN_CLUSTER_VALUE, FAN_STATUS_VALUE) +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity + return zigbee.onOffConfig(0, 300) + + zigbee.levelConfig() + + refresh() +} + +def installed() { + addChildFan() +} + +def addChildFan() { + def componentLabel + def childDevice + + if (device.displayName.endsWith(' Light') || + device.displayName.endsWith(' light')) { + componentLabel = "${device.displayName[0..-6]} Fan" + } else { + // no '1' at the end of deviceJoinName - use 2 to indicate second switch anyway + componentLabel = "$device.displayName Fan" + } + try { + String dni = "${device.deviceNetworkId}:1" + childDevice = addChildDevice("ITM Fan Child", dni, device.hub.id, [completedSetup: true, label: "${componentLabel}", isComponent: false]) + } catch(e) { + log.warn "Failed to add ITM Fan Controller - $e" + } + + if (childDevice != null) { + childDevice.sendEvent(name: "switch", value: "off") + } +} diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 0f71f169eab..52cb074bf55 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -38,6 +38,9 @@ metadata { // Samsung LED fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-002", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-002" //ITM RGBW + + // ABL + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-201", deviceJoinName: "Juno Connect", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-201" //E-series // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010D", manufacturer: "AduroSmart Eria", model: "AD-RGBW3001", deviceJoinName: "Eria Light" //Eria ZigBee RGBW Bulb From 02c06219bf85b161d46861d84715f10d714c7a8e Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Thu, 16 Sep 2021 10:05:31 +0800 Subject: [PATCH 056/184] repalce my own child button with smartthings offical child button --- .../min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 4f5a9fbc634..fa14ba13aad 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -137,7 +137,7 @@ private getConfigParamInput(param) { private addChildButton() { log.warn "Creating Button Device" def child = addChildDevice( - "sky-nie", + "smartthings", "Child Button", "${device.deviceNetworkId}:2", device.getHub().getId(), From bb57df34bb2030339b236d96d3ea837f556be842 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Wed, 15 Sep 2021 23:24:30 -0700 Subject: [PATCH 057/184] DevWs for Smartenit, Inc containing containing Smartenit Moisture Sensor (#71932) * DevWs for Smartenit, Inc containing containing Smartenit Moisture Sensor * Adding Moisture Sensor Child device handler * Battery report additions, constants adjustments * Indentation fixes * Spacing fixes * Removed escape from label * Added refresh to child handler --- .../moisture-sensor-child.groovy | 31 +++ .../smartenit-moisture-sensor.groovy | 180 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 devicetypes/smartenit/moisture-sensor-child.src/moisture-sensor-child.groovy create mode 100644 devicetypes/smartenit/smartenit-moisture-sensor.src/smartenit-moisture-sensor.groovy diff --git a/devicetypes/smartenit/moisture-sensor-child.src/moisture-sensor-child.groovy b/devicetypes/smartenit/moisture-sensor-child.src/moisture-sensor-child.groovy new file mode 100644 index 00000000000..ff4cf8eead3 --- /dev/null +++ b/devicetypes/smartenit/moisture-sensor-child.src/moisture-sensor-child.groovy @@ -0,0 +1,31 @@ +/** + * Moisture Sensor Child + * + * Copyright 2021 Luis Contreras + * + * 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: "Moisture Sensor Child", namespace: "Smartenit", author: "Luis Contreras") { + capability "Configuration" + capability "Refresh" + capability "Water Sensor" + capability "Health Check" + capability "Sensor" + } +} + +ping() { + refresh() +} + +refresh() { + parent.refresh() +} \ No newline at end of file diff --git a/devicetypes/smartenit/smartenit-moisture-sensor.src/smartenit-moisture-sensor.groovy b/devicetypes/smartenit/smartenit-moisture-sensor.src/smartenit-moisture-sensor.groovy new file mode 100644 index 00000000000..d5724f120a0 --- /dev/null +++ b/devicetypes/smartenit/smartenit-moisture-sensor.src/smartenit-moisture-sensor.groovy @@ -0,0 +1,180 @@ +/* + * Copyright 2016 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.clusters.iaszone.ZoneStatus +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition(name: "Smartenit Moisture Sensor", namespace: "Smartenit", author: "Luis Contreras") { + capability "Battery" + capability "Configuration" + capability "Refresh" + capability "Water Sensor" + capability "Health Check" + capability "Sensor" + + fingerprint manufacturer: "Compacta", model: "ZBLIQS", deviceJoinName: "Smartenit Moisture Sensor" + } +} + +def getBATTERY_VOLTAGE_ATTR() { 0x0020 } + +def installed() { + log.debug "Installed" + createChildDevices() +} + +private List collectAttributes(Map descMap) { + List descMaps = new ArrayList() + + descMaps.add(descMap) + + if (descMap.additionalAttrs) { + descMaps.addAll(descMap.additionalAttrs) + } + + return descMaps +} + +def parse(String description) { + log.debug "description: $description" + + // getEvent will handle temperature and humidity + Map map = zigbee.getEvent(description) + if (!map) { + if (description?.startsWith('zone status')) { + map = parseIasMessage(description) + } else { + Map descMap = zigbee.parseDescriptionAsMap(description) + + if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap?.value) { + map = getBatteryResult(Integer.parseInt(descMap.value, 16)) + } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS) { + def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16)) + map = translateZoneStatus(zs) + } + } + } + + log.debug "Parse returned $map" + def result = map ? createEvent(map) : [:] + + if (description?.startsWith('enroll request')) { + List cmds = zigbee.enrollResponse() + log.debug "enroll response: ${cmds}" + result = cmds?.collect { new physicalgraph.device.HubAction(it) } + } + return result +} + +private Map parseIasMessage(String description) { + ZoneStatus zs = zigbee.parseZoneStatus(description) + + translateZoneStatus(zs) +} + +private Map translateZoneStatus(ZoneStatus zs) { + if (zs.isAlarm2Set()) { + setChildMoistureState("wet") + } else { + setChildMoistureState("dry") + } + return zs.isAlarm1Set() ? getMoistureResult('wet') : getMoistureResult('dry') +} + +private setChildMoistureState(value) { + def childDevice = childDevices.find { + it.deviceNetworkId == "$device.deviceNetworkId:02" || it.deviceNetworkId == "$device.deviceNetworkId:02" + } + + if (childDevice) { + def map = createEvent(name: "water", value: value, translatable: true) + childDevice.sendEvent(map) + } +} + +private Map getMoistureResult(value) { + log.debug "water" + def descriptionText + if (value == "wet") { + descriptionText = '{{ device.displayName }} is wet' + } else { + descriptionText = '{{ device.displayName }} is dry' + } + return [ + name : 'water', + value : value, + descriptionText: descriptionText, + translatable : true + ] +} + +private Map getBatteryResult(rawValue) { + log.debug "Battery ${rawValue}" + def linkText = getLinkText(device) + + def result = [:] + + def volts = rawValue / 10 + if (!(rawValue == 0 || rawValue == 255)) { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) + result.descriptionText = "${linkText} battery was ${result.value}%" + result.name = 'battery' + } + + return result +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + +def refresh() { + log.debug "Refreshing Values" + + return zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) + + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_VOLTAGE_ATTR) + + zigbee.enrollResponse() +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + + log.debug "Configuring Reporting" + return refresh() + zigbee.batteryConfig() +} + +private void createChildDevices() { + try { + addChildDevice("Smartenit", "Moisture Sensor Child", "${device.deviceNetworkId}:02", device.hubId, + [completedSetup: true, + label: "${device.displayName} 2", + isComponent: false + ]) + } catch (Exception e) { + log.debug "Exception creating child device: ${e}" + } +} \ No newline at end of file From 3f1cdd530445f2d93e0a4c6eca5a7823e3ee5563 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Thu, 16 Sep 2021 17:56:01 +0900 Subject: [PATCH 058/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#75541) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * Update sihas-multipurpose-sensor.groovy Changes the log output for setPeopleCounter(peoplecounter). * Update sihas-multipurpose-sensor.groovy Add refresh for CSM300. --- .../sihas-multipurpose-sensor.groovy | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index e193f5b6e30..94ca4fef5ce 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -34,7 +34,7 @@ metadata { fingerprint inClusters: "0000,0001,0003,0020,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "OSM-300Z", deviceJoinName: "SiHAS Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2", ocfDeviceType: "x.com.st.d.sensor.motion" fingerprint inClusters: "0000,0003,0402,0001,0405", outClusters: "0004,0003,0019", manufacturer: "ShinaSystem", model: "TSM-300Z", deviceJoinName: "SiHAS Temperature/Humidity Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Temp/Humidity_Sensor", ocfDeviceType: "oic.d.thermostat" fingerprint inClusters: "0000,0001,0003,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "DSM-300Z", deviceJoinName: "SiHAS Contact Sensor", mnmn: "SmartThings", vid: "generic-contact-3", ocfDeviceType: "x.com.st.d.sensor.contact" - fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "b4e6d6e1-65e2-3f2e-8167-8ddd820f578e", ocfDeviceType: "x.com.st.d.sensor.motion" + fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "15962fd0-22b8-352e-9641-de640d672bb6", ocfDeviceType: "x.com.st.d.sensor.motion" } preferences { section { @@ -209,6 +209,12 @@ private Map getAnalogInputResult(value) { ] } +def setPeopleCounter(peoplecounter) { + int pc = Float.floatToIntBits(peoplecounter); + log.debug "SetPeopleCounter = $peoplecounter" + zigbee.writeAttribute(ANALOG_INPUT_BASIC_CLUSTER, ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE, DataType.FLOAT4, pc) +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ @@ -240,7 +246,11 @@ def refresh() { refreshCmds += zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) refreshCmds += zigbee.enrollResponse() } - + + if (isCSM300()) { + refreshCmds += zigbee.readAttribute(ANALOG_INPUT_BASIC_CLUSTER, ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE) + } + return refreshCmds } @@ -282,7 +292,7 @@ def configure() { configCmds += zigbee.configureReporting(ANALOG_INPUT_BASIC_CLUSTER, ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE, DataType.FLOAT4, 1, 600, 1) } - return refresh() + configCmds + return configCmds + refresh() } private Boolean isUSM300() { From 0baf66a7fd228608bb467b9d344f458e15eab241 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Fri, 17 Sep 2021 03:23:03 -0400 Subject: [PATCH 059/184] DevWs for Zooz (The Smartest House) containing containing Zooz Remote Switch ZEN34 (#75070) * DevWs for Zooz (The Smartest House) containing containing Zooz Remote Switch ZEN34 * Moved raw description above fingerprint * -requested change --- .../zooz-remote-switch-zen34.groovy | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 devicetypes/zooz/zooz-remote-switch-zen34.src/zooz-remote-switch-zen34.groovy diff --git a/devicetypes/zooz/zooz-remote-switch-zen34.src/zooz-remote-switch-zen34.groovy b/devicetypes/zooz/zooz-remote-switch-zen34.src/zooz-remote-switch-zen34.groovy new file mode 100644 index 00000000000..43692643328 --- /dev/null +++ b/devicetypes/zooz/zooz-remote-switch-zen34.src/zooz-remote-switch-zen34.groovy @@ -0,0 +1,323 @@ +/* + * Zooz Remote Switch ZEN34 + * + * Changelog: + * + * 2021-09-15 + * - requested change + * 2021-08-31 + * - Publication Release + * + * Copyright 2021 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x26: 3, // Switch Multilevel (4) + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5B: 1, // CentralScene (3) + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // Firmware Update Md (3) + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x87: 1, // Indicator + 0x8E: 2, // MultiChannelAssociation (3) + 0x9F: 1 // Security 2 +] + +@Field static List supportedButtonValues = ["down","down_hold","down_2x","down_3x","down_4x","down_5x","up","up_hold","up_2x","up_3x","up_4x","up_5x","down_released","up_released"] + +@Field static Map configParams = [ + ledMode: [num:1, title:"LED Indicator Mode", size:1, defaultVal:1, options:[0:"Always off", 1:"On when pressed [DEFAULT]", 2:"Always on (upper paddle color)", 3:"Always on (lower paddle color)"]], + upperPaddleLedColor: [num:2, title:"Upper Paddled LED Indicator Color", size:1, defaultVal:1, options:[0:"White", 1:"Blue [DEFAULT]", 2:"Green", 3:"Red", 4:"Magenta", 5:"Yellow", 6:"Cyan"]], + lowerPaddleLedColor: [num:3, title:"Lower Paddle LED Indicator Color", size:1, defaultVal:0, options:[0:"White [DEFAULT]", 1:"Blue", 2:"Green", 3:"Red", 4:"Magenta", 5:"Yellow", 6:"Cyan"]] +] + +@Field static int wakeUpInterval = 43200 +@Field static int btnPushed = 0 +@Field static int btnReleased = 1 +@Field static int btnHeld = 2 +@Field static int btnPushed2x = 3 +@Field static int btnPushed6x = 7 + +metadata { + definition ( + name:"Zooz Remote Switch ZEN34", + namespace:"Zooz", + author: "Kevin LaFramboise (krlaframboise)", + ocfDeviceType: "x.com.st.d.remotecontroller", + mnmn: "SmartThingsCommunity", + vid: "540fce12-499a-3b90-b276-f4159eb55f42" + ) { + capability "Sensor" + capability "Battery" + capability "Button" + capability "Refresh" + capability "Configuration" + capability "Health Check" + capability "platemusic11009.firmware" + capability "platemusic11009.syncStatus" + + fingerprint mfr: "027A", prod: "7000", model: "F001", deviceJoinName: "Zooz Remote" //Zooz Remote Switch ZEN34, raw description: zw:Ss2a type:1800 mfr:027A prod:7000 model:F001 ver:1.01 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,73,80,5B,70,84,7A + } + + preferences { + configParams.each { name, param -> + input name, "enum", + title: param.title, + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } + + input "debugLogging", "enum", + title: "Logging:", + required: false, + defaultValue: "1", + options: ["0":"Disabled", "1":"Enabled [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + state.refreshAll = true + initialize() +} + +def updated() { + logDebug "updated()..." + initialize() + + if (pendingChanges) { + logForceWakeupMessage("The setting changes will be sent to the device the next time it wakes up.") + } +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugOutput, 1) != 0) + + refreshSyncStatus() + + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((wakeUpInterval * 2) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + if (!device.currentValue("supportedButtonValues")) { + sendEvent(name:"supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed:false) + } + + if (!device.currentValue("numberOfButtons")) { + sendEvent(name:"numberOfButtons", value:1, displayed:false) + } + + if (!device.currentValue("button")) { + sendButtonEvent("up") + } +} + +def configure() { + logDebug "configure()..." + List cmds = [] + + if (state.refreshAll || !device.currentValue("firmwareVersion")) { + cmds << secureCmd(zwave.versionV1.versionGet()) + } + + if (state.refreshAll || !device.currentValue("battery")) { + cmds << secureCmd(zwave.batteryV1.batteryGet()) + } + + state.refreshAll = false + + if (state.wakeUpInterval != wakeUpInterval) { + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalSet(seconds: wakeUpInterval, nodeid: zwaveHubNodeId)) + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + logDebug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + if (cmds) { + sendHubCommand(cmds, 500) + } +} + +def ping() { + logDebug "ping()..." +} + +def refresh() { + logDebug "refresh()..." + state.refreshAll = true + + refreshSyncStatus() + + logForceWakeupMessage("The next time the device wakes up, the sensor data will be requested.") +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + logDebug "$cmd" + runIn(4, refreshSyncStatus) + state.wakeUpInterval = cmd.seconds +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + logDebug "Device Woke Up..." + runIn(4, refreshSyncStatus) + configure() + sendHubCommand([secureCmd(zwave.wakeUpV2.wakeUpNoMoreInformation())]) +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + state[name] = val + logDebug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEvent(name: "firmwareVersion", value: (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def val = (cmd.batteryLevel == 0xFF ? 1 : cmd.batteryLevel) + if (val > 100) { + val = 100 + } + logDebug "Battery is ${val}%" + sendEvent(name:"battery", value:val, unit:"%", isStateChange: true) +} + +void zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd){ + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + + String paddle = (cmd.sceneNumber == 1) ? "up" : "down" + String btnVal + switch (cmd.keyAttributes){ + case btnPushed: + btnVal = paddle + break + case btnReleased: + logDebug "${paddle}_released is not supported by SmartThings" + btnVal = paddle + "_released" + break + case btnHeld: + btnVal = paddle + "_hold" + break + case { it >= btnPushed2x && it <= btnPushed6x}: + btnVal = paddle + "_${cmd.keyAttributes - 1}x" + break + default: + logDebug "keyAttributes ${cmd.keyAttributes} not supported" + } + + if (btnVal) { + sendButtonEvent(btnVal) + } + } +} + +void sendButtonEvent(String value) { + String desc = "${device.displayName} ${value}" + logDebug(desc) + sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true, descriptionText: desc) +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +void logForceWakeupMessage(String msg) { + log.warn "${msg} You can force the device to wake up immediately by tapping the upper paddle 7x." +} + +Integer getPendingChanges() { + int configChanges = safeToInt(configParams.count { name, param -> + (getSettingVal(name) != getStoredVal(name)) + }, 0) + int pendingWakeUpInterval = (state.wakeUpInterval != wakeUpInterval ? 1 : 0) + return (configChanges + pendingWakeUpInterval) +} + +Integer getSettingVal(String name) { + return (settings ? safeToInt(settings[name], null) : null) +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From 1da0f5f643afff721880e2f7cdb1f9f372042bcc Mon Sep 17 00:00:00 2001 From: Winnie Wen Date: Wed, 22 Sep 2021 10:48:04 +0800 Subject: [PATCH 060/184] Remove the function related to CentralScene --- .../min-smart-plug-dimmer.groovy | 77 ++----------------- 1 file changed, 5 insertions(+), 72 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index fa14ba13aad..1a92fad2b4d 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v2.1.1 + * Min Smart Plug Dimmer v2.2.0 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,10 @@ * * Changelog: * + * 2.2.0 (09/22/2021) + * - Remove the function related to CentralScene-the function did not achieve the expected effect, + * and it can be replaced by the Automation function in the SmartThings APP + * * 2.1.1 (09/07/2021) * - Syntax format compliance adjustment * - delete dummy code @@ -134,55 +138,6 @@ private getConfigParamInput(param) { } } -private addChildButton() { - log.warn "Creating Button Device" - def child = addChildDevice( - "smartthings", - "Child Button", - "${device.deviceNetworkId}:2", - device.getHub().getId(), - [ - completedSetup: true, - isComponent: false, - label: "plugButton", - componentLabel: "${device.displayName[0..-8]} Button" - ] - ) - child?.sendEvent(name:"supportedButtonValues", value:JsonOutput.toJson(["pushed", "down", "down_2x", "up", "up_2x"]), displayed:false) - child?.sendEvent(name:"numberOfButtons", value:1, displayed:false) - sendButtonEvent("pushed") - return child -} - -def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { - logTrace "CentralSceneNotification: ${cmd}" - if (state.lastSequenceNumber != cmd.sequenceNumber) { - state.lastSequenceNumber = cmd.sequenceNumber - logTrace "${cmd}" - def paddle = (cmd.sceneNumber == 1) ? "down" : "up" - def btnVal - switch (cmd.keyAttributes) { - case 0: - btnVal = paddle - break - case 3: - btnVal = paddle + "_2x" - break - } - - if (btnVal) { - sendButtonEvent(btnVal) - } - } - return [] -} - -private sendButtonEvent(value) { - if (childDevices) { - childDevices[0].sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) - } -} - def ping() { logDebug "ping()..." return [ switchMultilevelGetCmd() ] @@ -216,13 +171,6 @@ def updated() { if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } - if (isButtonAvailable() && !childDevices) { - try { - addChildButton() - } catch (ex) { - log.error("Unable to create button device because the 'Child Button' DTH is not installed", ex) - } - } runIn(5, executeConfigureCmds, [overwrite: true]) } return [] @@ -333,7 +281,6 @@ private static getCommandClassVersions() { [ 0x20: 1, // Basic 0x26: 3, // Switch Multilevel - 0x5B: 1, // CentralScene (3) 0x55: 1, // Transport Service 0x59: 1, // AssociationGrpInfo 0x5A: 1, // DeviceResetLocally @@ -560,20 +507,6 @@ private sendSwitchEvents(rawVal, type) { if (rawVal) { sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") } - if (isButtonAvailable() && type == "physical") { - if (paddleControlParam.value == 2) { - sendButtonEvent("pushed") - } else { - def paddlesReversed = (paddleControlParam.value == 1) - def btnVal = ((rawVal && !paddlesReversed) || (!rawVal && paddlesReversed)) ? "up" : "down" - def oldSwitch = device.currentValue("switch") - def oldLevel = device.currentValue("level") - if ((oldSwitch == "on") && (btnVal == "up") && (oldLevel > rawVal)) { - btnVal = "down" - } - sendButtonEvent(btnVal) - } - } } private isButtonAvailable() { From 191cfdf788cfffd119c55b71ba576d1d6f9f78e3 Mon Sep 17 00:00:00 2001 From: Taejun Park Date: Thu, 23 Sep 2021 12:43:04 +0900 Subject: [PATCH 061/184] Add parsing logic of default response command --- .../zigbee-multi-switch.src/zigbee-multi-switch.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index 644fecf6490..62a9322e630 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -134,7 +134,7 @@ def parse(String description) { Map eventDescMap = zigbee.parseDescriptionAsMap(description) if (eventMap) { - if (eventDescMap && eventDescMap?.attrId == "0000") {//0x0000 : OnOff attributeId + if (eventDescMap && (eventDescMap?.attrId == "0000" || eventDescMap?.command == "0B")) {//0x0000 : OnOff attributeId, 0x0B : default response command if (eventDescMap?.sourceEndpoint == "01" || eventDescMap?.endpoint == "01") { sendEvent(eventMap) } else { @@ -293,4 +293,4 @@ private getChildCount() { default: return 2 } -} \ No newline at end of file +} From b7563cdaa3f2060a2bfaa6679f85d117a4d52da2 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Mon, 27 Sep 2021 14:59:53 +0900 Subject: [PATCH 062/184] DevWs for SHINA SYSTEM containing containing Zigbee Metering Plug (#75962) Adding the device handler for SHINA SYSTEM Zigbee Metering Plug. --- .../zigbee-metering-plug.src/zigbee-metering-plug.groovy | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 a280ced8888..795cf0d3d5a 100644 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -39,6 +39,7 @@ metadata { fingerprint manufacturer: "Jasco Products", model: "43095", deviceJoinName: "Enbrighten Outlet" //Enbrighten Plug-in Smart Switch With Energy Monitoring 43095, Raw Description: 01 0104 0100 00 07 0000 0003 0004 0005 0006 0702 0B05 02 000A 0019 fingerprint manufacturer: "Jasco Products", model: "43132", deviceJoinName: "Jasco Outlet" //Enbrighten In-Wall Smart Outlet With Energy Monitoring 43132, Raw Description: 01 0104 0100 00 07 0000 0003 0004 0005 0006 0702 0B05 02 000A 0019 fingerprint manufacturer: "Jasco Products", model: "43078", deviceJoinName: "Enbrighten Switch", ocfDeviceType: "oic.d.switch" //Enbrighten In-Wall Smart Switch With Energy Monitoring 43078, Raw Description: 01 0104 0100 00 07 0000 0003 0004 0005 0006 0702 0B05 02 000A 0019 + fingerprint inClusters: "0000,0001,0003,0006,0020,0B04,0702", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CCM-300Z", deviceJoinName: "SiHAS Outlet" // SIHAS Smart Plug with on/off button } tiles(scale: 2){ @@ -168,7 +169,7 @@ private int getPowerDiv() { } private int getEnergyDiv() { - (isSengledOutlet() || isJascoProductsOutlet()) ? 10000 : isFrientOutlet() ? 1000 : 100 + (isSengledOutlet() || isJascoProductsOutlet()) ? 10000 : (isFrientOutlet() || isCCM300()) ? 1000 : 100 } private boolean isSengledOutlet() { @@ -182,3 +183,7 @@ private boolean isJascoProductsOutlet() { private boolean isFrientOutlet() { device.getDataValue("manufacturer") == "frient A/S" } + +private Boolean isCCM300() { + device.getDataValue("model") == "CCM-300Z" +} From 3fa5c24c3edb3a625379c98c1f84a8b3e496bb04 Mon Sep 17 00:00:00 2001 From: frient-design <73893001+frient-design@users.noreply.github.com> Date: Wed, 29 Sep 2021 09:49:02 +0200 Subject: [PATCH 063/184] DevWs for frient containing containing Zigbee Non-Holdable Button (#75979) * DevWs for frient containing containing Zigbee Non-Holdable Button * Fix device join name Co-authored-by: Mohammed Kemal Co-authored-by: rboy1 <3846367+rboy1@users.noreply.github.com> --- .../zigbee-non-holdable-button.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy b/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy index c5267f6ad80..6f2bb0260ec 100644 --- a/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy +++ b/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy @@ -27,6 +27,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0500", outClusters: "0019", manufacturer: "HEIMAN", model: "SOS-EM", deviceJoinName: "HEIMAN Button" //HEIMAN Emergency Button fingerprint manufacturer: "frient A/S", model: "MBTZB-110", deviceJoinName: "frient Button" // Frient Smart Button, 20 0104 0007 00 05 0000 0001 0003 000F 0020 04 0003 0006 000A 0019 + fingerprint manufacturer: "frient A/S", model: "SBTZB-110", deviceJoinName: "frient Button" // Frient Smart Button, 20 0104 0007 00 05 0000 0001 0003 000F 0020 04 0003 0006 000A 0019 fingerprint manufacturer: "eWeLink", model: "KF01", deviceJoinName: "eWeLink Button" // 01 0104 0402 00 04 0000 0003 0500 0001 01 0003 } @@ -225,4 +226,4 @@ private getLiIon3VTable() {[ 2.0: 1, 1.9: 0, 0.0: 0 -]} \ No newline at end of file +]} From ffe10c3c160819bf347ef3884f8c995b421d6b2f Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 6 Oct 2021 00:53:19 +0800 Subject: [PATCH 064/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug (#74784) * DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug * preferences content adjust * * - Syntax format compliance adjustment * - fix a bugs * * - Syntax format compliance adjustment * - fix some bugs * Syntax format compliance adjustment * Syntax format compliance adjustment * 1.restore removeChildButton; 2.Simplify the code * delete dummy code. * * - remove the preferences item "createButton", Fixedly create a child button * Restrict its use based on fingerprints--because the child buttons is not visible to the user . * - fix a bug: when isButtonAvailable() return false,getLedModeParam is conflict with getPaddleControlParam * - Simplify the code, Syntax format compliance adjustment * Syntax format compliance adjustment * * - Syntax format compliance adjustment * - delete dummy code * add removeChildButton in updated() when isButtonAvailable() return false * restore addChildButton in updated() when it' needed. * * - Syntax format compliance adjustment * - delete dummy code * Syntax format compliance adjustment as PR review * Delete devicetypes/sky-nie/child-button.src directory repalce my own child button with smartthings offical child button * repalce my own child button with smartthings offical child button * Remove the function related to CentralScene Co-authored-by: Winnie Wen --- .../min-smart-plug.src/min-smart-plug.groovy | 177 +++++++++++------- 1 file changed, 111 insertions(+), 66 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy index 0d4a00d1dc5..ffb60b0eee4 100644 --- a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy +++ b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy @@ -1,7 +1,7 @@ /** - * Min Smart Plug v1.0.4 + * Min Smart Plug v2.2.0 * - * Models: MINOSTON (MP21Z) + * Models: MINOSTON (MP21Z) And Eva Logik (ZW30) / MINOSTON (MS10Z) * * Author: * winnie (sky-nie) @@ -10,6 +10,28 @@ * * Changelog: * + * 2.2.0 (09/22/2021) + * - Remove the function related to CentralScene-the function did not achieve the expected effect, + * and it can be replaced by the Automation function in the SmartThings APP + * + * 2.1.1 (09/07/2021) + * - Syntax format compliance adjustment + * - delete dummy code + * + * 2.1.0 (09/04/2021) + * - remove the preferences item "createButton", Fixedly create a child button + * Restrict its use based on fingerprints--because the child buttons is not visible to the user . + * - fix a bug: when isButtonAvailable() return false,getLedModeParam is conflict with getPaddleControlParam + * - Simplify the code, Syntax format compliance adjustment + * + * 2.0.2 (09/02/2021) + * 2.0.1 (08/27/2021) + * - Syntax format compliance adjustment + * - fix some bugs + * + * 2.0.0 (08/26/2021) + * - add new products supported + * * 1.0.4 (07/13/2021) * - Syntax format compliance adjustment * - delete dummy code @@ -40,9 +62,10 @@ * limitations under the License. * */ +import groovy.json.JsonOutput metadata { - definition (name: "Min Smart Plug", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-switch", ocfDeviceType: "oic.d.smartplug") { + definition (name: "Min Smart Plug", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-switch") { capability "Actuator" capability "Sensor" capability "Switch" @@ -53,21 +76,34 @@ metadata { attribute "firmwareVersion", "string" attribute "syncStatus", "string" - fingerprint mfr: "0312", prod: "C000", model: "C009", deviceJoinName: "Minoston Outlet" // old MP21Z - fingerprint mfr: "0312", prod: "FF00", model: "FF0C", deviceJoinName: "Minoston Outlet" //MP21Z Minoston Mini Smart Plug - fingerprint mfr: "0312", prod: "AC01", model: "4001", deviceJoinName: "New One Outlet" // N4001 New One Mini Smart Plug + fingerprint mfr: "0312", prod: "C000", model: "C009", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" // old MP21Z + fingerprint mfr: "0312", prod: "FF00", model: "FF0C", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //MP21Z Minoston Mini Smart Plug + fingerprint mfr: "0312", prod: "AC01", model: "4001", deviceJoinName: "New One Outlet", ocfDeviceType: "oic.d.smartplug" // N4001 New One Mini Smart Plug + fingerprint mfr: "0312", prod: "EE00", model: "EE01", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS10ZS Minoston Smart Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE03", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS12ZS Minoston Smart on/off Toggle Switch + fingerprint mfr: "0312", prod: "A000", model: "A005", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30 + fingerprint mfr: "0312", prod: "BB00", model: "BB01", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30S Evalogik Smart on/off Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB03", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30TS Evalogik Smart on/off Toggle Switch } preferences { - configParams.each { - if (it.name) { - if (it.range) { - input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range - } else { - input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options - } - } - } + getConfigParamInput(ledModeParam) + getConfigParamInput(autoOffIntervalParam) + getConfigParamInput(autoOnIntervalParam) + getConfigParamInput(powerFailureRecoveryParam) + input "disclaimer", "paragraph", + title: "WARNING", + description: "Configuring for 'Paddle Control'is only valid for the devices with product number of MS10ZS, MS12ZS, ZW30, ZW30S, ZW30TS(one of them)", + required: false + getConfigParamInput(paddleControlParam) + } +} + +private getConfigParamInput(param) { + if (param.range) { + input "configParam${param.num}", "number", title: "${param.name}:", required: false, defaultValue: "${param.value}", range: param.range + } else { + input "configParam${param.num}", "enum", title: "${param.name}:", required: false, defaultValue: "${param.value}", options: param.options } } @@ -85,12 +121,10 @@ private static def getCheckInterval() { def updated() { if (!isDuplicateCommand(state.lastUpdated, 5000)) { state.lastUpdated = new Date().time - logDebug "updated()..." if (device.latestValue("checkInterval") != checkInterval) { sendEvent(name: "checkInterval", value: checkInterval, displayed: false) } - runIn(5, executeConfigureCmds, [overwrite: true]) } return [] @@ -98,7 +132,6 @@ def updated() { def configure() { logDebug "configure()..." - if (state.resyncAll == null) { state.resyncAll = true runIn(8, executeConfigureCmds, [overwrite: true]) @@ -116,20 +149,10 @@ def executeConfigureCmds() { def cmds = [] - if (!device.currentValue("switch")) { - cmds << switchBinaryGetCmd() - } - - if (state.resyncAll || !device.currentValue("firmwareVersion")) { - cmds << secureCmd(zwave.versionV1.versionGet()) - } - configParams.each { param -> def storedVal = getParamStoredValue(param.num) def paramVal = param.value - if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { - logDebug "Changing ${param.name}(#${param.num}) from ${storedVal} to ${paramVal}" cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) } @@ -137,7 +160,7 @@ def executeConfigureCmds() { state.resyncAll = false if (cmds) { - sendCommands(delayBetween(cmds, 500)) + sendHubCommand(cmds, 500) } return [] } @@ -160,18 +183,7 @@ def off() { def refresh() { logDebug "refresh()..." refreshSyncStatus() - sendCommands([switchBinaryGetCmd()]) -} - -private sendCommands(cmds) { - if (cmds) { - def actions = [] - cmds.each { - actions << new physicalgraph.device.HubAction(it) - } - sendHubCommand(actions) - } - return [] + return [ switchBinaryGetCmd() ] } private switchBinaryGetCmd() { @@ -190,6 +202,7 @@ private secureCmd(cmd) { return cmd.format() } } catch (ex) { + log.error("secureCmd exception", ex) return cmd.format() } } @@ -210,8 +223,8 @@ def parse(String description) { } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + logTrace "SecurityMessageEncapsulation: ${cmd}" def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) - def result = [] if (encapsulatedCmd) { result += zwaveEvent(encapsulatedCmd) @@ -222,11 +235,9 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { - logTrace "${cmd}" - + logTrace "ConfigurationReport: ${cmd}" sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) runIn(4, refreshSyncStatus) - def param = configParams.find { it.num == cmd.parameterNumber } if (param) { def val = cmd.scaledConfigurationValue @@ -240,28 +251,27 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { logTrace "VersionReport: ${cmd}" - def subVersion = String.format("%02d", cmd.applicationSubVersion) def fullVersion = "${cmd.applicationVersion}.${subVersion}" - sendEvent(name: "firmwareVersion", value: fullVersion) return [] } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { - logTrace "${cmd}" + logTrace "BasicReport: ${cmd}" sendSwitchEvents(cmd.value, "physical") return [] } def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { - logTrace "${cmd}" + logTrace "SwitchBinaryReport: ${cmd}" sendSwitchEvents(cmd.value, "digital") return [] } private sendSwitchEvents(rawVal, type) { - sendEvent(name: "switch", value: (rawVal == 0xFF) ? "on" : "off", displayed: true, type: type) + def switchVal = (rawVal == 0xFF) ? "on" : "off" + sendEvent(name: "switch", value: switchVal, displayed: true, type: type) } def zwaveEvent(physicalgraph.zwave.Command cmd) { @@ -309,29 +319,46 @@ private getConfigParams() { ledModeParam, autoOffIntervalParam, autoOnIntervalParam, - powerFailureRecoveryParam + powerFailureRecoveryParam, + paddleControlParam + ] +} + +private static getPaddleControlOptions() { + return [ + "0":"Normal", + "1":"Reverse", + "2":"Toggle" ] } +private getPaddleControlParam() { + def num = isButtonAvailable()? 1 : 1000 + return getParam(num, "Paddle Control", 1, 0, paddleControlOptions) +} + private getLedModeParam() { - return getParam(1, "LED Indicator Mode", 1, 0, ledModeOptions) + def num = isButtonAvailable()? 2 : 1 + return getParam(num, "LED Indicator Mode", 1, 0, alternativeLedOptions) } private getAutoOffIntervalParam() { - return getParam(2, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") + def num = isButtonAvailable()? 4 : 2 + return getParam(num, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getAutoOnIntervalParam() { - return getParam(4, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") + def num = isButtonAvailable()? 6 : 4 + return getParam(num, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getPowerFailureRecoveryParam() { - return getParam(6, "Power Failure Recovery", 1, 0, powerFailureRecoveryOptions) + def num = isButtonAvailable()? 8 : 6 + return getParam(num, "Power Failure Recovery", 1, 0, powerFailureRecoveryOptions) } -private getParam(num, name, size, defaultVal, options=null, range=null) { +private getParam(num, name, size, defaultVal, options = null, range = null) { def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) - def map = [num: num, name: name, size: size, value: val] if (options) { map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value @@ -340,7 +367,6 @@ private getParam(num, name, size, defaultVal, options=null, range=null) { if (range) { map.range = range } - return map } @@ -353,12 +379,21 @@ private static setDefaultOption(options, defaultVal) { } } -private static getLedModeOptions() { - return [ - "0":"On When On", - "1":"Off When On", - "2":"Always Off" - ] +private getAlternativeLedOptions() { + if (isButtonAvailable()) { + return [ + "0":"On When On", + "1":"Off When On", + "2":"Always Off" + ] + } else { + return [ + "0":"Off When On", + "1":"On When On", + "2":"Always Off", + "3":"Always On" + ] + } } private static getPowerFailureRecoveryOptions() { @@ -369,7 +404,7 @@ private static getPowerFailureRecoveryOptions() { ] } -private static safeToInt(val, defaultVal=0) { +private static safeToInt(val, defaultVal = 0) { return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal } @@ -383,4 +418,14 @@ private logDebug(msg) { private logTrace(msg) { log.trace "$msg" -} \ No newline at end of file +} + +private isButtonAvailable() { + if (device == null) { + log.error "isButtonAvailable device = null" + return true + } else { + log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" + return "${device.rawDescription}".contains("model:EE01") || "${device.rawDescription}".contains("model:EE03") || "${device.rawDescription}".contains("model:A005") || "${device.rawDescription}".contains("model:BB01") || "${device.rawDescription}".contains("model:BB03") + } +} From d1ecbacd7ea9f9aea34d7db861bed46440769954 Mon Sep 17 00:00:00 2001 From: Dawid Sobierajski <89920842+dsobierajsk@users.noreply.github.com> Date: Tue, 5 Oct 2021 22:44:50 +0200 Subject: [PATCH 065/184] ICP-14305, ICP-14310 - fixes (#76007) * fixes ICP-14305, ICP-14310 * clean --- .../zwave-metering-switch.groovy | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 507ec4b53e2..feb0c8051a2 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -211,18 +211,30 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { [:] } +def isEverspringOutlet() { + return zwaveInfo.mfr == "0060" && zwaveInfo.prod == "0004" && zwaveInfo.model == "000B" +} + +def getDelay() { + if(isEverspringOutlet()){ + return 1000 + } else { + return 3000 + } +} + def on() { encapSequence([ zwave.basicV1.basicSet(value: 0xFF), zwave.switchBinaryV1.switchBinaryGet() - ], 3000) + ], getDelay()) } def off() { encapSequence([ zwave.basicV1.basicSet(value: 0x00), zwave.switchBinaryV1.switchBinaryGet() - ], 3000) + ], getDelay()) } /** From 49486dceca37fe9f3924c66132b19f136d4ac3a6 Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 12 Oct 2021 15:09:27 -0700 Subject: [PATCH 066/184] BUG-3640 Update lock code events Some lock code events were using undocumented fields. --- .../zigbee-lock.src/zigbee-lock.groovy | 17 ++----- .../zwave-lock.src/zwave-lock.groovy | 44 ++++++------------- 2 files changed, 17 insertions(+), 44 deletions(-) diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index 45cf8378873..299840f8888 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -423,7 +423,7 @@ def nameSlot(codeSlot, codeName) { def newCodeName = codeName ?: "Code $codeSlot" lockCodes[codeSlot] = newCodeName sendEvent(lockCodesEvent(lockCodes)) - sendEvent(name: "codeChanged", value: "$codeSlot renamed", data: [ lockName: deviceName, notify: false, notificationText: "Renamed \"$oldCodeName\" to \"$newCodeName\" in $deviceName at ${location.name}" ], + sendEvent(name: "codeChanged", value: "$codeSlot renamed", data: [ notify: false, notificationText: "Renamed \"$oldCodeName\" to \"$newCodeName\" in $deviceName at ${location.name}" ], descriptionText: "Renamed \"$oldCodeName\" to \"$newCodeName\"", displayed: true, isStateChange: true) } } @@ -523,11 +523,6 @@ private def parseAttributeResponse(String description) { return null } - if (responseMap.data) { - responseMap.data.lockName = deviceName - } else { - responseMap.data = [ lockName: deviceName ] - } result << createEvent(responseMap) log.info "ZigBee DTH - parseAttributeResponse() returning with result:- $result" return result @@ -585,7 +580,7 @@ private def parseCommandResponse(String description) { return null } codeName = getCodeName(lockCodes, codeID) - responseMap.data = [ codeId: codeID as String, usedCode: codeID, codeName: codeName, method: "keypad" ] + responseMap.data = [ codeId: codeID as String, codeName: codeName, method: "keypad" ] } else if (eventSource == 1) { responseMap.data = [ method: "command" ] } else if (eventSource == 2) { @@ -858,11 +853,6 @@ private def parseCommandResponse(String description) { } if(responseMap["value"]) { - if (responseMap.data) { - responseMap.data.lockName = deviceName - } else { - responseMap.data = [ lockName: deviceName ] - } result << createEvent(responseMap) } if (result) { @@ -931,8 +921,7 @@ private def allCodesDeletedEvent() { def codeName = code result << createEvent(name: "codeChanged", value: "$id deleted", - data: [ codeName: codeName, lockName: deviceName, notify: true, - notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ], + data: [ codeName: codeName, notify: true, notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ], descriptionText: "Deleted \"$codeName\"", displayed: true, isStateChange: true) clearStateForSlot(id) diff --git a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy index 4b654e85bbc..39af5e53372 100644 --- a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy +++ b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy @@ -283,8 +283,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport log.trace "[DTH] Executing 'ConfigurationReport' for device $deviceName - all codes deleted" result = allCodesDeletedEvent() result << createEvent(name: "codeChanged", value: "all deleted", descriptionText: "Deleted all user codes", - isStateChange: true, data: [lockName: deviceName, notify: true, - notificationText: "Deleted all user codes in $deviceName at ${location.name}"]) + isStateChange: true, data: [notify: true, notificationText: "Deleted all user codes in $deviceName at ${location.name}"]) result << createEvent(name: "lockCodes", value: util.toJson([:]), displayed: false, descriptionText: "'lockCodes' attribute updated") } result << createEvent(name:"codeLength", value: length, descriptionText: "Code length is $length", displayed: false) @@ -356,7 +355,6 @@ def zwaveEvent(DoorLockOperationReport cmd) { // DoorLockOperationReport is called when trying to read the lock state or when the lock is locked/unlocked from the DTH or the smart app def map = [ name: "lock" ] - map.data = [ lockName: device.displayName ] if (isKeyweLock()) { map.value = cmd.doorCondition >> 1 ? "unlocked" : "locked" map.descriptionText = cmd.doorCondition >> 1 ? "Unlocked" : "Locked" @@ -459,7 +457,7 @@ private def handleAccessAlarmReport(cmd) { codeID = readCodeSlotId(cmd) codeName = getCodeName(lockCodes, codeID) map.descriptionText = "Locked by \"$codeName\"" - map.data = [ codeId: codeID as String, usedCode: codeID, codeName: codeName, method: "keypad" ] + map.data = [ codeId: codeID as String, codeName: codeName, method: "keypad" ] } else { // locked by pressing the Schlage button map.descriptionText = "Locked manually" @@ -471,7 +469,7 @@ private def handleAccessAlarmReport(cmd) { codeID = readCodeSlotId(cmd) codeName = getCodeName(lockCodes, codeID) map.descriptionText = "Unlocked by \"$codeName\"" - map.data = [ codeId: codeID as String, usedCode: codeID, codeName: codeName, method: "keypad" ] + map.data = [ codeId: codeID as String, codeName: codeName, method: "keypad" ] } break case 7: @@ -569,11 +567,6 @@ private def handleAccessAlarmReport(cmd) { } if (map) { - if (map.data) { - map.data.lockName = deviceName - } else { - map.data = [ lockName: deviceName ] - } result << createEvent(map) } result = result.flatten() @@ -594,7 +587,6 @@ private def handleBurglarAlarmReport(cmd) { def deviceName = device.displayName def map = [ name: "tamper", value: "detected" ] - map.data = [ lockName: deviceName ] switch (cmd.zwaveAlarmEvent) { case 0: map.value = "clear" @@ -639,10 +631,10 @@ private def handleBatteryAlarmReport(cmd) { result << response(secure(zwave.batteryV1.batteryGet())) break; case 0x0A: - map = [ name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true, data: [ lockName: deviceName ] ] + map = [ name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true] break case 0x0B: - map = [ name: "battery", value: 0, descriptionText: "Battery too low to operate lock", isStateChange: true, displayed: true, data: [ lockName: deviceName ] ] + map = [ name: "battery", value: 0, descriptionText: "Battery too low to operate lock", isStateChange: true, displayed: true] break default: // delegating it to handleAlarmReportUsingAlarmType @@ -680,7 +672,7 @@ private def handleAlarmReportUsingAlarmType(cmd) { codeName = getCodeName(lockCodes, codeID) map.isStateChange = true // Non motorized locks, mark state changed since it can be unlocked multiple times map.descriptionText = "Unlocked by \"$codeName\"" - map.data = [ codeId: codeID as String, usedCode: codeID, codeName: codeName, method: "keypad" ] + map.data = [ codeId: codeID as String, codeName: codeName, method: "keypad" ] } break case 18: // Locked with keypad @@ -693,7 +685,7 @@ private def handleAlarmReportUsingAlarmType(cmd) { } else { codeName = getCodeName(lockCodes, codeID) map.descriptionText = "Locked by \"$codeName\"" - map.data = [ codeId: codeID as String, usedCode: codeID, codeName: codeName, method: "keypad" ] + map.data = [ codeId: codeID as String, codeName: codeName, method: "keypad" ] } break case 21: // Manually locked @@ -808,11 +800,6 @@ private def handleAlarmReportUsingAlarmType(cmd) { } if (map) { - if (map.data) { - map.data.lockName = deviceName - } else { - map.data = [ lockName: deviceName ] - } result << createEvent(map) } result = result.flatten() @@ -854,13 +841,12 @@ def zwaveEvent(UserCodeReport cmd) { map.value = "$codeID $changeType" map.isStateChange = true map.descriptionText = "${getStatusForDescription(changeType)} \"$codeName\"" - map.data = [ codeName: codeName, lockName: deviceName, notify: true, notificationText: "${getStatusForDescription(changeType)} \"$codeName\" in $deviceName at ${location.name}" ] + map.data = [ codeName: codeName, notify: true, notificationText: "${getStatusForDescription(changeType)} \"$codeName\" in $deviceName at ${location.name}" ] if(!isMasterCode(codeID)) { result << codeSetEvent(lockCodes, codeID, codeName) } else { map.descriptionText = "${getStatusForDescription('set')} \"$codeName\"" map.data.notificationText = "${getStatusForDescription('set')} \"$codeName\" in $deviceName at ${location.name}" - map.data.lockName = deviceName } } else { // We'll land here during scanning of codes @@ -873,14 +859,14 @@ def zwaveEvent(UserCodeReport cmd) { } map.value = "$codeID $changeType" map.descriptionText = "${getStatusForDescription(changeType)} \"$codeName\"" - map.data = [ codeName: codeName, lockName: deviceName ] + map.data = [ codeName: codeName ] } } else if(userIdStatus == 254 && isSchlageLock()) { // This is code creation/updation error for Schlage locks. // It should be OK to mark this as duplicate pin code error since in case the batteries are down, or lock is not in range, // or wireless interference is there, the UserCodeReport will anyway not be received. map = [ name: "codeChanged", value: "$codeID failed", descriptionText: "User code is not added", isStateChange: true, - data: [ lockName: deviceName, isCodeDuplicate: true] ] + data: [ isCodeDuplicate: true] ] } else { // We are using userIdStatus here because codeID = 0 is reported when user tries to set programming code as the user code if (codeID == "0" && userIdStatus == UserCodeReport.USER_ID_STATUS_AVAILABLE_NOT_SET && isSchlageLock()) { @@ -888,7 +874,7 @@ def zwaveEvent(UserCodeReport cmd) { log.trace "[DTH] All user codes deleted for Schlage lock" result << allCodesDeletedEvent() map = [ name: "codeChanged", value: "all deleted", descriptionText: "Deleted all user codes", isStateChange: true, - data: [ lockName: deviceName, notify: true, + data: [ notify: true, notificationText: "Deleted all user codes in $deviceName at ${location.name}"] ] lockCodes = [:] result << lockCodesEvent(lockCodes) @@ -898,12 +884,11 @@ def zwaveEvent(UserCodeReport cmd) { def codeName = getCodeName(lockCodes, codeID) map.value = "$codeID deleted" map.descriptionText = "Deleted \"$codeName\"" - map.data = [ codeName: codeName, lockName: deviceName, notify: true, notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ] + map.data = [ codeName: codeName, notify: true, notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ] result << codeDeletedEvent(lockCodes, codeID) } else { map.value = "$codeID unset" map.displayed = false - map.data = [ lockName: deviceName ] } } } @@ -1425,7 +1410,7 @@ void nameSlot(codeSlot, codeName) { def newCodeName = codeName ?: "Code $codeSlot" lockCodes[codeSlot] = newCodeName sendEvent(lockCodesEvent(lockCodes)) - sendEvent(name: "codeChanged", value: "$codeSlot renamed", data: [ lockName: deviceName, notify: false, notificationText: "Renamed \"$oldCodeName\" to \"$newCodeName\" in $deviceName at ${location.name}" ], + sendEvent(name: "codeChanged", value: "$codeSlot renamed", data: [ notify: false, notificationText: "Renamed \"$oldCodeName\" to \"$newCodeName\" in $deviceName at ${location.name}" ], descriptionText: "Renamed \"$oldCodeName\" to \"$newCodeName\"", displayed: true, isStateChange: true) } @@ -1642,8 +1627,7 @@ private def allCodesDeletedEvent() { displayed: false, isStateChange: true) def codeName = code - result << createEvent(name: "codeChanged", value: "$id deleted", data: [ codeName: codeName, lockName: deviceName, - notify: true, notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ], + result << createEvent(name: "codeChanged", value: "$id deleted", data: [ codeName: codeName, notify: true, notificationText: "Deleted \"$codeName\" in $deviceName at ${location.name}" ], descriptionText: "Deleted \"$codeName\"", displayed: true, isStateChange: true) clearStateForSlot(id) From e708a886242791c090597886d5ccbe160d10e1b7 Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 12 Oct 2021 15:11:57 -0700 Subject: [PATCH 067/184] a few missing from other lock dths --- .../samsung-smart-doorlock.groovy | 6 ------ .../zwave-lock-without-codes.groovy | 15 ++------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy b/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy index 3ee4c5f3868..84e9699746e 100755 --- a/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy +++ b/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy @@ -194,7 +194,6 @@ private def parseAttributeResponse(String description) { return null } - responseMap.data = [ lockName: deviceName ] result << createEvent(responseMap) log.info "ZigBee DTH - parseAttributeResponse() returning with result:- $result" return result @@ -386,11 +385,6 @@ private def parseCommandResponse(String description) { } if (responseMap["value"]) { - if (responseMap.data) { - responseMap.data.lockName = deviceName - } else { - responseMap.data = [ lockName: deviceName ] - } result << createEvent(responseMap) } if (result) { diff --git a/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy b/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy index 964f9376f74..410f05c316b 100644 --- a/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy +++ b/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy @@ -278,7 +278,6 @@ def zwaveEvent(DoorLockOperationReport cmd) { // DoorLockOperationReport is called when trying to read the lock state or when the lock is locked/unlocked from the DTH or the smart app def map = [name: "lock"] - map.data = [lockName: device.displayName] if (cmd.doorLockMode == 0xFF) { map.value = "locked" map.descriptionText = "Locked" @@ -383,11 +382,6 @@ private def handleAccessAlarmReport(cmd) { } if (map) { - if (map.data) { - map.data.lockName = deviceName - } else { - map.data = [lockName: deviceName] - } result << createEvent(map) } result = result.flatten() @@ -414,10 +408,10 @@ private def handleBatteryAlarmReport(cmd) { result << response(secure(zwave.batteryV1.batteryGet())) break; case 0x0A: - map = [name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true, data: [lockName: deviceName]] + map = [name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true] break case 0x0B: - map = [name: "battery", value: 0, descriptionText: "Battery too low to operate lock", isStateChange: true, displayed: true, data: [lockName: deviceName]] + map = [name: "battery", value: 0, descriptionText: "Battery too low to operate lock", isStateChange: true, displayed: true] break default: map = [displayed: false, descriptionText: "Alarm event ${cmd.alarmType} level ${cmd.alarmLevel}"] @@ -512,11 +506,6 @@ private def handleAlarmReportUsingAlarmType(cmd) { } if (map) { - if (map.data) { - map.data.lockName = deviceName - } else { - map.data = [ lockName: deviceName ] - } result << createEvent(map) } result = result.flatten() From 8671b098038cac59523ed0df289f258311e0ca99 Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Wed, 13 Oct 2021 18:42:54 +0900 Subject: [PATCH 068/184] Update zigbee-white-color-temperature-bulb.groovy (#76129) Add a fingerprint of Samsung Korea B2B Marketing --- .../zigbee-white-color-temperature-bulb.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 2c7140539bc..50426507a0c 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -41,6 +41,9 @@ metadata { // Samsung LED fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-001", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" //ITM CCT + // Samsung Korea B2B Marketing + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "HAN-LIGHT-Z-001", deviceJoinName: "SamsungB2B Light", mnmn: "Samsung Electronics", vid: "HAN-LIGHT-Z-001" //Samsung Korea B2B Marketing CCT + // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010C", manufacturer: "AduroSmart Eria", model: "AD-ColorTemperature3001", deviceJoinName: "Eria Light" //Eria ZigBee Color Temperature Bulb From 378f57c54422cc6c7b6f485f71bc8375828ab9f5 Mon Sep 17 00:00:00 2001 From: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Date: Wed, 13 Oct 2021 17:00:22 +0200 Subject: [PATCH 069/184] [BUG-3524] POPP TRV - changed logic to the one not relying on multiCmdEncap (#76120) * Changed logic to the one not relying on multiCmdEncap * Moved clearing cache to more optimal line --- .../zwave-radiator-thermostat.groovy | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy index db5a31c526d..453d8e233d7 100644 --- a/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy +++ b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy @@ -95,7 +95,6 @@ def initialize() { } def installed() { - state.isSetpointChangeRequestedByController = false initialize() } @@ -136,21 +135,16 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } } -def zwaveEvent(physicalgraph.zwave.commands.multicmdv1.MultiCmdEncap cmd) { - cmd.encapsulatedCommands().collect { encapsulatedCommand -> - isPoppRadiatorThermostat() ? zwaveEvent(encapsulatedCommand, true) : zwaveEvent(encapsulatedCommand) - //in case any future device would support MultiCmdEncap - //and won't need any special handler, like POPP does - }.flatten() -} - def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def cmds = [] if (!isPoppRadiatorThermostat()) { cmds += zwave.batteryV1.batteryGet() // POPP sends battery report automatically every wake up by itself, there's no need to duplicate it } + if (state.cachedSetpoint) { + cmds += zwave.thermostatSetpointV2.thermostatSetpointSet([precision: 1, scale: 0, scaledValue: state.cachedSetpoint, setpointType: 1, size: 2]) + state.cachedSetpoint = null + } cmds += [ - zwave.thermostatSetpointV2.thermostatSetpointSet([precision: 1, scale: 0, scaledValue: state.cachedSetpoint, setpointType: 1, size: 2]), zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: 1), zwave.wakeUpV2.wakeUpNoMoreInformation() ] @@ -185,19 +179,17 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeRepor def updateSetpoint(cmd) { def deviceTemperatureScale = cmd.scale ? 'F' : 'C' def setpoint = Float.parseFloat(convertTemperatureIfNeeded(cmd.scaledValue, deviceTemperatureScale, cmd.precision)) - state.cachedSetpoint = setpoint + state.expectedSetpoint = setpoint createEvent(name: "heatingSetpoint", value: setpoint, unit: temperatureScale) } -def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd, isResponseOfWakeUp = false) { - if (!state.isSetpointChangeRequestedByController) { - updateSetpoint(cmd) - } else if (isResponseOfWakeUp) { - state.isSetpointChangeRequestedByController = false - updateSetpoint(cmd) - } else { - [:] +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { + def reportedSetpoint = Float.parseFloat(convertTemperatureIfNeeded(cmd.scaledValue, deviceTemperatureScale, cmd.precision)) + // User manually adjusted setpoint on device, after changing it in the app + if (reportedSetpoint != state.expectedSetpoint && reportedSetpoint != state.cachedSetpoint) { + state.cachedSetpoint = null } + updateSetpoint(cmd) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { @@ -258,7 +250,6 @@ def off() { def setHeatingSetpoint(setpoint) { if (isPoppRadiatorThermostat() && device.status == "ONLINE") { - state.isSetpointChangeRequestedByController = true sendEvent(name: "heatingSetpoint", value: setpoint, unit: temperatureScale) } setpoint = temperatureScale == 'C' ? setpoint : fahrenheitToCelsius(setpoint) From 8b76b0a73f8fca4621c335d561fc4fcc70226d5d Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Thu, 14 Oct 2021 15:52:18 +0800 Subject: [PATCH 070/184] DevWs for NIE-TECH CO., LTD. containing containing Aeotec Wallmote (#76125) Co-authored-by: Winnie Wen --- .../smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy index f04b9d09bd3..8255a106459 100644 --- a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy +++ b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy @@ -27,7 +27,7 @@ metadata { fingerprint mfr: "0086", model: "0081", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Aeotec Wallmote fingerprint mfr: "0060", model: "0003", deviceJoinName: "Everspring Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Everspring Wall Switch fingerprint mfr: "0371", model: "0016", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Aeotec illumino Wallmote 7 - fingerprint mfr: "0312", model: "D001", deviceJoinName: "Minoston Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Minoston Wallmote + fingerprint mfr: "0312", prod: "0924", model: "D001", deviceJoinName: "Minoston Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Minoston Wallmote } tiles(scale: 2) { From b6941bed4bd4661b741e32aca51d8555d6fa70b0 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Thu, 14 Oct 2021 20:39:30 +0800 Subject: [PATCH 071/184] HEIMAN Outlet WWST-7664 (#76136) * HEIMAN Outlet * HEIMAN Outlet WWST-7664 * HEIMAN Outlet WWST-7664 --- .../zigbee-metering-plug.src/zigbee-metering-plug.groovy | 1 - devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) 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 795cf0d3d5a..e28128d91da 100644 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -29,7 +29,6 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0105", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet (USB) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0104", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0009, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "E_Socket", deviceJoinName: "HEIMAN Outlet" //HEIMAN Smart Outlet - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "HEIMAN", model: "HS6ESK-W-EF-3.0", deviceJoinName: "HEIMAN Outlet", ocfDeviceType: "oic.d.smartplug" //HEIMAN Smart Outlet fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "sengled", model: "E1C-NB7", deviceJoinName: "Sengled Outlet" //Sengled Smart Plug with Energy Tracker fingerprint profileId: "0104", manufacturer: "frient A/S", model: "SPLZB-131", deviceJoinName: "frient Outlet" // frient smart plug mini, raw description: 02 0104 0051 10 09 0000 0702 0003 0009 0B04 0006 0004 0005 0002 05 0000 0019 000A 0003 0406 fingerprint profileId: "0104", manufacturer: "frient A/S", model: "SPLZB-132", deviceJoinName: "frient Outlet" // frient smart plug mini, raw description: 02 0104 0051 10 09 0000 0702 0003 0009 0B04 0006 0004 0005 0002 05 0000 0019 000A 0003 0406 diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 4e9f7be26d1..db8b9119aad 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -45,6 +45,7 @@ metadata { // HEIMAN fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW1L-EFR-3.0", deviceJoinName: "HEIMAN Switch" //HEIMAN Smart Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "HEIMAN", model: "HS6ESK-W-EF-3.0", deviceJoinName: "HEIMAN Outlet", ocfDeviceType: "oic.d.smartplug" //HEIMAN Smart Outlet // HONYAR fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0095", deviceJoinName: "HONYAR Switch" //HONYAR Smart Switch From 8752d1e254eaaf9bba59e63aa5c9e892edd38612 Mon Sep 17 00:00:00 2001 From: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Date: Mon, 25 Oct 2021 09:05:05 +0200 Subject: [PATCH 072/184] [ICP-14316] Qubino Thermostat - inital 0 report with correct unit for disabled setpoint (#76168) * Added inital 0 report with correct unit for disabled setpoint * Sending straightforward event to ST, instead of a command to device * fixup! Sending straightforward event to ST, instead of a command to device --- .../qubino-flush-thermostat.src/qubino-flush-thermostat.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy index 3bf9ed75393..6660041570d 100644 --- a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy +++ b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy @@ -212,6 +212,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport //this device doesn't act like normal thermostat, it can support either 'cool' or 'heat' after configuration if (cmd.parameterNumber == 59 && !state.isThermostatModeSet) { state.supportedModes.add(cmd.scaledConfigurationValue ? "cool" : "heat") + sendEvent([name: cmd.scaledConfigurationValue ? "heatingSetpoint" : "coolingSetpoint", value: 0, unit: temperatureScale, isStateChange: true]) state.isThermostatModeSet = true } createEvent(name: "supportedThermostatModes", value: state.supportedModes.encodeAsJson(), displayed: false) From e0828efc9bc0fcbf7f49ec4ac21e16091729b267 Mon Sep 17 00:00:00 2001 From: lecontr <86373197+lecontr@users.noreply.github.com> Date: Tue, 26 Oct 2021 00:15:05 -0700 Subject: [PATCH 073/184] DevWs for Smartenit, Inc containing containing Smartenit Zigbee Metering Outlet (#71931) * DevWs for Smartenit, Inc containing containing Smartenit Zigbee Metering Outlet * Numerical values substituted by constants. Removed deprecated capability reference. * Removed constants * Removed references to power multiplier and power divisor * - updated copyright date --- .../smartenit-zigbee-metering-outlet.groovy | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy diff --git a/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy b/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy new file mode 100644 index 00000000000..a7d6d846e86 --- /dev/null +++ b/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy @@ -0,0 +1,130 @@ +/* + * Copyright 2021 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 groovy.transform.Field + + @Field final MeteringCurrentSummation = 0x0000 + @Field final MeteringInstantDemand = 0x0400 + @Field final Current = 0x0508 + @Field final Voltage = 0x0505 + @Field final EnergyDivisor = 100000 + @Field final CurrentDivisor = 1000 + @Field final SmartenitMfrCode = 0x1075 + @Field final ElectricalMeasurement = 0x0b04 + @Field final ActivePower = 0x050b + @Field final ReportingResponse = 0x07 + +metadata { + // Automatically generated. Make future change here. + definition(name: "Smartenit Zigbee Metering Outlet", namespace: "Smartenit", author: "Luis Contreras", mnmn: "SmartThingsCommunity", vid: "9f4df74b-f0d4-3515-9384-f5297ee3b11c", ocfDeviceType: "oic.d.smartplug", minHubCoreVersion: '000.017.0012') { + capability "Actuator" + capability "Switch" + capability "Power Meter" + capability "Energy Meter" + capability "Voltage Measurement" + capability "Configuration" + capability "monthpublic25501.current" + capability "Refresh" + capability "Sensor" + capability "Health Check" + + fingerprint manufacturer: "Compacta", model: "ZBMSKT1 (4035A)", deviceJoinName: "Smartenit Outlet" // rawDescription 01 0104 0009 00 09 0000 0003 0004 0005 0006 0015 0702 0B04 0B05 00 + } +} + +def getFPoint(String FPointHex){ + log.debug "printing fpointHex ${FPointHex}" + return (Float)Long.parseLong(FPointHex, 16) +} + +// Parse incoming device messages to generate events +def parse(String description) { + log.debug "description is $description" + + def event = zigbee.getEvent(description) + log.debug "event: ${event}" + + if (event) { + if (event.name == "power") { + event = createEvent(name: event.name, value: (event.value as Integer), descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) + } else if (event.name == "switch") { + def descriptionText = event.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' + event = createEvent(name: event.name, value: event.value, descriptionText: descriptionText, translatable: true) + } + } else { + def cluster = zigbee.parse(description) + log.debug "cluster def: ${cluster}" + def mapDescription = zigbee.parseDescriptionAsMap(description) + + if (cluster && cluster.clusterId == zigbee.ONOFF_CLUSTER && cluster.command == ReportingResponse) { + if (cluster.data[0] == 0x00) { + log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster + event = createEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + } else { + log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" + event = null + } + } else if (mapDescription && (mapDescription.clusterInt == zigbee.SIMPLE_METERING_CLUSTER)) { + if (mapDescription.attrInt == MeteringCurrentSummation) { + event = createEvent(name: "energy", value: getFPoint(mapDescription.value)/EnergyDivisor) + } else if (mapDescription.attrInt == MeteringInstantDemand) { + event = createEvent(name: "power", value: getFPoint(mapDescription.value)/EnergyDivisor) + } else { + log.debug "Could not find attribute mapping for ${mapDescription.clusterInt} ${mapDescription.attrInt}" + } + } else if (mapDescription && (mapDescription.clusterInt == ElectricalMeasurement)) { + if (mapDescription.attrInt == Voltage) { + event = createEvent(name: "voltage", value: getFPoint(mapDescription.value)) + } else if (mapDescription.attrInt == Current) { + event = createEvent(name: "current", value: getFPoint(mapDescription.value)/CurrentDivisor, unit: "A") + } + } else { + log.warn "DID NOT PARSE MESSAGE for description : $description" + log.debug "${cluster}" + } + } + return event ? createEvent(event) : event +} + +def off() { + zigbee.off() +} + +def on() { + zigbee.on() +} +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return zigbee.onOffRefresh() +} + +def refresh() { + zigbee.onOffRefresh() + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER , Voltage) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER , Current) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER , ActivePower) +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + + // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity + refresh() + zigbee.onOffConfig(0, 300) + zigbee.electricMeasurementPowerConfig() +} \ No newline at end of file From b9284b36897d5ff0d0d94692a3362d09ee711e9e Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:47:21 +0800 Subject: [PATCH 074/184] HEIMAN Wall Switch HS6SW1A-W-EF-3.0 (#76185) --- devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index db8b9119aad..b2efdf4d453 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -46,6 +46,7 @@ metadata { // HEIMAN fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW1L-EFR-3.0", deviceJoinName: "HEIMAN Switch" //HEIMAN Smart Switch fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "HEIMAN", model: "HS6ESK-W-EF-3.0", deviceJoinName: "HEIMAN Outlet", ocfDeviceType: "oic.d.smartplug" //HEIMAN Smart Outlet + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS6SW1A-W-EF-3.0", deviceJoinName: "HEIMAN Switch" //HEIMAN Smart Switch // HONYAR fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0095", deviceJoinName: "HONYAR Switch" //HONYAR Smart Switch From 45666f9ae2a14a26a4dc5c4cfd712e3cae61cf89 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:55:30 +0800 Subject: [PATCH 075/184] HEIMAN Wall Switch HS6SW3A-W-EF-3.0 (#76187) * HEIMAN Wall Switch HS6SW3A-W-EF-3.0 * HEIMAN Switch(2/3gang) --- .../zigbee-multi-switch.src/zigbee-multi-switch.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index 62a9322e630..04194274d74 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -42,6 +42,8 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0096", deviceJoinName: "HONYAR Switch 1" //HONYAR 2 Gang Switch 1 fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW3L-EFR-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 3 Gang Switch 1 fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW2L-EFR-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 2 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS6SW2A-W-EF-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 2 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS6SW3A-W-EF-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 3 Gang Switch 1 // Dawon fingerprint profileId: "0104", inClusters: "0000, 0002, 0004, 0003, 0006, 0009, 0019", manufacturer: "DAWON_DNS", model: "PM-S240-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S240-ZB @@ -272,6 +274,7 @@ private getChildCount() { case "PM-S350-ZB": case "ST-S350-ZB": case "SBM300Z3": + case "HS6SW3A-W-EF-3.0": return 3 case "E220-KR4N0Z0-HA": case "ZB-SW04": From 6f2fff4bd437ffd19acc6cc3e01ead2dc51e8776 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Fri, 5 Nov 2021 18:04:42 +0800 Subject: [PATCH 076/184] HEIMAN Scene Panel new (#76578) * HEIMAN Scene Panel new * HEIMAN Scene Panel modify * HEIMAN Scene Panel modify1 * HEIMAN Scene Panel modify2 * HEIMAN Scene Panel modify3 --- .../zigbee-scene-keypad.groovy | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy b/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy index 2fddefda37e..eb13b0d8775 100644 --- a/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy +++ b/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy @@ -30,6 +30,8 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005", outClusters: "0003, 0004, 0005", manufacturer: "REXENSE", model: "0106-G", deviceJoinName: "GDKES Remote Control", vid: "generic-6-button-alt" //GDKES Scene Keypad fingerprint profileId: "0104", inClusters: "0000, 0005", outClusters: "0000, 0005, 0017", manufacturer: "ORVIBO", model: "cef8701bb8664a67a83033c071ef05f2", deviceJoinName: "ORVIBO Remote Control", vid: "generic-3-button-alt" //ORVIBO Scene Keypad fingerprint profileId: "0104", inClusters: "0004", outClusters: "0000, 0001, 0003, 0004, 0005, 0B05", manufacturer: "HEIMAN", model: "E-SceneSwitch-EM-3.0", deviceJoinName: "HEIMAN Remote Control", vid: "generic-4-button-alt" //HEIMAN Scene Keypad + fingerprint profileId: "0104", inClusters: "0004", outClusters: "0000, 0001, 0003, 0004, 0005, 0B05", manufacturer: "HEIMAN", model: "HS6SSA-W-EF-3.0", deviceJoinName: "HEIMAN Scene Panel", vid: "generic-4-button-alt" //HEIMAN Scene Keypad + fingerprint profileId: "0104", inClusters: "0004", outClusters: "0000, 0001, 0003, 0004, 0005, 0B05", manufacturer: "HEIMAN", model: "HS6SSB-W-EF-3.0", deviceJoinName: "HEIMAN Scene Panel", vid: "generic-3-button-alt" //HEIMAN Scene Keypad } @@ -97,7 +99,7 @@ def configure() { def cmds = zigbee.enrollResponse() if (isHeimanButton()) cmds += zigbee.writeAttribute(0x0000, 0x0012, DataType.BOOLEAN, 0x01) + - addHubToGroup(0x000F) + addHubToGroup(0x0010) + addHubToGroup(0x0011) + addHubToGroup(0x0013) + addHubToGroup(0x000F) + addHubToGroup(0x0010) + addHubToGroup(0x0011) + addHubToGroup(0x0012) + addHubToGroup(0x0013) return cmds } @@ -153,19 +155,25 @@ private getSupportedButtonValues() { } private getChildCount() { - if (device.getDataValue("model") == "0106-G") { - return 6 - } else if (device.getDataValue("model") == "HY0048" || device.getDataValue("model") == "E-SceneSwitch-EM-3.0") { - return 4 - } else if (device.getDataValue("model") == "cef8701bb8664a67a83033c071ef05f2") { - return 3 + def modelName = device.getDataValue("model") + switch(modelName) { + case "cef8701bb8664a67a83033c071ef05f2": + case "HS6SSB-W-EF-3.0": + return 3 + case "E-SceneSwitch-EM-3.0": + case "HS6SSA-W-EF-3.0": + case "HY0048": + return 4 + case "0106-G": + return 6 } } private getCLUSTER_GROUPS() { 0x0004 } private boolean isHeimanButton() { - device.getDataValue("model") == "E-SceneSwitch-EM-3.0" + def modelName = device.getDataValue("model") + modelName == "E-SceneSwitch-EM-3.0" || modelName == "HS6SSA-W-EF-3.0" || modelName == "HS6SSB-W-EF-3.0" } private List addHubToGroup(Integer groupAddr) { @@ -179,5 +187,16 @@ private getButtonNum() {[ "02" : 1, "03" : 3, "05" : 4 + ], + "HS6SSA-W-EF-3.0" : [ + "01" : 3, + "02" : 2, + "03" : 4, + "04" : 1 + ], + "HS6SSB-W-EF-3.0" : [ + "02" : 1, + "03" : 3, + "04" : 2 ] ]} \ No newline at end of file From a86d400413190df4e6313e7cb67a9382d069b835 Mon Sep 17 00:00:00 2001 From: jwg-123 <51741592+jwg-123@users.noreply.github.com> Date: Tue, 9 Nov 2021 18:52:24 +0800 Subject: [PATCH 077/184] DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch (#76128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch * commit again * commit again * add profileId、inClusters、outClusters Co-authored-by: 啦啦 王 --- .../smartthings/zigbee-switch.src/zigbee-switch.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index b2efdf4d453..497833cad67 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -92,7 +92,9 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "SONOFF", model: "BASICZBR3", deviceJoinName: "SONOFF Outlet", ocfDeviceType: "oic.d.smartplug" //SONOFF Basic (R3 Zigbee) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "SONOFF", model: "S31 Lite zb", deviceJoinName: "S31 Outlet", ocfDeviceType: "oic.d.smartplug" //S31 Lite zb fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "1000", manufacturer: "SONOFF", model: "01MINIZB", deviceJoinName: "SONOFF 01MINIZB" //01MINIZB - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, FC57", outClusters: "0019", manufacturer: "SONOFF", model: "S26R2ZB", deviceJoinName: "SONOFF Plug", ocfDeviceType: "oic.d.smartplug" //SONOFF S26R2 Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, FC57", outClusters: "0019", manufacturer: "SONOFF", model: "S40LITE", deviceJoinName: "SONOFF Plug", ocfDeviceType: "oic.d.smartplug" //SONOFF S40Lite Plug + // Terncy fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0019", manufacturer: "", model: "TERNCY-LS01", deviceJoinName: "Terncy Switch" //Terncy Smart Light Socket @@ -187,4 +189,4 @@ def configure() { sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) log.debug "Configuring Reporting and Bindings." zigbee.onOffRefresh() + zigbee.onOffConfig() -} +} \ No newline at end of file From cbfccd9058762ab9765c01216976d730bf267352 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Wed, 10 Nov 2021 18:53:32 +0900 Subject: [PATCH 078/184] DevWs for SHINA SYSTEM containing containing Zigbee Power Meter (#76343) * DevWs for SHINA SYSTEM containing containing Zigbee Power Meter * Update zigbee-power-meter.groovy Remove inClusters and outClusters from the fingerprint and add whole Raw Description in a comment after this fingerprint. * Update zigbee-power-meter.groovy Add "zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 1, 600, 1)" * Update zigbee-power-meter.groovy Fix spacing. --- .../zigbee-power-meter.groovy | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy index 88be0594b85..ee7830a35a0 100644 --- a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy +++ b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy @@ -11,6 +11,8 @@ * for the specific language governing permissions and limitations under the License. * */ +import physicalgraph.zigbee.zcl.DataType + metadata { definition (name: "Zigbee Power Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", vid: "SmartThings-smartthings-Aeon_Home_Energy_Meter") { capability "Energy Meter" @@ -23,6 +25,7 @@ metadata { fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Energy Monitor" //Smart Sub-meter(CT Type) fingerprint profileId: "0104", deviceId:"0007", inClusters: "0000,0003,0702", outClusters: "000A", manufacturer: "Develco", model: "ZHEMI101", deviceJoinName: "frient Energy Monitor" // frient External Meter Interface (develco) 02 0104 0007 00 03 0000 0003 0702 01 000A fingerprint profileId: "0104", manufacturer: "Develco Products A/S", model: "EMIZB-132", deviceJoinName: "frient Energy Monitor" // frient Norwegian HAN (develco) 02 0104 0053 00 06 0000 0003 0020 0702 0704 0B04 03 0003 000A 0019 + fingerprint profileId: "0104", manufacturer: "ShinaSystem", model: "PMM-300Z1", deviceJoinName: "SiHAS Energy Monitor" // SIHAS Power Meter 01 0104 0000 01 05 0000 0004 0003 0B04 0702 02 0004 0019 } // tile definitions @@ -47,6 +50,10 @@ metadata { } } +def getATTRIBUTE_READING_INFO_SET() { 0x0000 } +def getATTRIBUTE_HISTORICAL_CONSUMPTION() { 0x0400 } +def getATTRIBUTE_ACTIVE_POWER() { 0x050B } + def parse(String description) { log.debug "description is $description" def event = zigbee.getEvent(description) @@ -55,7 +62,7 @@ def parse(String description) { if (event.name == "power") { def descMap = zigbee.parseDescriptionAsMap(description) log.debug "event : Desc Map: $descMap" - if (descMap.clusterInt == 0x0B04 && descMap.attrInt == 0x050b) { + if (descMap.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && descMap.attrInt == ATTRIBUTE_ACTIVE_POWER) { event.value = event.value/activePowerDivisor event.unit = "W" } else { @@ -80,19 +87,19 @@ def parse(String description) { attrData.each { def map = [:] if (it.isValidForDataType && (it.value != null)) { - if (it.clusterInt == 0x0702 && it.attrInt == 0x0400) { + if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { log.debug "meter" map.name = "power" map.value = zigbee.convertHexToInt(it.value)/powerDivisor map.unit = "W" } - if (it.clusterInt == 0x0B04 && it.attrInt == 0x050b) { + if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_ACTIVE_POWER) { log.debug "meter" map.name = "power" map.value = zigbee.convertHexToInt(it.value)/activePowerDivisor map.unit = "W" } - if (it.clusterInt == 0x0702 && it.attrInt == 0x0000) { + if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { log.debug "energy" map.name = "energy" map.value = zigbee.convertHexToInt(it.value)/(energyDivisor * 1000) @@ -120,6 +127,7 @@ def ping() { def refresh() { log.debug "refresh " zigbee.electricMeasurementPowerRefresh() + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET) + zigbee.simpleMeteringPowerRefresh() } @@ -130,14 +138,19 @@ def configure() { log.debug "Configuring Reporting" return refresh() + zigbee.simpleMeteringPowerConfig() + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 1, 600, 1) + zigbee.electricMeasurementPowerConfig() } -private getActivePowerDivisor() { 10 } -private getPowerDivisor() { isFrientSensor() ? 1 : 1000 } -private getEnergyDivisor() { isFrientSensor() ? 1 : 1000 } +private getActivePowerDivisor() { isPMM300Z1() ? 1 : 10 } +private getPowerDivisor() { (isFrientSensor() || isPMM300Z1()) ? 1 : 1000 } +private getEnergyDivisor() { (isFrientSensor() || isPMM300Z1()) ? 1 : 1000 } private Boolean isFrientSensor() { device.getDataValue("manufacturer") == "Develco Products A/S" || device.getDataValue("manufacturer") == "Develco" } + +private Boolean isPMM300Z1() { + device.getDataValue("model") == "PMM-300Z1" +} From 224f8de6d88a32e445dbeeffd6d177dbd42f3130 Mon Sep 17 00:00:00 2001 From: Donald Kirker Date: Mon, 15 Nov 2021 20:14:16 -0800 Subject: [PATCH 079/184] BUG-3088 Force metadata refresh for CT100 thermostat --- .../smartthings/ct100-thermostat.src/ct100-thermostat.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy index cfb29ecdabe..7c103d20d38 100644 --- a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy +++ b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy @@ -1,6 +1,6 @@ metadata { // Automatically generated. Make future change here. - definition (name: "CT100 Thermostat", namespace: "smartthings", author: "SmartThings") { + definition (name: "CT100 Thermostat", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "SmartThings-smartthings-CT100_Thermostat") { capability "Actuator" capability "Temperature Measurement" capability "Relative Humidity Measurement" From 8a8785093b87843307352de1c6d1c9b02d030e68 Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Tue, 16 Nov 2021 19:38:30 +0800 Subject: [PATCH 080/184] DevWs for CoolKit Technology Co.,Ltd containing containing Orvibo Contact Sensor (#76628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing Orvibo Contact Sensor * Modify format * Modify format * Update Orvibo-Contact-Sensor.groovy * Delete orvibo-contact-sensor.groovy Co-authored-by: 啦啦 王 --- .../Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index f36c65ea5f6..a33260a3676 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -30,6 +30,7 @@ metadata { capability "Sensor" fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "DS01", deviceJoinName: "eWeLink Open/Closed Sensor" //eWeLink Door Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0020,0500,FC57", outClusters: "0003,0019", manufacturer: "eWeLink", model: "SNZB-04P", deviceJoinName: "eWeLink Open/Closed Sensor" //eWeLink Door Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "ORVIBO", model: "e70f96b3773a4c9283c6862dbafb6a99", deviceJoinName: "Orvibo Open/Closed Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0500", outClusters: "000A,0019", manufacturer: "Aurora", model: "WindowSensor51AU", deviceJoinName: "Aurora Open/Closed Sensor" //Aurora Smart Door/Window Sensor fingerprint manufacturer: "Aurora", model: "DoorSensor50AU", deviceJoinName: "Aurora Open/Closed Sensor" // Raw Description: 01 0104 0402 00 06 0000 0001 0003 0020 0500 0B05 01 0019 //Aurora Smart Door/Window Sensor From be5125c63b792a297e40bbfdcb6535991a7b307c Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Wed, 17 Nov 2021 16:16:17 +0800 Subject: [PATCH 081/184] DevWs for CoolKit Technology Co.,Ltd containing containing SmartSense Temp/Humidity Sensor (#76624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing SmartSense Temp/Humidity Sensor * Modify format Co-authored-by: 啦啦 王 --- .../smartsense-temp-humidity-sensor.groovy | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index 7e04310670c..543d629fc53 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -37,6 +37,7 @@ metadata { //eWeLink fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0402, 0405", outClusters: "0003", manufacturer: "eWeLink", model: "TH01", deviceJoinName: "eWeLink Multipurpose Sensor" + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0020, 0402, 0405, FC57", outClusters: "0003, 0019", manufacturer: "eWeLink", model: "SNZB-02P", deviceJoinName: "eWeLink Multipurpose Sensor" } simulator { @@ -177,12 +178,10 @@ def refresh() { return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)+ zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000)+ zigbee.readAttribute(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000) - } else if (isEWeLinkTh01()) { - return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware - zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware - zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) + + } else if (isEWeLink()) { + return zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) + zigbee.readAttribute(0x0405, 0x0000) + - zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } else { return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware @@ -211,13 +210,11 @@ def configure() { zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000, DataType.UINT16, 60, 600, 1*100) + zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 60, 600, 0xA) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020, DataType.UINT8, 30, 21600, 0x1) - } else if (isEWeLinkTh01()) { + } else if (isEWeLink()) { return refresh() + - zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) + // New firmware - zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0xC2DF]) + // Original firmware - zigbee.batteryConfig() + - zigbee.temperatureConfig(3600, 7200) + - zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 3600, 7200, null) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 3600, 7200, 0x10) + + zigbee.temperatureConfig(10, 7200, 50) + + zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 10, 7200, 300) } else { return refresh() + zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) + // New firmware @@ -231,6 +228,6 @@ private Boolean isFrientSensor() { device.getDataValue("manufacturer") == "frient A/S" } -private Boolean isEWeLinkTh01() { - device.getDataValue("manufacturer") == "eWeLink" && device.getDataValue("model") == "TH01" +private Boolean isEWeLink() { + device.getDataValue("manufacturer") == "eWeLink" } From c193d322a6bcb88ee59b5c560dc0eb1c056c9746 Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Wed, 17 Nov 2021 16:30:40 +0800 Subject: [PATCH 082/184] DevWs for CoolKit Technology Co.,Ltd containing containing Zigbee Motion Detector (#76625) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing Zigbee Motion Detector * Modify format Co-authored-by: 啦啦 王 --- .../zigbee-motion-detector.src/zigbee-motion-detector.groovy | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy index 3a52885a02d..14003b028af 100644 --- a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy +++ b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy @@ -27,6 +27,7 @@ metadata { capability "Sensor" fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "MS01", deviceJoinName: "eWeLink Motion Sensor" //eWeLink Motion Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0020,0500,FC57", outClusters: "0003,0019", manufacturer: "eWeLink", model: "SNZB-03P", deviceJoinName: "eWeLink Motion Sensor" //eWeLink Motion Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "ORVIBO", model: "895a2d80097f4ae2b2d40500d5e03dcc", deviceJoinName: "Orvibo Motion Sensor" //Orvibo Motion Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "Megaman", model: "PS601/z1", deviceJoinName: "INGENIUM Motion Sensor" //INGENIUM ZB PIR Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001", outClusters: "0019", manufacturer: "HEIMAN", model: "PIRSensor-N", deviceJoinName: "HEIMAN Motion Sensor" //HEIMAN Motion Sensor @@ -101,7 +102,7 @@ def parse(String description) { def batteyHandler(String description){ def descMap = zigbee.parseDescriptionAsMap(description) def map = [:] - if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value) { + if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value && descMap?.attrInt == 0x0021) { map = getBatteryPercentageResult(Integer.parseInt(descMap.value, 16)) } return map @@ -171,7 +172,7 @@ def configure() { 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"]) - return zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 3600, 0x10) + refresh() + return zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 3600, 7200, 0x10) + refresh() } else if (manufacturer == "Third Reality, Inc") { return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } else { From 7616f23b21fb44b83d2904fa7610807ce192a4d8 Mon Sep 17 00:00:00 2001 From: Donald Kirker Date: Thu, 18 Nov 2021 17:10:05 -0800 Subject: [PATCH 083/184] CHAD-6599 Add resetEnergyMeter to energy meter device handlers with reset command (#76604) * CHAD-6599 Add resetEnergyMeter to energy meter device handlers with reset command * Add placeholder for device handlers with no reset command --- .../curb/curb-power-meter.src/curb-power-meter.groovy | 4 ++++ .../fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy | 4 ++++ .../fibaro-double-switch-2-usb.groovy | 4 ++++ .../fibaro-double-switch-2-zw5.groovy | 4 ++++ .../fibaro-single-switch-2-zw5.groovy | 4 ++++ .../fibaro-wall-plug-eu-zw5.groovy | 4 ++++ .../fibaro-wall-plug-us-zw5.groovy | 4 ++++ .../fibaro-wall-plug-usb.src/fibaro-wall-plug-usb.groovy | 4 ++++ .../fibaro-walli-dimmer-switch.groovy | 4 ++++ .../fibaro-walli-double-switch.groovy | 4 ++++ .../fibaro-walli-roller-shutter-driver.groovy | 4 ++++ .../fibaro-walli-roller-shutter-venetian.groovy | 4 ++++ .../fibaro-walli-roller-shutter.groovy | 4 ++++ .../qubino-3-phase-meter.src/qubino-3-phase-meter.groovy | 4 ++++ devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy | 4 ++++ .../qubino-flush-2-relay.src/qubino-flush-2-relay.groovy | 4 ++++ .../qubino-flush-shutter.src/qubino-flush-shutter.groovy | 4 ++++ .../smartenit/smartelek-evse.src/smartelek-evse.groovy | 4 ++++ .../smartenit-metering-dual-load-controller.groovy | 4 ++++ .../smartenit-zigbee-metering-outlet.groovy | 5 +++++ .../aeon-home-energy-meter-c3.groovy | 4 ++++ .../aeon-home-energy-meter.groovy | 4 ++++ .../aeon-illuminator-module.groovy | 4 ++++ devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy | 4 ++++ .../smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy | 4 ++++ .../child-energy-meter.src/child-energy-meter.groovy | 6 +++++- .../child-metering-switch.src/child-metering-switch.groovy | 4 ++++ .../dawon-zwave-smart-plug.groovy | 4 ++++ .../ezex-smart-electric-switch.groovy | 4 ++++ .../home-energy-meter.src/home-energy-meter.groovy | 4 ++++ .../smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy | 4 ++++ .../qubino-flush-thermostat.groovy | 4 ++++ .../zigbee-metering-dimmer.groovy | 4 ++++ .../zigbee-metering-plug-power-consumption-report.groovy | 4 ++++ .../zigbee-metering-plug.src/zigbee-metering-plug.groovy | 4 ++++ .../zigbee-power-meter.src/zigbee-power-meter.groovy | 3 +++ .../zwave-metering-dimmer.src/zwave-metering-dimmer.groovy | 4 ++++ .../zwave-metering-switch-secure.groovy | 4 ++++ .../zwave-metering-switch.src/zwave-metering-switch.groovy | 4 ++++ .../zwave-multi-metering-switch.groovy | 4 ++++ .../technisat/technisat-dimmer.src/technisat-dimmer.groovy | 4 ++++ .../technisat-on-off-switch.groovy | 4 ++++ .../technisat-roller-shutter-switch.groovy | 4 ++++ .../technisat-series-switch.groovy | 4 ++++ 44 files changed, 177 insertions(+), 1 deletion(-) diff --git a/devicetypes/curb/curb-power-meter.src/curb-power-meter.groovy b/devicetypes/curb/curb-power-meter.src/curb-power-meter.groovy index dfc78e0cfe4..4e0f596f643 100644 --- a/devicetypes/curb/curb-power-meter.src/curb-power-meter.groovy +++ b/devicetypes/curb/curb-power-meter.src/curb-power-meter.groovy @@ -48,6 +48,10 @@ metadata { } } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def handlePower(value) { sendEvent(name: "power", value: value) } diff --git a/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy b/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy index 9b2c41d1a5a..1562609b5c0 100644 --- a/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy @@ -111,6 +111,10 @@ def setLevel(level, rate = null ) { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { logging("${device.displayName} - Executing reset()","info") def cmds = [] cmds << zwave.meterV3.meterReset() diff --git a/devicetypes/fibargroup/fibaro-double-switch-2-usb.src/fibaro-double-switch-2-usb.groovy b/devicetypes/fibargroup/fibaro-double-switch-2-usb.src/fibaro-double-switch-2-usb.groovy index 370879f8c7b..4038a8e6f04 100644 --- a/devicetypes/fibargroup/fibaro-double-switch-2-usb.src/fibaro-double-switch-2-usb.groovy +++ b/devicetypes/fibargroup/fibaro-double-switch-2-usb.src/fibaro-double-switch-2-usb.groovy @@ -68,6 +68,10 @@ def off() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { parent.childReset() } 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 9fe9b363a43..71d33d6cae1 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 @@ -94,6 +94,10 @@ def childOff() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { def cmds = [] cmds << [zwave.meterV3.meterReset(), 1] cmds << [zwave.meterV3.meterGet(scale: 0), 1] diff --git a/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy b/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy index 4c66b89a48a..645beea8127 100644 --- a/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy @@ -95,6 +95,10 @@ def off() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { def cmds = [] cmds << zwave.meterV3.meterReset() cmds << zwave.meterV3.meterGet(scale: 0) 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 710beff621a..9290030e364 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 @@ -80,6 +80,10 @@ def off() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { def cmds = [] cmds << zwave.meterV3.meterReset() cmds << zwave.meterV3.meterGet(scale: 0) 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 1417165a9d8..eebab0251f8 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 @@ -95,6 +95,10 @@ def off() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { def cmds = [] cmds << [zwave.meterV3.meterReset(), 1] cmds << [zwave.meterV3.meterGet(scale: 0), 1] diff --git a/devicetypes/fibargroup/fibaro-wall-plug-usb.src/fibaro-wall-plug-usb.groovy b/devicetypes/fibargroup/fibaro-wall-plug-usb.src/fibaro-wall-plug-usb.groovy index 13386ea814a..add5ea4ef5e 100644 --- a/devicetypes/fibargroup/fibaro-wall-plug-usb.src/fibaro-wall-plug-usb.groovy +++ b/devicetypes/fibargroup/fibaro-wall-plug-usb.src/fibaro-wall-plug-usb.groovy @@ -46,6 +46,10 @@ def installed() { def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { parent.childReset() } diff --git a/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy b/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy index 675df2a6b20..aec4c6694dd 100644 --- a/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy +++ b/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy @@ -364,6 +364,10 @@ def refresh() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { encapSequence([ meterReset(), meterGet(scale: 0) diff --git a/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy b/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy index a6357b31202..5531c592fc8 100644 --- a/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy +++ b/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy @@ -394,6 +394,10 @@ def childReset(deviceNetworkId = null) { } } +def resetEnergyMeter() { + reset(1) +} + def reset(endpoint = 1) { log.debug "Resetting endpoint: ${endpoint}" delayBetween([ diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy index 21ae9e826f3..bdcba95b888 100644 --- a/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy @@ -295,6 +295,10 @@ def setShadeLevel(level) { encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def refresh() { sendHubCommand([ encap(zwave.switchMultilevelV3.switchMultilevelGet()) diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy index 7cfbf097669..e44e8e4d604 100644 --- a/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy @@ -329,6 +329,10 @@ def setShadeLevel(level) { encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def setSlats(childDni, level) { state.isManualCommand = false def time = (int) (state.timeOfVenetianMovement * 1.1) diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy index 3cb91b3a7ff..fb76b073651 100644 --- a/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy @@ -323,6 +323,10 @@ def setShadeLevel(level) { encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def refresh() { sendHubCommand([ encap(zwave.switchMultilevelV3.switchMultilevelGet()) diff --git a/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy b/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy index e61f2982096..a3d80ddd6ff 100644 --- a/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy +++ b/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy @@ -66,6 +66,10 @@ def ping() { refresh() } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def parse(String description) { def result = null def cmd = zwave.parse(description) diff --git a/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy b/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy index 807f7ce7ca7..8147733bff7 100644 --- a/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy +++ b/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy @@ -473,6 +473,10 @@ def setLevel(value, duration = null) { encapCommands(commands, getStatusDelay) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ diff --git a/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy b/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy index a23cbf7f262..54ee2647a3e 100644 --- a/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy +++ b/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy @@ -423,6 +423,10 @@ def childReset(deviceNetworkId) { } } +def resetEnergyMeter() { + reset(1) +} + def reset(endpoint = 1) { log.debug "Resetting endpoint: ${endpoint}" delayBetween([ diff --git a/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy b/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy index f538774b19d..c11a5cd5a8a 100644 --- a/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy +++ b/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy @@ -260,6 +260,10 @@ def setSlats(level) { ]) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def refresh() { [ encap(zwave.switchMultilevelV3.switchMultilevelGet()), diff --git a/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy b/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy index ccd01619da8..4a096ffc6f0 100644 --- a/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy +++ b/devicetypes/smartenit/smartelek-evse.src/smartelek-evse.groovy @@ -299,6 +299,10 @@ def startcharging() { zigbee.command(EVSECluster, StartCharging, "", [mfgCode: SmartenitMfrCode]) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def refresh() { zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation) + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand) + diff --git a/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy b/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy index b78e67d6099..0dc17950d3e 100644 --- a/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy +++ b/devicetypes/smartenit/smartenit-metering-dual-load-controller.src/smartenit-metering-dual-load-controller.groovy @@ -141,6 +141,10 @@ def setLoadtwo(val) { } } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def refresh() { zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringCurrentSummation) + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, MeteringInstantDemand) + diff --git a/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy b/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy index a7d6d846e86..be71653d2dd 100644 --- a/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy +++ b/devicetypes/smartenit/smartenit-zigbee-metering-outlet.src/smartenit-zigbee-metering-outlet.groovy @@ -105,6 +105,11 @@ def off() { def on() { zigbee.on() } + +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ diff --git a/devicetypes/smartthings/aeon-home-energy-meter-c3.src/aeon-home-energy-meter-c3.groovy b/devicetypes/smartthings/aeon-home-energy-meter-c3.src/aeon-home-energy-meter-c3.groovy index d4e09f229fc..b3dfc81b217 100644 --- a/devicetypes/smartthings/aeon-home-energy-meter-c3.src/aeon-home-energy-meter-c3.groovy +++ b/devicetypes/smartthings/aeon-home-energy-meter-c3.src/aeon-home-energy-meter-c3.groovy @@ -125,6 +125,10 @@ def refresh() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { // No V1 available return [ zwave.meterV2.meterReset().format(), diff --git a/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy b/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy index 568740d34ff..fda6a24af10 100644 --- a/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy +++ b/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy @@ -147,6 +147,10 @@ def refresh() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { log.debug "reset()..." // No V1 available delayBetween([ diff --git a/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy b/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy index 66e26f71c79..6e050eb088c 100644 --- a/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy +++ b/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy @@ -177,6 +177,10 @@ def refresh() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { return [ zwave.meterV2.meterReset().format(), zwave.meterV2.meterGet().format() diff --git a/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy b/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy index f828c411825..44c4a4237ea 100644 --- a/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy +++ b/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy @@ -126,6 +126,10 @@ def refresh() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { return [ zwave.meterV2.meterReset().format(), zwave.meterV2.meterGet().format() diff --git a/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy b/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy index fd506d75300..7aba9fa4b43 100644 --- a/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy +++ b/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy @@ -248,6 +248,10 @@ def resetCmd(endpoint = null) { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { delayBetween([resetCmd(null), reset1(), reset2(), reset3(), reset4()]) } diff --git a/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy b/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy index a182b0c19a8..3fc9dea705c 100644 --- a/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy +++ b/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy @@ -37,6 +37,10 @@ metadata { } } +def resetEnergyMeter() { + parent.childReset(device.deviceNetworkId) +} + def refresh() { parent.childRefresh(device.deviceNetworkId) } @@ -47,4 +51,4 @@ def ping() { def installed() { sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [hubHardwareId: device.hub.hardwareID]) -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/child-metering-switch.src/child-metering-switch.groovy b/devicetypes/smartthings/child-metering-switch.src/child-metering-switch.groovy index 26980dd9479..457088e9993 100644 --- a/devicetypes/smartthings/child-metering-switch.src/child-metering-switch.groovy +++ b/devicetypes/smartthings/child-metering-switch.src/child-metering-switch.groovy @@ -66,6 +66,10 @@ def ping() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { parent.childReset(device.deviceNetworkId) } diff --git a/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy b/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy index 2bd3afbde3f..cc593b87d71 100755 --- a/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy +++ b/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy @@ -233,6 +233,10 @@ def configure() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { encapSequence([ meterReset(), meterGet(scale: 0) diff --git a/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy b/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy index 7ed24482a84..dfe05ec6596 100755 --- a/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy +++ b/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy @@ -108,6 +108,10 @@ def on() { zigbee.on() } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ diff --git a/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy b/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy index 72f1596b0fb..48693aab128 100644 --- a/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy +++ b/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy @@ -101,6 +101,10 @@ def poll() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { delayBetween([ zwave.meterV2.meterReset().format(), zwave.meterV2.meterGet(scale: 0).format() diff --git a/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy b/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy index c883a81c017..b613f5c0c2b 100644 --- a/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy +++ b/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy @@ -354,6 +354,10 @@ def setLevel(level) { ], 1000) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { def map = [:] if (cmd.meterType == 1 && cmd.scale == 0) { diff --git a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy index 6660041570d..e6a7a539959 100644 --- a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy +++ b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy @@ -285,6 +285,10 @@ def updateSetpoint(setpoint, setpointType) { ] } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def configure() { [ secure(zwave.configurationV1.configurationSet(parameterNumber: 78, scaledConfigurationValue: temperatureScale == 'C' ? 0 : 1, size: 1)), diff --git a/devicetypes/smartthings/zigbee-metering-dimmer.src/zigbee-metering-dimmer.groovy b/devicetypes/smartthings/zigbee-metering-dimmer.src/zigbee-metering-dimmer.groovy index 1c67c7b9fb3..03ad547bd93 100644 --- a/devicetypes/smartthings/zigbee-metering-dimmer.src/zigbee-metering-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-metering-dimmer.src/zigbee-metering-dimmer.groovy @@ -102,6 +102,10 @@ def setLevel(value, rate = null) { zigbee.setLevel(value) + (value?.toInteger() > 0 ? zigbee.on() : []) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ diff --git a/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy b/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy index 1e147e010a9..2ad7266b121 100644 --- a/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug-power-consumption-report.src/zigbee-metering-plug-power-consumption-report.groovy @@ -110,6 +110,10 @@ def on() { return cmds } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ 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 e28128d91da..8ead950a318 100644 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -138,6 +138,10 @@ def on() { return cmds } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ diff --git a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy index ee7830a35a0..36b48b6e924 100644 --- a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy +++ b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy @@ -116,6 +116,9 @@ def parse(String description) { } } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} /** * PING is used by Device-Watch in attempt to reach the Device 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 74a99e03a63..23c8af60299 100644 --- a/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy +++ b/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy @@ -281,6 +281,10 @@ def configure() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { encapSequence([ meterReset(), meterGet(scale: 0) 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 6d6d9309b2e..43b477d923a 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 @@ -276,6 +276,10 @@ def off() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { log.debug "Executing 'reset'" encap(zwave.meterV2.meterReset()) } 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 feb0c8051a2..170107bfdba 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -284,6 +284,10 @@ def configure() { } def reset() { + resetEnergyMeter() +} + +def resetEnergyMeter() { encapSequence([ meterReset(), meterGet(scale: 0) diff --git a/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy b/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy index 7c591ab529c..7b0be10c797 100644 --- a/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy @@ -339,6 +339,10 @@ def childReset(deviceNetworkId) { } } +def resetEnergyMeter() { + reset(1) +} + def reset(endpoint = 1) { log.debug "Resetting endpoint: ${endpoint}" delayBetween([ diff --git a/devicetypes/technisat/technisat-dimmer.src/technisat-dimmer.groovy b/devicetypes/technisat/technisat-dimmer.src/technisat-dimmer.groovy index d0dfbf0cb67..dba23fd8eb8 100644 --- a/devicetypes/technisat/technisat-dimmer.src/technisat-dimmer.groovy +++ b/devicetypes/technisat/technisat-dimmer.src/technisat-dimmer.groovy @@ -199,6 +199,10 @@ def refresh() { ], 1000) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def configure() { log.debug "configure()" def result = [] diff --git a/devicetypes/technisat/technisat-on-off-switch.src/technisat-on-off-switch.groovy b/devicetypes/technisat/technisat-on-off-switch.src/technisat-on-off-switch.groovy index f9e5bb6d036..0715c3a15ca 100644 --- a/devicetypes/technisat/technisat-on-off-switch.src/technisat-on-off-switch.groovy +++ b/devicetypes/technisat/technisat-on-off-switch.src/technisat-on-off-switch.groovy @@ -183,6 +183,10 @@ def refresh() { ]) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def configure() { log.debug "configure()" def result = [] diff --git a/devicetypes/technisat/technisat-roller-shutter-switch.src/technisat-roller-shutter-switch.groovy b/devicetypes/technisat/technisat-roller-shutter-switch.src/technisat-roller-shutter-switch.groovy index 04cc08fa301..9ba7079cb06 100644 --- a/devicetypes/technisat/technisat-roller-shutter-switch.src/technisat-roller-shutter-switch.groovy +++ b/devicetypes/technisat/technisat-roller-shutter-switch.src/technisat-roller-shutter-switch.groovy @@ -228,6 +228,10 @@ def refresh() { ], 1000) } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def configure() { log.debug "configure()" def result = [] diff --git a/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy b/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy index c1287b2e8c7..fbd079005f4 100644 --- a/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy +++ b/devicetypes/technisat/technisat-series-switch.src/technisat-series-switch.groovy @@ -268,6 +268,10 @@ def childReset(deviceNetworkId) { log.debug("childReset from endpoint ${endpoint}") } +def resetEnergyMeter() { + log.debug "resetEnergyMeter: not implemented" +} + def configure() { log.debug "configure()" def result = [] From 58655e6c959f014d4eeb1db631ff81fde8f1e3c8 Mon Sep 17 00:00:00 2001 From: jwg-123 <51741592+jwg-123@users.noreply.github.com> Date: Fri, 19 Nov 2021 16:14:12 +0800 Subject: [PATCH 084/184] DevWs for www.easyiot.tech containing containing ZigBee RGBW Bulb (#76635) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for www.easyiot.tech containing containing ZigBee RGBW Bulb * Update zigbee-rgbw-bulb.groovy * Update zigbee-rgbw-bulb.groovy use 2 tabs,please review,thank you Co-authored-by: jiang wegang --- .../smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 52cb074bf55..40c753e69e4 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -103,6 +103,8 @@ metadata { // Ajax Online fingerprint manufacturer: "Ajaxonline", model: "AJ-RGBCCT 5 in 1", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" fingerprint manufacturer: "Ajax online Ltd", model: "AJ_ZB30_GU10", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" // Raw Description: 0B 0104 010D 01 08 0000 0003 0004 0005 0006 0008 0300 1000 00 + // Shenzhen C-Lux + fingerprint manufacturer: "Shenzhen C-Lux", model: "CL000ZB", deviceJoinName: "C-Lux Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" } // UI tile definitions From 671aad49fc492d6e939a80318783ecdf2933d225 Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Mon, 22 Nov 2021 15:35:31 +0800 Subject: [PATCH 085/184] DevWs for CoolKit Technology Co.,Ltd containing containing Ikea Button (#76622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing Ikea Button * Modify format * reformat * reformat Co-authored-by: 啦啦 王 --- .../ikea-button.src/ikea-button.groovy | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy index 0463afe45b8..b7a48ada477 100644 --- a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy +++ b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy @@ -33,6 +33,8 @@ metadata { fingerprint manufacturer: "KE", model: "TRADFRI open/close remote", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_open/close_remote" // raw description 01 0104 0203 01 07 0000 0001 0003 0009 0020 1000 FC7C 07 0003 0004 0006 0008 0019 0102 1000 //IKEA TRÅDFRI Open/Close Remote fingerprint manufacturer: "SOMFY", model: "Situo 4 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_Situo4_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 fingerprint manufacturer: "SOMFY", model: "Situo 1 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 + fingerprint inClusters: "0000, 0001, 0003", outClusters: "0003, 0006", manufacturer: "eWeLink", model: "WB01", deviceJoinName: "eWeLink Button" //eWeLink Button + fingerprint inClusters: "0000, 0001, 0003, 0020, FC57", outClusters: "0003, 0006, 0019", manufacturer: "eWeLink", model: "SNZB-01P", deviceJoinName: "eWeLink Button" //eWeLink Button } tiles { @@ -179,6 +181,7 @@ private void createChildButtonDevices(numberOfButtons) { def installed() { def numberOfButtons = 1 + def supportedButtons = [] if (isIkeaRemoteControl()) { numberOfButtons = 5 @@ -194,7 +197,14 @@ def installed() { createChildButtonDevices(numberOfButtons) } - def supportedButtons = isIkeaOpenCloseRemote() || isSomfy() ? ["pushed"] : ["pushed", "held"] + if (isIkeaOpenCloseRemote() || isSomfy()) { + supportedButtons = ["pushed"] + } else if (isEWeLink()) { + supportedButtons = ["pushed", "held", "double"] + } else { + supportedButtons = ["pushed", "held"] + } + sendEvent(name: "supportedButtonValues", value: supportedButtons.encodeAsJSON(), displayed: false) sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) numberOfButtons.times { @@ -374,6 +384,17 @@ private Map getButtonEvent(Map descMap) { buttonNumber = OPENCLOSESTOP_BUTTONS_ENDPOINTS[endpoint].STOP } } + } else if (isEWeLink()) { + if (descMap.clusterInt == zigbee.ONOFF_CLUSTER) { + buttonNumber = 1 + if (descMap.commandInt == 0x00) { + buttonState = "held" + } else if (descMap.commandInt == 0x01) { + buttonState = "double" + } else { + buttonState = "pushed" + } + } } if (buttonNumber != 0) { @@ -415,6 +436,10 @@ private boolean isSomfySituo4() { isSomfy() && device.getDataValue("model") == "Situo 4 Zigbee" } +private boolean isEWeLink() { + device.getDataValue("manufacturer") == "eWeLink" +} + private Integer getGroupAddrFromBindingTable(description) { log.info "Parsing binding table - '$description'" def btr = zigbee.parseBindingTableResponse(description) From a76b92e009d851f9f602924512fe7f5b11d99e79 Mon Sep 17 00:00:00 2001 From: Kevin LaFramboise Date: Tue, 30 Nov 2021 13:56:18 -0500 Subject: [PATCH 086/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZSE43 Tilt | Shock XS Sensor --- .../zooz-zse43-tilt-shock-xs-sensor.groovy | 386 ++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 devicetypes/zooz/zooz-zse43-tilt-shock-xs-sensor.src/zooz-zse43-tilt-shock-xs-sensor.groovy diff --git a/devicetypes/zooz/zooz-zse43-tilt-shock-xs-sensor.src/zooz-zse43-tilt-shock-xs-sensor.groovy b/devicetypes/zooz/zooz-zse43-tilt-shock-xs-sensor.src/zooz-zse43-tilt-shock-xs-sensor.groovy new file mode 100644 index 00000000000..27eb6f8a979 --- /dev/null +++ b/devicetypes/zooz/zooz-zse43-tilt-shock-xs-sensor.src/zooz-zse43-tilt-shock-xs-sensor.groovy @@ -0,0 +1,386 @@ +/* + * Zooz ZSE43 Tilt | Shock XS Sensor + * + * Changelog: + * + * 2021-11-25 + * - Publication Release + * + * Copyright 2021 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x30: 2, // SensorBinary + 0x55: 1, // Transport Service v2 + 0x59: 1, // AssociationGrpInfo v3 + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo v2 + 0x6C: 1, // Supervision + 0x70: 2, // Configuration v4 + 0x71: 3, // Notification v4 + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd v5 + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association v3 + 0x86: 1, // Version v2 + 0x87: 1, // Indicator v3 + 0x8E: 2, // Multi Channel Association v4 + 0x9F: 1 // Security 2 +] + +@Field static Map configParams = [ + ledIndicator: [num:1, title:"LED Indicator", size:1, defaultVal:3, options:[0:"LED off", 1:"Blinks on vibration only", 2:"Blinks for open/close only", 3:"Blinks for any status change [DEFAULT]"]], + lowBatteryReports: [num:3, title:"Low Battery Reports", size:1, defaultVal:20, options:[10:"10%", 20:"20% [DEFAULT]", 30:"30%", 40:"40%", 50:"50%"]], + vibrationSensitivity: [num:4, title:"Vibration Sensitivity", size:1, defaultVal:0, options:[0:"High [DEFAULT]", 1:"Medium", 2:"Low"]], + disableEnableSensors: [num:7, title:"Disable / Enable Sensors", size:1, defaultVal:2, options:[0:"Only tilt sensor enabled", 1:"Only vibration sensor enabled", 2:"Both sensors enabled [DEFAULT]"]] +] + +@Field static int contactOnly = 0 +@Field static int vibrationOnly = 1 +@Field static int accessControl = 6 +@Field static int accessControlOpen = 22 +@Field static int accessControlClosed = 23 +@Field static int homeSecurity = 7 +@Field static int homeSecurityVibration = 3 +@Field static int sensorTypeContact = 10 +@Field static int wakeUpInterval = 43200 + +metadata { + definition ( + name: "Zooz ZSE43 Tilt | Shock XS Sensor", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType:"oic.d.sensor", + vid: "11ae8701-e665-34ea-8b46-3ce2ce15d0f3", + mnmn: "SmartThingsCommunity" + ) { + capability "Sensor" + capability "Acceleration Sensor" + capability "Contact Sensor" + capability "Battery" + capability "Refresh" + capability "Health Check" + capability "Configuration" + capability "platemusic11009.contactVibrationSensor" + capability "platemusic11009.firmware" + capability "platemusic11009.syncStatus" + + // zw:Ss2a type:0701 mfr:027A prod:7000 model:E003 ver:1.10 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,72,5A,87,73,80,71,30,70,84,7A + fingerprint mfr:"027A", prod:"7000", model:"E003", deviceJoinName: "Zooz Tilt | Shock Sensor" // Zooz ZSE43 Tilt | Shock XS Sensor + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } + } + + input "debugLogging", "enum", + title: "Logging:", + required: false, + defaultValue: "1", + options: ["0":"Disabled", "1":"Enabled [DEFAULT]"] + } +} + +def installed() { + logDebug "installed()..." + state.pendingRefresh = true + initialize() +} + +def updated() { + logDebug "updated()..." + initialize() + + if (pendingChanges) { + logForceWakeupMessage("The setting changes will be sent to the device the next time it wakes up.") + } +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugLogging, 1) != 0) + refreshSyncStatus() + + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((wakeUpInterval * 2) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + if (!device.currentValue("acceleration") || ((device.currentValue("acceleration") == "active") && (getSettingVal("disableEnableSensors") == contactOnly))) { + sendEvent(name: "acceleration", value: "inactive", displayed:false) + } + + if (!device.currentValue("contactVibration")) { + sendEvent(name: "contactVibration", value: "inactive", displayed:false) + } else { + sendContactVibrationEvent(device.currentValue("contact"), device.currentValue("acceleration")) + } +} + +def refresh() { + logDebug "refresh()..." + + if (state.pendingRefresh) { + sendAccelerationEvent("inactive") + } + + refreshSyncStatus() + state.pendingRefresh = true + logForceWakeupMessage("The device will be refreshed the next time it wakes up.") +} + +void logForceWakeupMessage(String msg) { + log.warn "${msg} To force the device to wake up immediately press the action button 4x quickly." +} + +def configure() { + logDebug "configure()..." + sendHubCommand(getRefreshCmds(), 250) +} + +List getRefreshCmds() { + List cmds = [] + + if (state.pendingRefresh || !device.currentValue("battery")) { + cmds << secureCmd(zwave.batteryV1.batteryGet()) + } + + if (state.pendingRefresh || !device.currentValue("firmwareVersion")) { + cmds << secureCmd(zwave.versionV1.versionGet()) + } + + if (state.pendingRefresh || !device.currentValue("contact")) { + cmds << secureCmd(zwave.sensorBinaryV2.sensorBinaryGet(sensorType: sensorTypeContact)) + } + + if (state.wakeUpInterval == null) { + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + state.pendingRefresh = false + return cmds +} + +List getConfigureCmds() { + List cmds = [] + + int changes = pendingChanges + if (changes) { + log.warn "Syncing ${changes} Change(s)" + } + + if (state.wakeUpInterval != wakeUpInterval) { + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalSet(seconds: wakeUpInterval, nodeid:zwaveHubNodeId)) + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + logDebug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + return cmds +} + +def ping() { + logDebug "ping()" +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + logDebug "Device Woke Up..." + List cmds = [] + + cmds += getRefreshCmds() + cmds += getConfigureCmds() + + if (!cmds) { + cmds << secureCmd(zwave.batteryV1.batteryGet()) + } + + cmds << secureCmd(zwave.wakeUpV2.wakeUpNoMoreInformation()) + sendHubCommand(cmds, 150) +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + logDebug "Wake Up Interval = ${cmd.seconds} seconds" + state.wakeUpInterval = cmd.seconds + refreshSyncStatus() +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + Integer val = (cmd.batteryLevel == 0xFF ? 1 : cmd.batteryLevel) + if (val > 100) { + val = 100 + } + logDebug "Battery is ${val}%" + sendEvent(name:"battery", value:val, unit:"%", isStateChange: true) +} + +void zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { + logDebug "${cmd}" + if (cmd.sensorType == sensorTypeContact) { + sendContactEvent(cmd.sensorValue ? "open" : "closed") + } +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationType == accessControl) { + if (cmd.event == accessControlOpen) { + sendContactEvent("open") + } else if (cmd.event == accessControlClosed) { + sendContactEvent("closed") + } else { + logDebug "${cmd}" + } + } else if (cmd.notificationType == homeSecurity) { + sendAccelerationEvent((cmd.event == homeSecurityVibration) ? "active" : "inactive") + } else { + logDebug "${cmd}" + } +} + +void sendContactEvent(String value) { + logDebug "Contact is ${value}" + sendEvent(name: "contact", value: value) + sendContactVibrationEvent(value, device.currentValue("acceleration")) +} + +void sendAccelerationEvent(String value) { + logDebug "Acceleration is ${value}" + sendEvent(name: "acceleration", value: value) + sendContactVibrationEvent(device.currentValue("contact"), value) +} + +void sendContactVibrationEvent(String contactValue, String vibrationValue) { + String value + switch (getSettingVal("disableEnableSensors")) { + case contactOnly: + value = contactValue + break + case vibrationOnly: + value = vibrationValue + break + default: + value = "${contactValue}${vibrationValue.capitalize()}" + } + + if (device.currentValue("contactVibration") != value) { + sendEvent(name: "contactVibration", value: value, displayed: false) + } +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEvent(name: "firmwareVersion", value: (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + state[name] = val + logDebug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: ${cmd}" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +Integer getPendingChanges() { + int configChanges = safeToInt(configParams.count { name, param -> + (getSettingVal(name) != getStoredVal(name)) + }, 0) + int pendingWakeUpInterval = (state.wakeUpInterval != wakeUpInterval ? 1 : 0) + return (configChanges + pendingWakeUpInterval) +} + +Integer getSettingVal(String name) { + Integer value = safeToInt(settings[name], null) + if ((value == null) && (getStoredVal(name) != null)) { + return configParams[name].defaultVal + } else { + return value + } +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From 579c60327431042b6768a9adfb65f226337cc60f Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Thu, 2 Dec 2021 22:00:58 +0900 Subject: [PATCH 087/184] WWST-7793, change FP of the ABL E-series and the Samsung Korea B2B Marketing (#76691) * Update zigbee-white-color-temperature-bulb.groovy Change VID/MNMN of Samsung Korea B2B Marketing * Update zigbee-rgbw-bulb.groovy Change VID/MNMN of ABL --- .../smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy | 4 ++-- .../zigbee-white-color-temperature-bulb.groovy | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 40c753e69e4..17001cf5738 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -40,8 +40,8 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-002", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-002" //ITM RGBW // ABL - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-201", deviceJoinName: "Juno Connect", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-201" //E-series - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-201", deviceJoinName: "Juno Connect", mnmn: "SmartThingsCommunity", vid: "0c0d8ed8-d536-324c-9b80-d4705a55e4df" //E-series + // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010D", manufacturer: "AduroSmart Eria", model: "AD-RGBW3001", deviceJoinName: "Eria Light" //Eria ZigBee RGBW Bulb diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 50426507a0c..b2e1aca9909 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -42,7 +42,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-001", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" //ITM CCT // Samsung Korea B2B Marketing - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "HAN-LIGHT-Z-001", deviceJoinName: "SamsungB2B Light", mnmn: "Samsung Electronics", vid: "HAN-LIGHT-Z-001" //Samsung Korea B2B Marketing CCT + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "HAN-LIGHT-Z-001", deviceJoinName: "SamsungB2B Light", mnmn: "SmartThingsCommunity", vid: "c0b88b06-99f7-3781-a5a8-8a66fccf2bae" //Samsung Korea B2B Marketing CCT // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010C", manufacturer: "AduroSmart Eria", model: "AD-ColorTemperature3001", deviceJoinName: "Eria Light" //Eria ZigBee Color Temperature Bulb From ba57af1a4af810eafa5ac96109d0b4ea91b2cfdb Mon Sep 17 00:00:00 2001 From: Juan Pablo Risso Date: Fri, 3 Dec 2021 13:51:36 -0500 Subject: [PATCH 088/184] C2C-1619 - Ecobee Migration - Remove Groovy --- .../ecobee-sensor.src/ecobee-sensor.groovy | 92 -- .../ecobee-switch.src/ecobee-switch.groovy | 97 -- .../ecobee-thermostat.groovy | 617 -------- .../ecobee-connect.src/ecobee-connect.groovy | 1362 ----------------- .../ecobee-connect.src/i18n/ar-AE.properties | 26 - .../ecobee-connect.src/i18n/bg-BG.properties | 26 - .../ecobee-connect.src/i18n/ca-ES.properties | 26 - .../ecobee-connect.src/i18n/cs-CZ.properties | 26 - .../ecobee-connect.src/i18n/da-DK.properties | 26 - .../ecobee-connect.src/i18n/de-DE.properties | 26 - .../ecobee-connect.src/i18n/el-GR.properties | 26 - .../ecobee-connect.src/i18n/en-GB.properties | 20 - .../ecobee-connect.src/i18n/es-ES.properties | 26 - .../ecobee-connect.src/i18n/es-MX.properties | 26 - .../ecobee-connect.src/i18n/es-US.properties | 20 - .../ecobee-connect.src/i18n/et-EE.properties | 26 - .../ecobee-connect.src/i18n/fi-FI.properties | 26 - .../ecobee-connect.src/i18n/fr-CA.properties | 26 - .../ecobee-connect.src/i18n/fr-FR.properties | 26 - .../ecobee-connect.src/i18n/hr-HR.properties | 26 - .../ecobee-connect.src/i18n/hu-HU.properties | 26 - .../ecobee-connect.src/i18n/it-IT.properties | 26 - .../ecobee-connect.src/i18n/ko-KR.properties | 26 - .../ecobee-connect.src/i18n/nl-NL.properties | 26 - .../ecobee-connect.src/i18n/no-NO.properties | 26 - .../ecobee-connect.src/i18n/pl-PL.properties | 26 - .../ecobee-connect.src/i18n/pt-BR.properties | 26 - .../ecobee-connect.src/i18n/pt-PT.properties | 26 - .../ecobee-connect.src/i18n/ro-RO.properties | 26 - .../ecobee-connect.src/i18n/ru-RU.properties | 26 - .../ecobee-connect.src/i18n/sk-SK.properties | 26 - .../ecobee-connect.src/i18n/sl-SI.properties | 26 - .../ecobee-connect.src/i18n/sq-AL.properties | 26 - .../ecobee-connect.src/i18n/sr-RS.properties | 26 - .../ecobee-connect.src/i18n/sv-SE.properties | 26 - .../ecobee-connect.src/i18n/th-TH.properties | 26 - .../ecobee-connect.src/i18n/tr-TR.properties | 26 - .../ecobee-connect.src/i18n/zh-CN.properties | 26 - 38 files changed, 3040 deletions(-) delete mode 100644 devicetypes/smartthings/ecobee-sensor.src/ecobee-sensor.groovy delete mode 100644 devicetypes/smartthings/ecobee-switch.src/ecobee-switch.groovy delete mode 100644 devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy delete mode 100644 smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties delete mode 100644 smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties diff --git a/devicetypes/smartthings/ecobee-sensor.src/ecobee-sensor.groovy b/devicetypes/smartthings/ecobee-sensor.src/ecobee-sensor.groovy deleted file mode 100644 index bb20924a21b..00000000000 --- a/devicetypes/smartthings/ecobee-sensor.src/ecobee-sensor.groovy +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2015 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. - * - * Ecobee Sensor - * - * Author: SmartThings - */ -import groovy.json.JsonOutput -metadata { - definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") { - capability "Health Check" - capability "Sensor" - capability "Temperature Measurement" - capability "Motion Sensor" - capability "Refresh" - } - - tiles(scale: 2) { - multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) { - tileAttribute ("device.temperature", key: "PRIMARY_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"] - ] - } - } - - standardTile("motion", "device.motion", inactiveLabel: false, width: 2, height: 2) { - state "active", label:"Motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC" - state "inactive", label:"No Motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" - } - - standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "default", action:"refresh.refresh", icon:"st.secondary.refresh" - } - - main (["temperature","motion"]) - details(["temperature","motion","refresh"]) - } -} - -def initialize() { - sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false) - updateDataValue("EnrolledUTDH", "true") -} - -void installed() { - initialize() -} - -def updated() { - log.debug "updated()" - parent.setSensorName(device.label, device.deviceNetworkId) - initialize() -} - -// Called when the DTH is uninstalled, is this true for cirrus/gadfly integrations? -// Informs parent to purge its associated data -def uninstalled() { - log.debug "uninstalled() parent.purgeChildDevice($device.deviceNetworkId)" - // purge DTH from parent - parent?.purgeChildDevice(this) -} - -def refresh() { - log.debug "refresh, calling parent poll" - parent.poll() -} diff --git a/devicetypes/smartthings/ecobee-switch.src/ecobee-switch.groovy b/devicetypes/smartthings/ecobee-switch.src/ecobee-switch.groovy deleted file mode 100644 index 9375b30bccf..00000000000 --- a/devicetypes/smartthings/ecobee-switch.src/ecobee-switch.groovy +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Ecobee Switch+ - * - * Copyright 2016 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: "Ecobee Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { - capability "Switch" - capability "Refresh" - capability "Sensor" - capability "Health Check" - } - - simulator { - // TODO: define status and reply messages here - } - - tiles(scale: 2) { - multiAttributeTile(name:"rich-control", type: "generic", canChangeIcon: true){ - tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { - attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00a0dc", nextState:"turningOff" - attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" - attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00a0dc", nextState:"turningOff" - attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" - } - } - - standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { - state "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00a0dc", nextState:"turningOff" - state "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" - state "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00a0dc", nextState:"turningOff" - state "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" - state "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000" - } - standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - main(["switch"]) - details(["rich-control", "refresh"]) - } -} - -// parse events into attributes -def parse(String description) { - log.debug "Parsing '${description}'" -} - -void initialize() { - sendEvent(name: "DeviceWatch-Enroll", value: toJson([protocol: "cloud", scheme:"untracked"]), displayed: false) -} - -void installed() { - log.trace "[DTH] Executing installed() for device=${this.device.displayName}" - initialize() -} - -void updated() { - log.trace "[DTH] Executing updated() for device=${this.device.displayName}" - initialize() -} - -//remove from the selected devices list in SM -void uninstalled() { - log.trace "[DTH] Executing uninstalled() for device=${this.device.displayName}" - parent?.purgeChildDevice(this) -} - -def refresh() { - log.trace "[DTH] Executing 'refresh' for ${this.device.displayName}" - parent?.poll() -} - -def on() { - log.trace "[DTH] Executing 'on' for ${this.device.displayName}" - boolean desiredState = true - parent.controlSwitch( this.device.deviceNetworkId, desiredState ) -} - -def off() { - log.trace "[DTH] Executing 'off' for ${this.device.displayName}" - boolean desiredState = false - parent.controlSwitch( this.device.deviceNetworkId, desiredState ) -} - -def toJson(Map m) { - return groovy.json.JsonOutput.toJson(m) -} diff --git a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy deleted file mode 100644 index 3aaa542b3d4..00000000000 --- a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy +++ /dev/null @@ -1,617 +0,0 @@ -/** - * Copyright 2015 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. - * - * Ecobee Thermostat - * - * Author: SmartThings - * Date: 2013-06-13 - */ -import groovy.json.JsonOutput -metadata { - definition (name: "Ecobee Thermostat", namespace: "smartthings", author: "SmartThings") { - capability "Actuator" - capability "Thermostat" - capability "Temperature Measurement" - capability "Sensor" - capability "Refresh" - capability "Relative Humidity Measurement" - capability "Health Check" - - // New discrete thermostat capabilities, added to replace "Thermostat" and prepare for migration to st-schema - capability "Thermostat Cooling Setpoint" - capability "Thermostat Heating Setpoint" - capability "Thermostat Mode" - capability "Thermostat Fan Mode" - capability "Thermostat Operating State" - - command "generateEvent" - command "resumeProgram" - command "switchMode" - command "switchFanMode" - command "lowerHeatingSetpoint" - command "raiseHeatingSetpoint" - command "lowerCoolSetpoint" - command "raiseCoolSetpoint" - // To satisfy some SA/rules that incorrectly using poll instead of Refresh - command "poll" - - attribute "thermostat", "string" - attribute "maxHeatingSetpoint", "number" - attribute "minHeatingSetpoint", "number" - attribute "maxCoolingSetpoint", "number" - attribute "minCoolingSetpoint", "number" - attribute "deviceTemperatureUnit", "string" - attribute "deviceAlive", "enum", ["true", "false"] - } - - tiles { - multiAttributeTile(name:"temperature", type:"generic", width:3, height:2, canChangeIcon: true) { - tileAttribute("device.temperature", key: "PRIMARY_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.humidity", key: "SECONDARY_CONTROL") { - attributeState "humidity", label:'${currentValue}%', icon:"st.Weather.weather12" - } - } - standardTile("lowerHeatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "heatingSetpoint", action:"lowerHeatingSetpoint", icon:"st.thermostat.thermostat-left" - } - valueTile("heatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "heatingSetpoint", label:'${currentValue}° heat', backgroundColor:"#ffffff" - } - standardTile("raiseHeatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "heatingSetpoint", action:"raiseHeatingSetpoint", icon:"st.thermostat.thermostat-right" - } - standardTile("lowerCoolSetpoint", "device.coolingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "coolingSetpoint", action:"lowerCoolSetpoint", icon:"st.thermostat.thermostat-left" - } - valueTile("coolingSetpoint", "device.coolingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "coolingSetpoint", label:'${currentValue}° cool', backgroundColor:"#ffffff" - } - standardTile("raiseCoolSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "heatingSetpoint", action:"raiseCoolSetpoint", icon:"st.thermostat.thermostat-right" - } - standardTile("mode", "device.thermostatMode", width:2, height:2, inactiveLabel: false, decoration: "flat") { - state "off", action:"switchMode", nextState: "updating", icon: "st.thermostat.heating-cooling-off" - state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat" - state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool" - state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto" - state "emergency heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.emergency-heat" - state "updating", label:"Updating...", icon: "st.secondary.secondary" - } - standardTile("fanMode", "device.thermostatFanMode", width:2, height:2, inactiveLabel: false, decoration: "flat") { - state "auto", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-auto" - state "on", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-on" - state "updating", label:"Updating...", icon: "st.secondary.secondary" - } - valueTile("thermostat", "device.thermostat", width:2, height:1, decoration: "flat") { - state "thermostat", label:'${currentValue}', backgroundColor:"#ffffff" - } - standardTile("refresh", "device.thermostatMode", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "default", action:"refresh.refresh", icon:"st.secondary.refresh" - } - standardTile("resumeProgram", "device.resumeProgram", width:2, height:1, inactiveLabel: false, decoration: "flat") { - state "resume", action:"resumeProgram", nextState: "updating", label:'Resume', icon:"st.samsung.da.oven_ic_send" - state "updating", label:"Working", icon: "st.secondary.secondary" - } - main "temperature" - details(["temperature", "lowerHeatingSetpoint", "heatingSetpoint", "raiseHeatingSetpoint", - "lowerCoolSetpoint", "coolingSetpoint", "raiseCoolSetpoint", "mode", "fanMode", - "thermostat", "resumeProgram", "refresh"]) - } - - preferences { - input "holdType", "enum", title: "Hold Type", - description: "When changing temperature, use Temporary (Until next transition) or Permanent hold (default)", - required: false, options:["Temporary", "Permanent"] - input "deadbandSetting", "number", title: "Minimum temperature difference between the desired Heat and Cool " + - "temperatures in Auto mode:\nNote! This must be the same as configured on the thermostat", - description: "temperature difference °F", defaultValue: 5, - required: false - } - -} - -void installed() { - // The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline - // Using 12 minutes because in testing, device health team found that there could be "jitter" - initialize() -} -def initialize() { - sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false) - updateDataValue("EnrolledUTDH", "true") -} - -def updated() { - log.debug "updated()" - parent.setName(device.label, device.deviceNetworkId) - initialize() -} - -// Called when the DTH is uninstalled, is this true for cirrus/gadfly integrations? -// Informs parent to purge its associated data -def uninstalled() { - log.debug "uninstalled() parent.purgeChildDevice($device.deviceNetworkId)" - // purge DTH from parent - parent?.purgeChildDevice(this) -} - -def ping() { - log.debug "ping() NOP" -} - -// parse events into attributes -def parse(String description) { - log.debug "Parsing '${description}'" -} - -def refresh() { - log.debug "refresh, calling parent poll" - parent.poll() -} - -void poll() { - log.debug "poll not implemented as it is done by parent SmartApp every 5 minutes" -} - -def generateEvent(Map results) { - if(results) { - def linkText = getLinkText(device) - def supportedThermostatModes = ["off"] - def thermostatMode = null - def locationScale = getTemperatureScale() - - results.each { name, value -> - def event = [name: name, linkText: linkText, handlerName: name] - def sendValue = value - - if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint" ) { - sendValue = getTempInLocalScale(value, "F") // API return temperature values in F - event << [value: sendValue, unit: locationScale] - } else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") { - // Old attributes, keeping for backward compatibility - sendValue = getTempInLocalScale(value, "F") // API return temperature values in F - event << [value: sendValue, unit: locationScale, displayed: false] - // Store min/max setpoint in device unit to avoid conversion rounding error when updating setpoints - device.updateDataValue(name+"Fahrenheit", "${value}") - } else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){ - if (value == true) { - supportedThermostatModes << ((name == "auxHeatMode") ? "emergency heat" : name - "Mode") - } - return // as we don't want to send this event here, proceed to next name/value pair - } else if (name=="thermostatFanMode"){ - sendEvent(name: "supportedThermostatFanModes", value: fanModes(), displayed: false) - event << [value: value, data:[supportedThermostatFanModes: fanModes()]] - } else if (name=="humidity") { - event << [value: value, displayed: false, unit: "%"] - } else if (name == "deviceAlive") { - event['displayed'] = false - } else if (name == "thermostatMode") { - thermostatMode = (value == "auxHeatOnly") ? "emergency heat" : value.toLowerCase() - return // as we don't want to send this event here, proceed to next name/value pair - } else if (name == "name") { - return // as we don't want to send this event, proceed to next name/value pair - } else { - event << [value: value.toString()] - } - event << [descriptionText: getThermostatDescriptionText(name, sendValue, linkText)] - sendEvent(event) - } - if (state.supportedThermostatModes != supportedThermostatModes) { - state.supportedThermostatModes = supportedThermostatModes - sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) - } - if (thermostatMode) { - sendEvent(name: "thermostatMode", value: thermostatMode, data:[supportedThermostatModes:state.supportedThermostatModes], linkText: linkText, - descriptionText: getThermostatDescriptionText("thermostatMode", thermostatMode, linkText), handlerName: "thermostatMode") - } - generateSetpointEvent () - generateStatusEvent () - } -} - -//return descriptionText to be shown on mobile activity feed -def getThermostatDescriptionText(name, value, linkText) { - if(name == "temperature") { - return "temperature is ${value}°${location.temperatureScale}" - - } else if(name == "heatingSetpoint") { - return "heating setpoint is ${value}°${location.temperatureScale}" - - } else if(name == "coolingSetpoint"){ - return "cooling setpoint is ${value}°${location.temperatureScale}" - - } else if (name == "thermostatMode") { - return "thermostat mode is ${value}" - - } else if (name == "thermostatFanMode") { - return "thermostat fan mode is ${value}" - - } else if (name == "humidity") { - return "humidity is ${value} %" - } else { - return "${name} = ${value}" - } -} - -void setHeatingSetpoint(setpoint) { -log.debug "***setHeatingSetpoint($setpoint)" - if (setpoint) { - state.heatingSetpoint = setpoint.toDouble() - runIn(2, "updateSetpoints", [overwrite: true]) - } -} - -def setCoolingSetpoint(setpoint) { -log.debug "***setCoolingSetpoint($setpoint)" - if (setpoint) { - state.coolingSetpoint = setpoint.toDouble() - runIn(2, "updateSetpoints", [overwrite: true]) - } -} - -def updateSetpoints() { - def deviceScale = "F" //API return/expects temperature values in F - def data = [targetHeatingSetpoint: null, targetCoolingSetpoint: null] - def heatingSetpoint = getTempInLocalScale("heatingSetpoint") - def coolingSetpoint = getTempInLocalScale("coolingSetpoint") - if (state.heatingSetpoint) { - data = enforceSetpointLimits("heatingSetpoint", [targetValue: state.heatingSetpoint, - heatingSetpoint: heatingSetpoint, coolingSetpoint: coolingSetpoint]) - } - if (state.coolingSetpoint) { - heatingSetpoint = data.targetHeatingSetpoint ? getTempInLocalScale(data.targetHeatingSetpoint, deviceScale) : heatingSetpoint - coolingSetpoint = data.targetCoolingSetpoint ? getTempInLocalScale(data.targetCoolingSetpoint, deviceScale) : coolingSetpoint - data = enforceSetpointLimits("coolingSetpoint", [targetValue: state.coolingSetpoint, - heatingSetpoint: heatingSetpoint, coolingSetpoint: coolingSetpoint]) - } - state.heatingSetpoint = null - state.coolingSetpoint = null - updateSetpoint(data) -} - -void resumeProgram() { - log.debug "resumeProgram() is called" - - sendEvent("name":"thermostat", "value":"resuming schedule", "description":statusText, displayed: false) - def deviceId = device.deviceNetworkId.split(/\./).last() - if (parent.resumeProgram(deviceId)) { - sendEvent("name":"thermostat", "value":"setpoint is updating", "description":statusText, displayed: false) - } else { - sendEvent("name":"thermostat", "value":"resume failed", "description":statusText, displayed: false) - log.error "Error resumeProgram() check parent.resumeProgram(deviceId)" - } - // Prevent double tap and spamming of resume command - runIn(5, "updateResume", [overwrite: true]) -} - -def updateResume() { - sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true) - refresh() -} - -def modes() { - return state.supportedThermostatModes -} - -def fanModes() { - // Ecobee does not report its supported fanModes; use hard coded values - ["on", "auto"] -} - -def switchMode() { - def currentMode = device.currentValue("thermostatMode") - def modeOrder = modes() - if (modeOrder) { - def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] } - def nextMode = next(currentMode) - switchToMode(nextMode) - } else { - log.warn "supportedThermostatModes not defined" - } -} - -def switchToMode(mode) { - log.debug "switchToMode: ${mode}" - def deviceId = device.deviceNetworkId.split(/\./).last() - // Thermostat's mode for "emergency heat" is "auxHeatOnly" - if (!(parent.setMode(((mode == "emergency heat") ? "auxHeatOnly" : mode), deviceId))) { - log.warn "Error setting mode:$mode" - // Ensure the DTH tile is reset - mode = device.currentValue("thermostatMode") - } - generateModeEvent(mode) - generateStatusEvent() -} - -def switchFanMode() { - def currentFanMode = device.currentValue("thermostatFanMode") - def fanModeOrder = fanModes() - def next = { fanModeOrder[fanModeOrder.indexOf(it) + 1] ?: fanModeOrder[0] } - switchToFanMode(next(currentFanMode)) -} - -def switchToFanMode(fanMode) { - log.debug "switchToFanMode: $fanMode" - def heatingSetpoint = getTempInDeviceScale("heatingSetpoint") - def coolingSetpoint = getTempInDeviceScale("coolingSetpoint") - def deviceId = device.deviceNetworkId.split(/\./).last() - def sendHoldType = holdType ? ((holdType=="Temporary") ? "nextTransition" : "indefinite") : "indefinite" - - if (!(parent.setFanMode(heatingSetpoint, coolingSetpoint, deviceId, sendHoldType, fanMode))) { - log.warn "Error setting fanMode:fanMode" - // Ensure the DTH tile is reset - fanMode = device.currentValue("thermostatFanMode") - } - generateFanModeEvent(fanMode) -} - -def getDataByName(String name) { - state[name] ?: device.getDataValue(name) -} - -def setThermostatMode(String mode) { - log.debug "setThermostatMode($mode)" - def supportedModes = modes() - if (supportedModes) { - mode = mode.toLowerCase() - def modeIdx = supportedModes.indexOf(mode) - if (modeIdx < 0) { - log.warn("Thermostat mode $mode not valid for this thermostat") - return - } - mode = supportedModes[modeIdx] - switchToMode(mode) - } else { - log.warn "supportedThermostatModes not defined" - } -} - -def setThermostatFanMode(String mode) { - log.debug "setThermostatFanMode($mode)" - mode = mode.toLowerCase() - def supportedFanModes = fanModes() - def modeIdx = supportedFanModes.indexOf(mode) - if (modeIdx < 0) { - log.warn("Thermostat fan mode $mode not valid for this thermostat") - return - } - mode = supportedFanModes[modeIdx] - switchToFanMode(mode) -} - -def generateModeEvent(mode) { - sendEvent(name: "thermostatMode", value: mode, data:[supportedThermostatModes: modes()], - isStateChange: true, descriptionText: "$device.displayName is in ${mode} mode") -} - -def generateFanModeEvent(fanMode) { - sendEvent(name: "thermostatFanMode", value: fanMode, data:[supportedThermostatFanModes: fanModes()], - isStateChange: true, descriptionText: "$device.displayName fan is in ${fanMode} mode") -} - -def generateOperatingStateEvent(operatingState) { - sendEvent(name: "thermostatOperatingState", value: operatingState, descriptionText: "$device.displayName is ${operatingState}", displayed: true) -} - -def off() { setThermostatMode("off") } -def heat() { setThermostatMode("heat") } -def emergencyHeat() { setThermostatMode("emergency heat") } -def cool() { setThermostatMode("cool") } -def auto() { setThermostatMode("auto") } - -def fanOn() { setThermostatFanMode("on") } -def fanAuto() { setThermostatFanMode("auto") } -def fanCirculate() { setThermostatFanMode("circulate") } - -// =============== Setpoints =============== -def generateSetpointEvent() { - def mode = device.currentValue("thermostatMode") - def setpoint = getTempInLocalScale("heatingSetpoint") // (mode == "heat") || (mode == "emergency heat") - def coolingSetpoint = getTempInLocalScale("coolingSetpoint") - - if (mode == "cool") { - setpoint = coolingSetpoint - } else if ((mode == "auto") || (mode == "off")) { - setpoint = roundC((setpoint + coolingSetpoint) / 2) - } // else (mode == "heat") || (mode == "emergency heat") - sendEvent("name":"thermostatSetpoint", "value":setpoint, "unit":location.temperatureScale) -} - -def raiseHeatingSetpoint() { - alterSetpoint(true, "heatingSetpoint") -} - -def lowerHeatingSetpoint() { - alterSetpoint(false, "heatingSetpoint") -} - -def raiseCoolSetpoint() { - alterSetpoint(true, "coolingSetpoint") -} - -def lowerCoolSetpoint() { - alterSetpoint(false, "coolingSetpoint") -} - -// Adjusts nextHeatingSetpoint either .5° C/1° F) if raise true/false -def alterSetpoint(raise, setpoint) { - // don't allow setpoint change if thermostat is off - if (device.currentValue("thermostatMode") == "off") { - return - } - def locationScale = getTemperatureScale() - def deviceScale = "F" - def heatingSetpoint = getTempInLocalScale("heatingSetpoint") - def coolingSetpoint = getTempInLocalScale("coolingSetpoint") - def targetValue = (setpoint == "heatingSetpoint") ? heatingSetpoint : coolingSetpoint - def delta = (locationScale == "F") ? 1 : 0.5 - targetValue += raise ? delta : - delta - - def data = enforceSetpointLimits(setpoint, - [targetValue: targetValue, heatingSetpoint: heatingSetpoint, coolingSetpoint: coolingSetpoint], raise) - // update UI without waiting for the device to respond, this to give user a smoother UI experience - // also, as runIn's have to overwrite and user can change heating/cooling setpoint separately separate runIn's have to be used - if (data.targetHeatingSetpoint) { - sendEvent("name": "heatingSetpoint", "value": getTempInLocalScale(data.targetHeatingSetpoint, "F"), - unit: locationScale, eventType: "ENTITY_UPDATE", displayed: false) - } - if (data.targetCoolingSetpoint) { - sendEvent("name": "coolingSetpoint", "value": getTempInLocalScale(data.targetCoolingSetpoint, "F"), - unit: locationScale, eventType: "ENTITY_UPDATE", displayed: false) - } - runIn(5, "updateSetpoint", [data: data, overwrite: true]) -} - -def enforceSetpointLimits(setpoint, data, raise = null) { - def locationScale = getTemperatureScale() - def minSetpoint = (setpoint == "heatingSetpoint") ? device.getDataValue("minHeatingSetpointFahrenheit") : device.getDataValue("minCoolingSetpointFahrenheit") - def maxSetpoint = (setpoint == "heatingSetpoint") ? device.getDataValue("maxHeatingSetpointFahrenheit") : device.getDataValue("maxCoolingSetpointFahrenheit") - minSetpoint = minSetpoint ? Double.parseDouble(minSetpoint) : ((setpoint == "heatingSetpoint") ? 45 : 65) // default 45 heat, 65 cool - maxSetpoint = maxSetpoint ? Double.parseDouble(maxSetpoint) : ((setpoint == "heatingSetpoint") ? 79 : 92) // default 79 heat, 92 cool - def deadband = deadbandSetting ? deadbandSetting : 5 // °F - def delta = (locationScale == "F") ? 1 : 0.5 - def targetValue = getTempInDeviceScale(data.targetValue, locationScale) - def heatingSetpoint = getTempInDeviceScale(data.heatingSetpoint, locationScale) - def coolingSetpoint = getTempInDeviceScale(data.coolingSetpoint, locationScale) - // Enforce min/mix for setpoints - if (targetValue > maxSetpoint) { - targetValue = maxSetpoint - } else if (targetValue < minSetpoint) { - targetValue = minSetpoint - } else if ((raise != null) && ((setpoint == "heatingSetpoint" && targetValue == heatingSetpoint) || - (setpoint == "coolingSetpoint" && targetValue == coolingSetpoint))) { - // Ensure targetValue differes from old. When location scale differs from device, - // converting between C -> F -> C may otherwise result in no change. - targetValue += raise ? delta : - delta - } - // Enforce deadband between setpoints - if (setpoint == "heatingSetpoint") { - heatingSetpoint = targetValue - coolingSetpoint = (heatingSetpoint + deadband > coolingSetpoint) ? heatingSetpoint + deadband : coolingSetpoint - } - if (setpoint == "coolingSetpoint") { - coolingSetpoint = targetValue - heatingSetpoint = (coolingSetpoint - deadband < heatingSetpoint) ? coolingSetpoint - deadband : heatingSetpoint - } - return [targetHeatingSetpoint: heatingSetpoint, targetCoolingSetpoint: coolingSetpoint] -} - -def updateSetpoint(data) { - def deviceId = device.deviceNetworkId.split(/\./).last() - def sendHoldType = holdType ? ((holdType=="Temporary") ? "nextTransition" : "indefinite") : "indefinite" - - if (parent.setHold(data.targetHeatingSetpoint, data.targetCoolingSetpoint, deviceId, sendHoldType)) { - log.debug "updateSetpoint succeed to change setpoints:${data}" - sendEvent("name": "heatingSetpoint", "value": getTempInLocalScale(data.targetHeatingSetpoint, "F"), - unit: getTemperatureScale(), eventType: "ENTITY_UPDATE", displayed: false) - sendEvent("name": "coolingSetpoint", "value": getTempInLocalScale(data.targetCoolingSetpoint, "F"), - unit: getTemperatureScale(), eventType: "ENTITY_UPDATE", displayed: false) - generateStatusEvent() - } else { - log.error "Error updateSetpoint" - runIn(5, "refresh", [overwrite: true]) - } -} - -def generateStatusEvent() { - def mode = device.currentValue("thermostatMode") - def heatingSetpoint = device.currentValue("heatingSetpoint") - def coolingSetpoint = device.currentValue("coolingSetpoint") - def temperature = device.currentValue("temperature") - def statusText = "Right Now: Idle" - def operatingState = "idle" - - if (mode == "heat" || mode == "emergency heat") { - if (temperature < heatingSetpoint) { - statusText = "Heating to ${heatingSetpoint}°${location.temperatureScale}" - operatingState = "heating" - } - } else if (mode == "cool") { - if (temperature > coolingSetpoint) { - statusText = "Cooling to ${coolingSetpoint}°${location.temperatureScale}" - operatingState = "cooling" - } - } else if (mode == "auto") { - if (temperature < heatingSetpoint) { - statusText = "Heating to ${heatingSetpoint}°${location.temperatureScale}" - operatingState = "heating" - } else if (temperature > coolingSetpoint) { - statusText = "Cooling to ${coolingSetpoint}°${location.temperatureScale}" - operatingState = "cooling" - } - } else if (mode == "off") { - statusText = "Right Now: Off" - } else { - statusText = "?" - } - - sendEvent("name":"thermostat", "value":statusText, "description":statusText, displayed: true) - sendEvent("name":"thermostatOperatingState", "value":operatingState, "description":operatingState, displayed: false) -} - -def generateActivityFeedsEvent(notificationMessage) { - sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true) -} - -// Get stored temperature from currentState in current local scale -def getTempInLocalScale(state) { - def temp = device.currentState(state) - def scaledTemp = convertTemperatureIfNeeded(temp.value.toBigDecimal(), temp.unit).toDouble() - return (getTemperatureScale() == "F" ? scaledTemp.round(0).toInteger() : roundC(scaledTemp)) -} - -// Get/Convert temperature to current local scale -def getTempInLocalScale(temp, scale) { - def scaledTemp = convertTemperatureIfNeeded(temp.toBigDecimal(), scale).toDouble() - return (getTemperatureScale() == "F" ? scaledTemp.round(0).toInteger() : roundC(scaledTemp)) -} - -// Get stored temperature from currentState in device scale -def getTempInDeviceScale(state) { - def temp = device.currentState(state) - if (temp && temp.value && temp.unit) { - return getTempInDeviceScale(temp.value.toBigDecimal(), temp.unit) - } - return 0 -} - -def getTempInDeviceScale(temp, scale) { - if (temp && scale) { - //API return/expects temperature values in F - return ("F" == scale) ? temp : celsiusToFahrenheit(temp).toDouble().round(0).toInteger() - } - return 0 -} - -def roundC (tempC) { - return (Math.round(tempC.toDouble() * 2))/2 -} diff --git a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy deleted file mode 100644 index ca7f0cc9be0..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy +++ /dev/null @@ -1,1362 +0,0 @@ -/** - * Copyright 2015 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. - * - * Ecobee Service Manager - * - * Author: scott - * Date: 2013-08-07 - * - * Last Modification: - * JLH - 01-23-2014 - Update for Correct SmartApp URL Format - * JLH - 02-15-2014 - Fuller use of ecobee API - * 10-28-2015 DVCSMP-604 - accessory sensor, DVCSMP-1174, DVCSMP-1111 - not respond to routines - */ -import groovy.json.JsonSlurper -include 'localization' - -definition( - name: "Ecobee (Connect)", - namespace: "smartthings", - author: "SmartThings", - description: "Connect your Ecobee thermostat to SmartThings.", - category: "SmartThings Labs", - iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee.png", - iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee@2x.png", - singleInstance: true, - usesThirdPartyAuthentication: true, - pausable: false -) { - appSetting "clientId" - appSetting "serverUrl" // See note below - // NOTE regarding OAuth settings. On NA01 (i.e. graph.api) and NA01S the serverUrl app setting can be left - // Blank. For other shards is should be set to the callback URL registered with Honeywell, which is: - // - // Production -- https://graph.api.smartthings.com - // Staging -- https://graph-na01s-useast1.smartthingsgdev.com -} - -preferences { - page(name: "auth", title: "ecobee", nextPage:"", content:"authPage", uninstall: true, install:false) - page(name: "deviceList", title: "ecobee", content:"ecobeeDeviceList", install:true) -} - -mappings { - path("/oauth/initialize") {action: [GET: "oauthInitUrl"]} - path("/oauth/callback") {action: [GET: "callback"]} -} - -def authPage() { - log.debug "authPage()" - // Make sure poll/devices are not unscheduled/silenced when authPage is called when the app exits. - // For some reason the first page is called when the app exits normally. - if (!state.initializeEndTime || (now() - state.initializeEndTime > 2000)) { - // Make sure the poll is stopped to prevent state changes while user is configuring the app - unschedule() - // Schedule pollRestart in 15 minutes in case user exits the app abnormally. TODO: Is 15min short/long enough? - runIn(15*60, "restartPoll") - // TODO Make sure no child is calling any poll or command methods to prevent state changes - //def childDevices = getChildDevices() - //if (childDevices) { - // childDevices*.parentBusy(true) - //} - } - - if(!state.accessToken) { //this is to access token for 3rd party to make a call to connect app - state.accessToken = createAccessToken() - } - - def description - def uninstallAllowed = false - def oauthTokenProvided = false - - if(state.authToken) { - if(!state.jwt) { - state.jwt = true - refreshAuthToken() - } - description = "You are connected." - uninstallAllowed = true - oauthTokenProvided = true - } else { - description = "Click to enter Ecobee Credentials" - } - - def redirectUrl = buildRedirectUrl - //log.debug "RedirectUrl = ${redirectUrl}" - // get rid of next button until the user is actually auth'd - if (!oauthTokenProvided) { - return dynamicPage(name: "auth", title: "Login", nextPage: "", uninstall:uninstallAllowed) { - section() { - paragraph "Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button." - href url:redirectUrl, style:"embedded", required:true, title:"ecobee", description:description - } - } - } else { - return dynamicPage(name: "auth", title: "Log In", nextPage:"deviceList", install: false, uninstall:uninstallAllowed) { - section(){ - paragraph "Tap Next to continue to set up your ecobee thermostats." - href url:redirectUrl, style:"embedded", state:"complete", title:"ecobee", description:description - } - } - } -} - -def restartPoll() { - // This method should only be called in case the SA was terminated abnormally without - // calling initialize which will unschedule this and start the poll as part of the normal flow - // TODO Make sure child is calling any poll or command methods to prevent state changes - //def childDevices = getChildDevices() - //if (childDevices) { - // childDevices*.parentBusy(false) - //} - // Call poll - unschedule() - poll() - runEvery5Minutes("poll") -} - -def ecobeeDeviceList() { - getEcobeeDevices() - - def thermostatList = thermostatsDiscovered() - def numThermostats = thermostatList.size() - def sensors = sensorsDiscovered() - def numSensors = sensors.size() - def switches = switchesDiscovered() - def numSwitches = switches.size() - - if (!numThermostats && !numSensors && !numSwitches) { - return dynamicPage(name: "deviceList", title: "No devices found", uninstall: true) { - section ("") { - paragraph "Could not find any devices avilable for SmartThings to control. Please check your ecobee account and retry later." - } - } - } - - return dynamicPage(name: "deviceList", title: "Select Your ecobee Devices", uninstall: true) { - if (numThermostats > 0) { - def preselectedThermostats = thermostatList.collect{it.key} - section("") { - paragraph "Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings." - input(name: "thermostats", title:"Select ecobee Thermostats ({{numThermostats}} found)", messageArgs: [numThermostats: numThermostats], - type: "enum", required:false, multiple:true, - description: "Tap to choose", metadata:[values:thermostatList], defaultValue: preselectedThermostats) - } - } - if (numSensors > 0) { - def preselectedSensors = sensors.collect{it.key} - section("") { - paragraph "Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings." - input(name: "ecobeesensors", title: "Select ecobee remote sensors ({{numSensors}} found)", messageArgs: [numSensors: numSensors], - type: "enum", required:false, description: "Tap to choose", multiple:true, options:sensors, defaultValue: preselectedSensors) - } - } - if (numSwitches > 0) { - def preselectedSwitches = switches.collect{it.key} - section("") { - paragraph "Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings." - input(name: "ecobeeswitches", title: "Select ecobee switches ({{numSwitches}} found)", messageArgs: [numSwitches: numSwitches], - type: "enum", required:false, description: "Tap to choose", multiple:true, options:switches, defaultValue: preselectedSwitches) - } - } - } -} - -def oauthInitUrl() { - log.debug "oauthInitUrl with callback: ${callbackUrl}" - - state.oauthInitState = UUID.randomUUID().toString() - - def oauthParams = [ - response_type: "code", - scope: "smartRead,smartWrite", - client_id: smartThingsClientId, - state: state.oauthInitState, - redirect_uri: callbackUrl - ] - - redirect(location: "${apiEndpoint}/authorize?${toQueryString(oauthParams)}") -} - -def callback() { - log.debug "callback()>> params: $params, params.code ${params.code}" - - def code = params.code - def oauthState = params.state - - if (oauthState == state.oauthInitState) { - def tokenParams = [ - grant_type: "authorization_code", - code : code, - client_id : smartThingsClientId, - redirect_uri: callbackUrl - ] - - def tokenUrl = "${apiEndpoint}/token?${toQueryString(tokenParams)}" - - httpPost(uri: tokenUrl) { resp -> - state.refreshToken = resp.data.refresh_token - state.authToken = resp.data.access_token - } - if ( state.authToken ) { - // get jwt for switch+ devices - state.jwt = true - refreshAuthToken() - } - if (state.authToken) { - success() - } else { - fail() - } - - } else { - log.error "callback() failed oauthState != state.oauthInitState" - } -} - -def success() { - def message = """ -

Your ecobee Account is now connected to SmartThings!

-

Click 'Done' to finish setup.

- """ - connectionStatus(message) -} - -def fail() { - def message = """ -

The connection could not be established!

-

Click 'Done' to return to the menu.

- """ - connectionStatus(message) -} - -def connectionStatus(message, redirectUrl = null) { - def redirectHtml = "" - if (redirectUrl) { - redirectHtml = """ - - """ - } - - def html = """ - - - - - Ecobee & SmartThings connection - - - -
- ecobee icon - connected device icon - SmartThings logo - ${message} -
- - - """ - - render contentType: 'text/html', data: html -} - -def getEcobeeDevices() { - log.debug "getting device list" - state.remoteSensors = [] // reset depriciated application state, replaced by remoteSensors2 - - def thermostatList = [:] - def remoteSensors = [:] - def switchList = [:] - def isThermostatPolled = false - def isSwitchesPolled = false - def pollAttempt = 1 - // try obtain devices twice, in case authToken needs to be refreshed - while (!(isThermostatPolled && isSwitchesPolled) && (pollAttempt < 3)) { - try { - // First get thermostats their remote sensors - if (!isThermostatPolled) { - def bodyParams = [ - selection: [ - selectionType: "registered", - selectionMatch: "", - includeSettings: true, - includeRuntime: true, - includeSensors: true - ] - ] - def deviceListParams = [ - uri: apiEndpoint, - path: "/1/thermostat", - headers: ["Content-Type": "text/json", "Authorization": "Bearer ${state.authToken}"], - // TODO - the query string below is not consistent with the Ecobee docs: - // https://www.ecobee.com/home/developer/api/documentation/v1/operations/get-thermostats.shtml - query: [format: 'json', body: toJson(bodyParams)] - ] - httpGet(deviceListParams) { resp -> - isThermostatPolled = true - if (resp.status == 200) { - resp.data.thermostatList.each { stat -> - def dni = [ app.id, stat.identifier ].join('.') - def data = getThermostatData(stat) - thermostatList[dni] = thermostatList[dni] ? thermostatList[dni] << [data:data] : [data:data] - thermostatList[dni].polled = true - thermostatList[dni].pollAttempts = 0 - // compile all remote sensors conected to the thermostat - stat.remoteSensors.each { sensor -> - if (sensor.type == "ecobee3_remote_sensor") { - def rsDni = "ecobee_sensor-"+ sensor?.id + "-" + sensor?.code - remoteSensors[rsDni] = sensor - remoteSensors[rsDni] << [thermostatId: dni] - } - } - } - state.remoteSensors2 = remoteSensors - state.thermostats = thermostatList - } else { - log.debug "Failed to get thermostats and sensors, status:${resp.status}" - } - } - } - // Now get light swiches - if (!isSwitchesPolled) { - def switchListParams = [ - uri: apiEndpoint + "/ea/devices", - headers: ["Content-Type": "application/json;charset=UTF-8", "Authorization": "Bearer ${state.authToken}"], - ] - httpGet(switchListParams) { resp -> - isSwitchesPolled = true - if (resp.status == 200) { - resp.data?.devices?.each { - if (it.type == "LIGHT_SWITCH") { - switchList[it?.identifier] = it - switchList[it?.identifier] << [deviceAlive: (it?.connected ?: false)] - } - } - state.switchList = switchList - } else { - log.warn "Unable to get switch device list, status:${resp.status}" - } - } - } - } catch (groovyx.net.http.HttpResponseException e) { - log.error "Exception getEcobeeDevices: ${e?.getStatusCode()}, e:${e}, data:${e.response?.data}" - if (e.response?.data?.status?.code == 14) { - pollAttempt++ - if (pollAttempt > 2 || !refreshAuthToken()) { - pollAttempt = 3 - log.error "Ecobee failed getting devices despite refreshing authToken" - } - } - } catch (Exception e) { - log.error "Unhandled exception $e in getEcobeeDevices tried:${pollAttempt} times" - // break the loop and exit - pollAttempt = 3 - } - } -} - -Map thermostatsDiscovered() { - def map = [:] - def thermostatList = state.thermostats ?: [:] - thermostatList.each { key, stat -> - map[key] = stat.data.name - } - return map -} - -Map sensorsDiscovered() { - def map = [:] - def remoteSensors = state.remoteSensors2 ?: [:] - remoteSensors.each { key, sensors -> - map[key] = sensors.name - } - return map -} - -def switchesDiscovered() { - def map = [:] - def switches = state.switchList ?: [:] - switches.each { key, ecobeeSwitch -> - map[key] = ecobeeSwitch.name - } - return map -} - -def getThermostatDisplayName(stat) { - if(stat?.name) { - return stat.name.toString() - } - return (getThermostatTypeName(stat) + " (${stat.identifier})").toString() -} - -def getThermostatTypeName(stat) { - return stat.modelNumber == "siSmart" ? "Smart Si" : "Smart" -} - -def installed() { - log.debug "Installed with settings: ${settings}" - // initialize will be called by the updated method -} - -def updated() { - log.debug "Updated with settings: ${settings}" - unsubscribe() - unschedule() - initialize() -} - -def initialize() { - def thermostatList = state.thermostats ?: [:] - def remoteSensors = state.remoteSensors2 ?: [:] - def switchList = state.switchList ?: [:] - def childThermostats = thermostats.collect { dni -> - def d = getChildDevice(dni) - if(!d) { - d = addChildDevice(app.namespace, getChildName(), dni, null, ["label":"${thermostatList[dni].data.name}" ?: getChildName()]) - log.debug "created ${d.displayName} with id $dni" - // initialize DTH with default data will be done using the first poll data - // TODO: Move this to DTH install method - d.generateEvent(thermostatList[dni].data) - } else { - log.debug "found ${d.displayName} with id $dni already exists" - } - return d - } - def childSensors = ecobeesensors.collect { dni -> - def d = getChildDevice(dni) - if(!d) { - d = addChildDevice(app.namespace, getSensorChildName(), dni, null, ["label":remoteSensors[dni].name ?: getSensorChildName()]) - log.debug "created ${d.displayName} with id $dni" - // initialize DTH with default data - TODO: Move this to DTH install method - d.sendEvent(name:"temperature", value: 0, unit: location.temperatureScale, - descriptionText: "temperature is unknown", displayed: true) - d.sendEvent(name:"motion", value: "inactive") - } else { - log.debug "found ${d.displayName} with id $dni already exists" - } - return d - } - def childSwitches = ecobeeswitches.collect { dni -> - def d = getChildDevice(dni) - if(!d) { - d = addChildDevice(app.namespace, getSwitchChildName(), dni, null, ["label":"${switchList[dni].name}" ?: getSwitchChildName()]) - log.debug "created ${d.displayName} with id $dni" - // initialize DTH with default data - TODO: Move this to DTH install method - d.sendEvent(name:"switch", value: "off") - } else { - log.debug "found ${d.displayName} with id $dni already exists" - } - return d - } - - log.debug "Now have ${childThermostats.size()} thermostats, ${childSensors.size()} sensors and ${childSwitches.size()} switches" - - def delete // Delete any that are no longer in settings - if(!thermostats && !ecobeesensors && !ecobeeswitches) { - log.debug "delete thermostats ands sensors" - delete = getAllChildDevices() //inherits from SmartApp (data-management) - } else { //delete only thermostat - log.debug "delete individual thermostat and sensor" - delete = getChildDevices().findAll { - !thermostats?.contains(it.deviceNetworkId) && - !ecobeesensors?.contains(it.deviceNetworkId) && - !ecobeeswitches?.contains(it.deviceNetworkId) - } - } - log.warn "force deleting devices ${delete}" - delete.each { deleteChildDevice(it.deviceNetworkId, true) } //inherits from SmartApp (data-management) - - // TODO Schedule purge of uninstalled device data as it takes some time before the child is gone - runIn(10, "purgeUninstalledDeviceData", [overwrite: true]) - - //send activity feeds to tell that device is connected - def notificationMessage = "is connected to SmartThings" - sendActivityFeeds(notificationMessage) - state.timeSendPush = null - state.reAttempt = 0 - -// pollHandler() //first time polling data data from thermostat - // clear depreciated data - state.remoteSensors = [] - state.sensors = [] - //automatically update devices status every 5 mins - runEvery5Minutes("poll") - poll() - state.initializeEndTime = now() -} - -def purgeUninstalledDeviceData() { - // purge state from devices that are not selected - def thermostatList = state.thermostats ?: [:] - def remoteSensors = state.remoteSensors2 ?: [:] - def switchList = state.switchList ?: [:] - - // clean up device lists - thermostatList.keySet().removeAll(thermostatList.keySet() - thermostats) - remoteSensors.keySet().removeAll(remoteSensors.keySet() - ecobeesensors) - switchList.keySet().removeAll(switchList.keySet() - ecobeeswitches) - state.thermostats = thermostatList - state.remoteSensors2 = remoteSensors - state.switchList = switchList -} - -def purgeChildDevice(childDevice) { - def dni = childDevice.device.deviceNetworkId - def thermostatList = state.thermostats ?: [:] - def remoteSensors = state.remoteSensors2 ?: [:] - def switchList = state.switchList ?: [:] - if (thermostatList[dni]) { - thermostatList.remove(dni) - state.thermostats = thermostatList - if (thermostats) { - thermostats.remove(dni) - } - app.updateSetting("thermostats", thermostats ? thermostats : []) - } else if (remoteSensors[dni]){ - remoteSensors.remove(dni) - state.remoteSensors2 = remoteSensors - if (ecobeesensors) { - ecobeesensors.remove(dni) - } - app.updateSetting("ecobeesensors", ecobeesensors ? ecobeesensors : []) - } else if(switchList[dni]) { - switchList.remove(dni) - state.switchList = switchList - if (ecobeeswitches) { - ecobeeswitches.remove(dni) - } - app.updateSetting("ecobeeswitches", ecobeeswitches ? ecobeeswitches : []) - } else { - log.error "Failed to purge data for childDevice dni:$dni" - } - if (getChildDevices().size <= 1) { - log.info "No more thermostats to poll, unscheduling" - unschedule() - state.authToken = null - runIn(1, "terminateMe") - } -} - -def terminateMe() { - log.info "terminateMe" - try { - app.delete() - } catch (Exception e) { - log.error "Termination failed, I’m invincible!" - } -} - -def poll() { - // No need to keep trying to poll if authToken is null - if (!state.authToken) { - log.info "poll failed due to authToken=null" - def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials." - sendPushAndFeeds(notificationMessage) - markChildrenOffline(true) - unschedule() - unsubscribe() - return - } - def isThermostatPolled = !(thermostats || ecobeesensors) // If no thermostats or sensors, mark them polled - def isSwitchesPolled = !(ecobeeswitches) // If no switches, mark them polled - def pollAttempt = 1 - - // Mark all devices as offline for device health - def remoteSensors = state.remoteSensors2 ?: [:] - def thermostatList = state.thermostats ?: [:] - def switchList = state.switchList ?: [:] - remoteSensors.each { rdni, sensor -> - sensor.deviceAlive = false - sensor.polled = false - } - thermostatList.each { dni, stat -> - stat.polled = false - stat.data = stat.data ? stat.data << [deviceAlive:false] : [deviceAlive:false] - } - switchList.each { sdni, sw -> - sw.deviceAlive = false - sw.polled = false - } - state.remoteSensors2 = remoteSensors - state.thermostats = thermostatList - state.switchList = switchList - - while (!(isThermostatPolled && isSwitchesPolled) && (pollAttempt < 3)) { - try{ - // First check if we need to poll thermostats or sensors - if (!isThermostatPolled) { - def requestBody = [ - selection: [ - selectionType: "registered", - selectionMatch: "", - includeExtendedRuntime: true, - includeSettings: true, - includeRuntime: true, - includeSensors: true - ] - ] - def pollParams = [ - uri: apiEndpoint, - path: "/1/thermostat", - headers: ["Content-Type": "text/json", "Authorization": "Bearer ${state.authToken}"], - // TODO - the query string below is not consistent with the Ecobee docs: - // https://www.ecobee.com/home/developer/api/documentation/v1/operations/get-thermostats.shtml - query: [format: 'json', body: toJson(requestBody)] - ] - - httpGet(pollParams) { resp -> - isThermostatPolled = true - if(resp.status == 200) { - storeThermostatData(resp.data.thermostatList) - if (ecobeesensors) { - updateSensorData(resp.data.thermostatList.remoteSensors) - } - } - } - } - // Check if we have switches that needs to be polled - if (!isSwitchesPolled) { - def switchListParams = [ - uri: apiEndpoint + "/ea/devices", - headers: ["Content-Type": "application/json;charset=UTF-8", "Authorization": "Bearer ${state.authToken}"], - ] - - httpGet(switchListParams) { resp -> - isSwitchesPolled = true - if (resp.status == 200) { - updateSwitches(resp.data?.devices) - } else { - log.warn "Unable to get switch device list!" - } - } - } - - } catch (groovyx.net.http.HttpResponseException e) { - log.info "HttpResponseException ${e}, ${e?.getStatusCode()} polling ecobee pollAttempt:${pollAttempt}, " + - "isThermostatPolled:${isThermostatPolled}, isSwitchesPolled:${isSwitchesPolled}, ${e?.response?.data}" - if (e?.getStatusCode() == 401 || e?.response?.data?.status?.code == 14) { - pollAttempt++ - // Try refresh authToken and try poll one more time - if (pollAttempt > 2 || !refreshAuthToken()) { - // refresh of authToken failed, break the loop and exit - pollAttempt = 3 - log.error "Ecobee poll failed despite refreshing authToken" - } - } else { - log.error "Ecobee poll failed for other reason than expired authToken" - // break the loop and exit - pollAttempt = 3 - } - } catch (Exception e) { - log.error "Unhandled exception $e in ecobee polling pollAttempt:${pollAttempt}, " + - "isThermostatPolled:${isThermostatPolled}, isSwitchesPolled:${isSwitchesPolled}" - // break the loop and exit - pollAttempt = 3 - } - } - markChildrenOffline() - log.trace "poll exit pollAttempt:${pollAttempt}, isThermostatPolled:${isThermostatPolled}, " + - "isSwitchesPolled:${isSwitchesPolled}" -} - -def markChildrenOffline(boolean markAllOffline = false) { - if (markAllOffline) { - def childDevices = getChildDevices() - childDevices.each{ child -> - child.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - child.sendEvent("name":"thermostat", "value":"Offline") - } - } else { - def remoteSensors = state.remoteSensors2 ?: [:] - def thermostatList = state.thermostats ?: [:] - def switchList = state.switchList ?: [:] - // For devices offline that wasn't polled update pollAttemps, if this is 3rd pollAttempts, mark device offline - def thermostatsOffline = thermostatList.findAll { dni, stat -> - if ((stat.data.deviceAlive == false) && (stat.polled == false)) { - stat.pollAttempts = stat.pollAttempts ? stat.pollAttempts + 1 : 1 - if (stat.pollAttempts > 2) { - return dni - } - } - }?.keySet() - def remoteSensorsOffline = remoteSensors.findAll { rsdni, sensor -> - if ((sensor.deviceAlive == false) && (sensor.polled == false)) { - sensor.pollAttempts = sensor.pollAttempts ? sensor.pollAttempts + 1 : 1 - if (sensor.pollAttempts > 2) { - return rsdni - } - } - }?.keySet() - def switchesOffline = switchList.findAll { sdni, sw -> - if ((sw.deviceAlive == false) && (sw.polled == false)) { - sw.pollAttempts = sw.pollAttempts ? sw.pollAttempts + 1 : 1 - if (sw.pollAttempts > 2) { - return sdni - } - } - }?.keySet() - def devicesOffline = thermostatsOffline + remoteSensorsOffline + switchesOffline - devicesOffline.each { dni -> - def child = getChildDevice(dni) - if (child) { - child.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - } - } - state.remoteSensors2 = remoteSensors - state.thermostats = thermostatList - state.switchList = switchList - } -} - -// Poll Child is invoked from the Child Device itself as part of the Poll Capability -def pollChild() { - log.warn "Depreciated method pollChild is called" -} - -void controlSwitch( dni, desiredState ) { - // no need to try sending a command if authToken is null - if (!state.authToken) { - log.warn "controlSwitch failed due to authToken=null" - return - } - - def deviceAlive = state.switchList[dni].deviceAlive - // Only send command to online switches - if (deviceAlive == true) { - def d = getChildDevice(dni) - log.trace "[SM] Executing '${(desiredState ? "on" : "off")}' controlSwitch for ${d.device.displayName}" - def body = [ "on": desiredState ] - def params = [ - uri: apiEndpoint + "/ea/devices/ls/$dni/state", - headers: ["Content-Type": "application/json;charset=UTF-8", "Authorization": "Bearer ${state.authToken}"], - body: toJson(body) - ] - def keepTrying = true - def tokenRefreshTries = 0 - - while (keepTrying) { - try { - httpPut(params) { resp -> - keepTrying = false - def rspDataString = "${resp?.data}".toString() - log.info "RESPONSE CODE: ${resp.status}, data:${rspDataString}" - } - } catch (groovyx.net.http.HttpResponseException e) { - //log.warn "Code=${e.getStatusCode()}" - if (e.getStatusCode() == 401) { - tokenRefreshTries++ - if (tokenRefreshTries > 1 || !refreshAuthToken()) { - // refresh of authToken failed, break the loop and exit - log.info "Error refreshing auth_token! Unable to control switch: ${d.device.displayName}" - keepTrying = false - } else { - params.headers.Authorization = "Bearer ${state.authToken}" - } - } else if (e.getStatusCode() == 200) { - // Due to ecobee API returning empty boddy on success we get HttpResponseException from platfrom - // so handle sucess response here - keepTrying = false - log.debug "Ecobee response to switch control = 'Success' for ${d.device.displayName}" - def switchState = desiredState == true ? "on" : "off" - d.sendEvent(name:"switch", value: switchState) - } else { - keepTrying = false - log.error "Exception from device control status:${e.getStatusCode()}, getMessage:${e.getMessage()}" - } - } catch (Exception e) { - def rspDataString = "${e.response?.data}".toString() - log.error "Unhandled exception ${e.getStatusCode()}, $e, response data:$rspDataString" - keepTrying = false - } - } - } else { - log.debug "Can't send command to offline swich!" - } -} - -def availableModes(child) { - def tData = state.thermostats[child.device.deviceNetworkId] - - if(!tData) { - log.error "ERROR: Device connection removed? no data for ${child.device.deviceNetworkId} after polling" - return null - } - - def modes = ["off"] - - if (tData.data.heatMode) { - modes.add("heat") - } - if (tData.data.coolMode) { - modes.add("cool") - } - if (tData.data.autoMode) { - modes.add("auto") - } - if (tData.data.auxHeatMode) { - modes.add("auxHeatOnly") - } - - return modes -} - -def currentMode(child) { - - def tData = state.thermostats[child.device.deviceNetworkId] - - if(!tData) { - log.error "ERROR: Device connection removed? no data for ${child.device.deviceNetworkId} after polling" - return null - } - - def mode = tData.data.thermostatMode - return mode -} - -def updateSwitches(switches) { - if (switches) { - def switchList = state.switchList ?: [:] - switches.each { - if ( it.type == "LIGHT_SWITCH" ) { - def childSwitch = getChildDevice(it?.identifier) - if (childSwitch) { - switchList[it?.identifier] = it - switchList[it?.identifier] << [deviceAlive: (it?.connected ?: false)] - switchList[it?.identifier].polled = true - switchList[it?.identifier].pollAttempts = 0 - if (it?.connected) { - def switchState = it?.state?.on == true ? "on" : "off" - childSwitch.sendEvent(name:"switch", value: switchState) - childSwitch.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - } else { - childSwitch.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - } - } else { - log.info "[SM] pollSwitches received data for non-smarthings switch, ingoring" - } - } - } - state.switchList = switchList - } -} - -def updateSensorData(sensorData) { - def remoteSensors = state.remoteSensors2 ?: [:] - sensorData.each { - it.each { - if (it.type == "ecobee3_remote_sensor") { - def temperature = "" - def occupancy = "" - def dni = "ecobee_sensor-"+ it?.id + "-" + it?.code - def child = getChildDevice(dni) - if(child) { - // If DeviceWatch hasn't be enrolled as untracked scheme, re-enroll - if (!child.getDataValue("EnrolledUTDH")) { - child.updated() - } else if (it?.name && (it.name != child.displayName)) { - // Only allowing name change after DeviceWatch has been enrolled, this to ensure the ST name - // is preserved and not changed to name from ecobee cloud as this is the first name change is allowed - child.setDisplayName(it.name) - } - if (remoteSensors[dni] && remoteSensors[dni].deviceAlive) { - it.capability.each { - if (it.type == "temperature") { - if (it.value == "unknown") { - // setting to 0 as "--" is not a valid number depite 0 being a valid value - temperature = 0 - } else { - if (location.temperatureScale == "F") { - temperature = Math.round(it.value.toDouble() / 10) - } else { - temperature = convertFtoC(it.value.toDouble() / 10) - } - } - } else if (it.type == "occupancy") { - occupancy = (it.value == "true") ? "active" : "inactive" - } - } - remoteSensors[dni] << it - child.sendEvent(name:"temperature", value: temperature, unit: location.temperatureScale, - descriptionText: "temperature is " + (temperature ? "${temperature}°${location.temperatureScale}" : "unknown"), displayed: true) - child.sendEvent(name:"motion", value: occupancy) - child.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - } else { - if (remoteSensors[dni]) { - remoteSensors[dni] << it - } else if (!child.getDataValue("DeviceIssue")) { - child.updateDataValue("DeviceIssue", "Please remove and re-add sensor") - } - child.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - } - } - } - } - } - state.remoteSensors2 = remoteSensors -} - -def getChildDeviceIdsString() { - return thermostats.collect { it.split(/\./).last() }.join(',') -} - -def toJson(Map m) { - return groovy.json.JsonOutput.toJson(m) -} - -def toQueryString(Map m) { - return m.collect { k, v -> "${k}=${URLEncoder.encode(v.toString())}" }.sort().join("&") -} - -boolean refreshAuthToken() { - log.debug "refreshing auth token" - def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials." - def isSuccess = false - - if(!state.refreshToken) { - log.warn "Can not refresh OAuth token since there is no refreshToken stored" - sendPushAndFeeds(notificationMessage) - } else { - def refreshParams = [ - method: 'POST', - uri : apiEndpoint, - path : "/token" - ] - if (state.jwt) { - refreshParams.query = [ - grant_type: "refresh_token", - refresh_token: state.refreshToken, - client_id : smartThingsClientId, - ecobee_type: "jwt" - ] - } else { - refreshParams.query = [ - grant_type: "refresh_token", - code: state.refreshToken, - client_id: smartThingsClientId - ] - } - try { - httpPost(refreshParams) { resp -> - if(resp.status == 200) { - log.debug "Token refreshed, ${resp.data}" - state.refreshToken = resp.data?.refresh_token - state.authToken = resp.data?.access_token - state.reAttempt = 0 - isSuccess = true - } - } - } catch (groovyx.net.http.HttpResponseException e) { - def rspDataString = "${e.response?.data}".toString() - log.error "Error refreshing auth_token:${e.statusCode}, refreshAttempt:${state.reAttempt}, response data:$rspDataString" - if ((e.statusCode == 400) || (e.statusCode == 302)) { - def slurper = new JsonSlurper() - def rspData = slurper.parseText(rspDataString) - if (rspData && (rspData.error != "invalid_request" || rspData.error != "not_supported")) { - // either "invalid_grant", "unauthorized_client", "unsupported_grant_type", - // or "invalid_scope", request user to re-enter credentials - sendPushAndFeeds(notificationMessage) - } - } else if (e.statusCode == 401) { // unauthorized*/ - state.reAttempt = state.reAttempt ? state.reAttempt + 1 : 1 - log.warn "reAttempt refreshAuthToken ${state.reAttempt}" - if (state.reAttempt > 3) { - sendPushAndFeeds(notificationMessage) - state.reAttempt = 0 - } - } - } - } - return isSuccess -} - -/** - * Executes the resume program command on the Ecobee thermostat - * @param deviceId - the ID of the device - * - * @retrun true if the command was successful, false otherwise. - */ -boolean resumeProgram(deviceId) { - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: deviceId, - includeRuntime: true - ], - functions: [ - [ - type: "resumeProgram" - ] - ] - ] - return sendCommandToEcobee(payload) -} - -/** - * Executes the set hold command on the Ecobee thermostat - * @param heating - The heating temperature to set in fahrenheit - * @param cooling - the cooling temperature to set in fahrenheit - * @param deviceId - the ID of the device - * @param sendHoldType - the hold type to execute - * - * @return true if the command was successful, false otherwise - */ -boolean setHold(heating, cooling, deviceId, sendHoldType) { - // Ecobee requires that temp values be in fahrenheit multiplied by 10. - int h = heating * 10 - int c = cooling * 10 - - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: deviceId, - includeRuntime: true - ], - functions: [ - [ - type: "setHold", - params: [ - coolHoldTemp: c, - heatHoldTemp: h, - holdType: sendHoldType - ] - ] - ] - ] - - return sendCommandToEcobee(payload) -} - -/** - * Executes the set fan mode command on the Ecobee thermostat - * @param heating - The heating temperature to set in fahrenheit - * @param cooling - the cooling temperature to set in fahrenheit - * @param deviceId - the ID of the device - * @param sendHoldType - the hold type to execute - * @param fanMode - the fan mode to set to - * - * @return true if the command was successful, false otherwise - */ -boolean setFanMode(heating, cooling, deviceId, sendHoldType, fanMode) { - // Ecobee requires that temp values be in fahrenheit multiplied by 10. - int h = heating * 10 - int c = cooling * 10 - - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: deviceId, - includeRuntime: true - ], - functions: [ - [ - type: "setHold", - params: [ - coolHoldTemp: c, - heatHoldTemp: h, - holdType: sendHoldType, - fan: fanMode - ] - ] - ] - ] - - return sendCommandToEcobee(payload) -} - -/** - * Sets the mode of the Ecobee thermostat - * @param mode - the mode to set to - * @param deviceId - the ID of the device - * - * @return true if the command was successful, false otherwise - */ -boolean setMode(mode, deviceId) { - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: deviceId, - includeRuntime: true - ], - thermostat: [ - settings: [ - hvacMode: mode - ] - ] - ] - return sendCommandToEcobee(payload) -} - -/** - * Sets the name of the Ecobee thermostat - * @param name - the name to set to - * @param deviceId - the ID of the device - * - * @return true if the command was successful, false otherwise - */ -def setName(name, deviceId) { - def thermostatList = state.thermostats ?: [:] - if (thermostatList[deviceId]?.data?.name != name) { - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: deviceId.split(/\./).last(), - includeRuntime: true - ], - thermostat: [ - name: name - ] - ] - log.debug "setName: payload:$payload" - sendCommandToEcobee(payload) - } -} - -/** - * Sets the name of the Ecobee3 remote sensor - * @param name - the name to set to - * @param deviceId - the ID of the device - * - * @return true if the command was successful, false otherwise - */ -def setSensorName(name, deviceId) { - def remoteSensors = state.remoteSensors2 ?: [:] - if (remoteSensors[deviceId] && (remoteSensors[deviceId]?.name != name)) { - def payload = [ - selection: [ - selectionType: "thermostats", - selectionMatch: remoteSensors[deviceId].thermostatId?.split(/\./).last(), - includeRuntime: true - ], - functions: [ - [ - "type": "updateSensor", - "params": [ - "deviceId": remoteSensors[deviceId].id, - "sensorId": remoteSensors[deviceId].capability?.first()?.id, - "name": name - ] - ] - ] - ] - log.debug "setSensorName: payload:$payload" - sendCommandToEcobee(payload) - } -} - -/** - * Makes a request to the Ecobee API to actuate the thermostat. - * Used by command methods to send commands to Ecobee. - * - * @param bodyParams - a map of request parameters to send to Ecobee. - * - * @return true if the command was accepted by Ecobee without error, false otherwise. - */ -boolean sendCommandToEcobee(Map bodyParams) { - // no need to try sending a command if authToken is null - if (!state.authToken) { - log.warn "sendCommandToEcobee failed due to authToken=null" - return false - } - def isSuccess = false - def cmdParams = [ - uri: apiEndpoint, - path: "/1/thermostat", - headers: ["Content-Type": "application/json", "Authorization": "Bearer ${state.authToken}"], - body: toJson(bodyParams) - ] - def keepTrying = true - def cmdAttempt = 1 - - while (keepTrying) { - try{ - httpPost(cmdParams) { resp -> - keepTrying = false - if(resp.status == 200) { - log.debug "updated ${resp.data}" - def returnStatus = resp.data.status.code - if (returnStatus == 0) { - log.debug "Successful call to ecobee API." - isSuccess = true - } else { - log.debug "Error return code = ${returnStatus}" - } - } - } - } catch (groovyx.net.http.HttpResponseException e) { - log.info "Exception sending command: $e, status:${e.getStatusCode()}, ${e?.response?.data}" - if (e.response.data.status.code == 14) { - cmdAttempt++ - if (cmdAttempt > 2 || !refreshAuthToken()) { - // refresh authToken failed, break loop and exit - log.error "Error refreshing auth_token! Unable to send command" - keepTrying = false - } else { - cmdParams.headers.Authorization = "Bearer ${state.authToken}" - } - } else { - log.error "Exception sending command: Authentication error, invalid authentication method, lack of credentials, etc." - keepTrying = false - } - } - } - return isSuccess -} - -def getChildName() { return "Ecobee Thermostat" } -def getSensorChildName() { return "Ecobee Sensor" } -def getSwitchChildName() { return "Ecobee Switch" } -def getServerUrl() { return appSettings.serverUrl ?: apiServerUrl } -def getCallbackUrl() { return "${serverUrl}/oauth/callback" } -def getBuildRedirectUrl() { return "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" } -def getApiEndpoint() { return "https://api.ecobee.com" } -def getSmartThingsClientId() { return appSettings.clientId } -def getVendorIcon() { return "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee.png" } - -//send both push notification and mobile activity feeds -def sendPushAndFeeds(notificationMessage) { - def timeNow = now() - log.warn "sendPushAndFeeds >> notificationMessage: ${notificationMessage}" - log.warn "sendPushAndFeeds >> state.timeSendPush: ${state.timeSendPush}" - // notification is sent to remind user once a day - if (!state.timeSendPush || (24 * 60 * 60 * 1000 < (timeNow - state.timeSendPush))) { - sendPush("Your Ecobee thermostat " + notificationMessage) - sendActivityFeeds(notificationMessage) - state.timeSendPush = now() - } - state.authToken = null -} - -def getThermostatData(data) { - - return [ - name: getThermostatDisplayName(data),//stat.name ? stat.name : stat.identifier), - coolMode: (data.settings.coolStages > 0), - heatMode: (data.settings.heatStages > 0), - deviceTemperatureUnit: (data.settings.useCelsius == false && location.temperatureScale == "F") ? "F" : "C", - minHeatingSetpoint: (data.settings.heatRangeLow / 10), - maxHeatingSetpoint: (data.settings.heatRangeHigh / 10), - minCoolingSetpoint: (data.settings.coolRangeLow / 10), - maxCoolingSetpoint: (data.settings.coolRangeHigh / 10), - autoMode: data.settings.autoHeatCoolFeatureEnabled, - deviceAlive: data.runtime.connected, - auxHeatMode: (data.settings.hasHeatPump) && (data.settings.hasForcedAir || data.settings.hasElectric || data.settings.hasBoiler), - temperature: (data.runtime.actualTemperature / 10), - heatingSetpoint: (data.runtime.desiredHeat / 10), - coolingSetpoint: (data.runtime.desiredCool / 10), - thermostatMode: data.settings.hvacMode, - humidity: data.runtime.actualHumidity, - thermostatFanMode: data.runtime.desiredFanMode - ] -} - -/** - * Stores data about the thermostats in atomicState. - * @param thermostats - a list of thermostats as returned from the Ecobee API - */ -void storeThermostatData(thermostatData) { - def data - def remoteSensors = state.remoteSensors2 ?: [:] - def thermostatList = state.thermostats ?: [:] - thermostatData.each { stat -> - def dni = [ app.id, stat.identifier ].join('.') - def childDevice = getChildDevice(dni) - data = getThermostatData(stat) - if (childDevice) { - // Adjust autoMode in regards to coolMode and heatMode as thermostat may report autoMode:true despite only having heat or cool mode - data["autoMode"] = data["autoMode"] && data.coolMode && data.heatMode - if (!childDevice.getDataValue("EnrolledUTDH")) { - childDevice.updated() - } - if (childDevice.displayName != data.name) { - childDevice.setDisplayName(data.name) - } - if (data["deviceAlive"]) { - childDevice.generateEvent(data) - childDevice.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - } else { - childDevice.sendEvent("name":"thermostat", "value":"Offline") - childDevice.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - } - thermostatList[dni] = thermostatList[dni] ? thermostatList[dni] << [data:data] : [data:data] - thermostatList[dni].polled = true - thermostatList[dni].pollAttempts = 0 - } else { - log.info "Got poll data for ${data.name} with identifier ${stat.identifier} that doesn't have a DTH" - } - // Make sure any remote senors connected to the thermostat are marked offline too - stat.remoteSensors.each { sensor -> - if (sensor.type == "ecobee3_remote_sensor") { - def rsDni = "ecobee_sensor-"+ sensor?.id + "-" + sensor?.code - if (ecobeesensors?.contains(rsDni)) { - remoteSensors[rsDni] = remoteSensors[rsDni] ? - remoteSensors[rsDni] << [deviceAlive:data["deviceAlive"]] : [deviceAlive:data["deviceAlive"]] - remoteSensors[rsDni] << [thermostatId: dni] - remoteSensors[rsDni].polled = true - remoteSensors[rsDni].pollAttempts = 0 - } - } - } - } - state.thermostats = thermostatList - state.remoteSensors2 = remoteSensors -} - -def sendActivityFeeds(notificationMessage) { - def devices = getChildDevices() - devices.each { child -> - child.generateActivityFeedsEvent(notificationMessage) //parse received message from parent - } -} - -def convertFtoC (tempF) { - return String.format("%.1f", (Math.round(((tempF - 32)*(5/9)) * 2))/2) -} diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties deleted file mode 100644 index 555db6a9e05..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=قم بتوصيل ثرموستات Ecobee بـ SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=أنت متصل. -'''Click to enter Ecobee Credentials'''=النقر لإدخال بيانات اعتماد Ecobee -'''Login'''=تسجيل الدخول -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=انقر أدناه لتسجيل الدخول إلى خدمة ecobee والمصادقة على الوصول إلى SmartThings. تأكد من التمرير للأسفل على الصفحة ٢ والضغط على زر ”السماح“. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=تحديد أجهزة الثرموستات -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=انقر أدناه لرؤية قائمة أجهزة ثرموستات ecobee المتوفرة في حساب ecobee، وحدد الأجهزة التي ترغب في توصيلها بـ SmartThings. -'''Tap to choose'''=النقر لاختيار -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=انقر أدناه لرؤية قائمة مستشعرات ecobee المتوفرة في حساب ecobee، وحدد الأجهزة التي ترغب في توصيلها بـ SmartThings. -'''Tap to choose'''=النقر لاختيار -'''Select Ecobee Sensors ({{numFound}} found)'''=تحديد مستشعرات Ecobee‏ ‎({{numFound}} found) -'''Your ecobee Account is now connected to SmartThings!'''=حساب ecobee متصل الآن بـ SmartThings! -'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد. -'''The connection could not be established!'''=يتعذر إنشاء الاتصال! -'''Click 'Done' to return to the menu.'''=انقر فوق ”تم“ للعودة إلى القائمة. -'''is connected to SmartThings'''={{deviceName}} متصل بـ SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=تم قطع اتصال {{deviceName}} بـ SmartThings، لأن بيانات اعتماد الوصول قد تغيرت أو فُقدت. يُرجى الانتقال إلى التطبيق الذكي Ecobee (Connect)‎ وإعادة إدخال بيانات اعتماد تسجيل الدخول إلى حسابك. -'''Your Ecobee thermostat '''=ثرموستات Ecobee -'''Select your ecobee devices'''=تحديد أجهزة ecobee لديك -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=انقر أدناه لإضافة أجهزة الثرموستات المتوفرة في حساب ecobee لديك أو إزالتها. سيتم توصيل أجهزة الثرموستات المحددة بـ SmartThings. -'''Log In'''=تسجيل الدخول -'''Tap Next to continue to set up your ecobee thermostats.'''=انقر فوق ”التالي“ لمتابعة إعداد أجهزة الثرموستات ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=انقر أدناه لإضافة المستشعرات عن بُعد المتوفرة في حساب ecobee لديك أو إزالتها منه. سيتم توصيل المستشعرات المحددة بـ SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=انقر أدناه لإضافة مفاتيح التبديل المتوفرة في حساب ecobee لديك أو إزالتها. سيتم توصيل مفاتيح التبديل المحددة بـ SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties b/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties deleted file mode 100644 index 19f0cf6bdd4..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Свържете термостата Ecobee към SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Свързани сте. -'''Click to enter Ecobee Credentials'''=Щракнете, за да въведете идентификационни данни за Ecobee -'''Login'''=Вход -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Докоснете по-долу, за да влезете в услугата ecobee и да упълномощите достъпа на SmartThings. Превъртете надолу в страница 2 и натиснете бутона Allow (Позволяване). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Избор на термостати -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Докоснете по-долу, за да видите списък с термостатите ecobee във вашия ecobee акаунт, и изберете онези, които искате да свържете към SmartThings. -'''Tap to choose'''=Докосване за избор -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Докоснете по-долу, за да видите списък със сензорите ecobee във вашия ecobee акаунт, и изберете онези, които искате да свържете към SmartThings. -'''Tap to choose'''=Докосване за избор -'''Select Ecobee Sensors ({{numFound}} found)'''=Избор на сензори Ecobee ({{numFound}} с намерени) -'''Your ecobee Account is now connected to SmartThings!'''=Вашият ecobee акаунт вече е свързан към SmartThings! -'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката. -'''The connection could not be established!'''=Връзката не може да се осъществи! -'''Click 'Done' to return to the menu.'''=Щракнете върху Done (Готово), за да се върнете към менюто. -'''is connected to SmartThings'''=е свързан към SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=е прекъснат от SmartThings, тъй като идентификационните данни за достъп са променени или изгубени. Отидете в Ecobee (Connect) SmartApp и въведете отново идентификационните си данни за влизане в акаунта. -'''Your Ecobee thermostat '''=Вашият термостат Ecobee -'''Select your ecobee devices'''=Избор на ecobee устройства -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Докоснете по-долу, за да добавите или премахнете термостатите, налични във вашия ecobee акаунт. Избраните термостати ще се свържат със SmartThings. -'''Log In'''=Влизане -'''Tap Next to continue to set up your ecobee thermostats.'''=Докоснете Next (Напред), за да продължите с настройването на термостатите ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Докоснете по-долу, за да премахнете отдалечените сензори, налични във вашия ecobee акаунт. Избраните сензори ще се свържат със SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Докоснете по-долу, за да добавите или премахнете превключвателите, налични във вашия ecobee акаунт. Избраните превключватели ще се свържат със SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties deleted file mode 100644 index e6364de3c01..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conecte su termostato Ecobee a SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Está conectado. -'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee -'''Login'''=Inicio de sesión -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y autorizar el acceso a SmartThings. Asegúrese de desplazarse hacia abajo a la página 2 y pulsar el botón “Allow” (Permitir). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Seleccionar los termostatos -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores de Ecobee ({{numFound}} encontrados) -'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración. -'''The connection could not be established!'''=¡No se ha podido establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. -'''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. -'''Your Ecobee thermostat '''=Su termostato Ecobee -'''Select your ecobee devices'''=Selecciona os teus dispositivos de ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toca a continuación para engadir ou eliminar termóstatos dispoñibles na túa conta de ecobee. Os termóstatos seleccionados conectaranse a SmartThings. -'''Log In'''=Iniciar sesión -'''Tap Next to continue to set up your ecobee thermostats.'''=Toca Seguinte para continuar coa configuración dos teus termóstatos de ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Toca a continuación para engadir ou eliminar sensores remotos dispoñibles na túa conta de ecobee. Os sensores seleccionados conectaranse a SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Toca a continuación para engadir ou eliminar interruptores dispoñibles na túa conta de ecobee. Os interruptores seleccionados conectaranse a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties b/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties deleted file mode 100644 index da3e40a8f84..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Připojte termostat Ecobee k systému SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Jste připojeni. -'''Click to enter Ecobee Credentials'''=Klepněte a zadejte přihlašovací údaje Ecobee -'''Login'''=Přihlásit -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Klepnutím na následující tlačítko se přihlásíte ke službě ecobee a autorizujete přístup pro systém SmartThings. Posuňte se dolů na stránku 2 a stiskněte tlačítko „Allow“ (Povolit). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Vyberte termostaty -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Klepnutím na následující tlačítko zobrazte seznam termostatů ecobee dostupných na vašem účtu ecobee a vyberte ty, které chcete připojit k systému SmartThings. -'''Tap to choose'''=Klepnutím zvolte -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Klepnutím na následující tlačítko zobrazte seznam senzorů ecobee dostupných na vašem účtu ecobee a vyberte ty, které chcete připojit k systému SmartThings. -'''Tap to choose'''=Klepnutím zvolte -'''Select Ecobee Sensors ({{numFound}} found)'''=Vyberte senzory Ecobee (nalezeno {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Účet ecobee je nyní připojen k systému SmartThings! -'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo). -'''The connection could not be established!'''=Připojení nelze navázat! -'''Click 'Done' to return to the menu.'''=Klepnutím na tlačítko „Done“ (Hotovo) se vrátíte do menu. -'''is connected to SmartThings'''=je připojen ke SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=byl odpojen od systému SmartThings, protože přístupové přihlašovací údaje byly změněny nebo ztraceny. Přejděte do Ecobee (Connect) SmartApp a znovu zadejte své přihlašovací údaje k účtu. -'''Your Ecobee thermostat '''=Termostat Ecobee -'''Select your ecobee devices'''=Vyberte zařízení ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Klepnutím na následující tlačítko přidáte nebo odeberete termostaty dostupné na účtu ecobee. Vybrané termostaty budou připojeny k aplikaci SmartThings. -'''Log In'''=Přihlásit -'''Tap Next to continue to set up your ecobee thermostats.'''=Klepněte na tlačítko Next (Další) a pokračujte nastavením termostatů ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Klepnutím na následující tlačítko přidáte nebo odeberete vzdálené termostaty dostupné na účtu ecobee. Vybrané senzory budou připojeny k aplikaci SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Klepnutím na následující tlačítko přidáte nebo odeberete spínače dostupné na účtu ecobee. Vybrané spínače budou připojeny k aplikaci SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties b/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties deleted file mode 100644 index ab837fde6b3..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Forbind din Ecobee-termostat med SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Du er nu forbundet. -'''Click to enter Ecobee Credentials'''=Klik for at indtaste Ecobee-legitimationsoplysninger -'''Login'''=Log ind -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tryk nedenfor for at logge ind på din ecobee-tjeneste og godkende SmartThings-adgang. Sørg for at rulle ned på side 2 og trykke på knappen “Allow” (Tillad). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Vælg dine termostater -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryk herunder for at se listen over ecobee-termostater, der er tilgængelige på din ecobee-konto, og vælg dem, du vil forbinde med SmartThings. -'''Tap to choose'''=Tryk for at vælge -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryk herunder for at se listen over ecobee-sensorer, der er tilgængelige på din ecobee-konto, og vælg dem, du vil forbinde med SmartThings. -'''Tap to choose'''=Tryk for at vælge -'''Select Ecobee Sensors ({{numFound}} found)'''=Vælg Ecobee-sensorer ({{numFound}} fundet) -'''Your ecobee Account is now connected to SmartThings!'''=Din ecobee-konto er nu forbundet med SmartThings! -'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen. -'''The connection could not be established!'''=Der kunne ikke oprettes forbindelse! -'''Click 'Done' to return to the menu.'''=Klik på “Done” (Udført) for at vende tilbage til menuen. -'''is connected to SmartThings'''=er forbundet med SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=er koblet fra SmartThings, fordi adgangslegitimationsoplysningerne er ændret eller gået tabt. Gå til Ecobee (Connect (Forbind)) SmartApp, og indtast dine kontologinoplysninger igen. -'''Your Ecobee thermostat '''=Din Ecobee-termostat -'''Select your ecobee devices'''=Vælg dine ecobee-enheder -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tryk herunder for at tilføje eller fjerne termostater, der er tilgængelige på din ecobee-konto. De valgte termostater bliver forbundet til SmartThings. -'''Log In'''=Log ind -'''Tap Next to continue to set up your ecobee thermostats.'''=Tryk på Næste for at fortsætte med at konfigurere dine ecobee-termostater. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Tryk herunder for at tilføje eller fjerne eksterne sensorer, der er tilgængelige på din ecobee-konto. De valgte sensorer bliver forbundet til SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Tryk herunder for at tilføje eller fjerne kontakter, der er tilgængelige på din ecobee-konto. De valgte kontakter bliver forbundet til SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties deleted file mode 100644 index a5909eef5b5..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Verbinden Sie Ihr Ecobee-Thermostat mit SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Sie sind verbunden. -'''Click to enter Ecobee Credentials'''=Hier klicken, um die ecobee-Zugangsdaten einzugeben. -'''Login'''=Anmeldung -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tippen Sie unten, um sich am ecobee-Dienst anzumelden und den SmartThings-Zugriff zu autorisieren. Stellen Sie sicher, dass Sie bis auf Seite 2 herunterscrollen und auf die Schaltfläche „Allow“ (Zulassen) tippen. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Ihre Thermostate auswählen -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tippen Sie unten, um eine Liste der ecobee-Thermostate anzuzeigen, die in Ihrem ecobee-Konto verfügbar sind, und wählen Sie diejenigen aus, mit denen Sie eine Verbindung zu SmartThings herstellen möchten. -'''Tap to choose'''=Zur Auswahl tippen -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tippen Sie unten, um eine Liste der ecobee-Sensoren anzuzeigen, die in Ihrem ecobee-Konto verfügbar sind, und wählen Sie diejenigen aus, mit denen Sie eine Verbindung zu SmartThings herstellen möchten. -'''Tap to choose'''=Zur Auswahl tippen -'''Select Ecobee Sensors ({{numFound}} found)'''=ecobee-Sensoren auswählen ({{numFound}} gefunden) -'''Your ecobee Account is now connected to SmartThings!'''=Ihr ecobee-Konto ist jetzt mit SmartThings verbunden! -'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen. -'''The connection could not be established!'''=Es konnte keine Verbindung hergestellt werden! -'''Click 'Done' to return to the menu.'''=Klicken Sie auf „Done“ (OK), um zum Menü zurückzukehren. -'''is connected to SmartThings'''=ist mit SmartThings verbunden -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ist von SmartThings getrennt, da die Zugangsdaten für den Zugriff geändert wurden oder verloren gingen. Wechseln Sie zur ecobee (Connect)-SmartApp und geben Sie Ihre Kontozugangsdaten erneut ein. -'''Your Ecobee thermostat '''=Ihr ecobee-Thermostat -'''Select your ecobee devices'''=Wählen Sie Ihre ecobee-Geräte aus -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tippen Sie unten, um Thermostate hinzuzufügen oder zu entfernen, die in Ihrem ecobee-Konto verfügbar sind. Ausgewählte Thermostate werden mit SmartThings verbunden. -'''Log In'''=Anmelden -'''Tap Next to continue to set up your ecobee thermostats.'''=Tippen Sie auf „Next“ (Weiter), um die Einrichtung Ihrer ecobee-Thermostate fortzusetzen. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Tippen Sie unten, um Remote-Sensoren hinzuzufügen oder zu entfernen, die in Ihrem ecobee-Konto verfügbar sind. Ausgewählte Sensoren werden mit SmartThings verbunden. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Tippen Sie unten, um Schalter hinzuzufügen oder zu entfernen, die in Ihrem ecobee-Konto verfügbar sind. Ausgewählte Schalter werden mit SmartThings verbunden. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties deleted file mode 100644 index abe17d298d5..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Συνδέστε το θερμοστάτη Ecobee στο SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Έχετε συνδεθεί. -'''Click to enter Ecobee Credentials'''=Κάντε κλικ για να καταχωρήσετε διαπιστευτήρια Ecobee -'''Login'''=Σύνδεση -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Πατήστε παρακάτω για να συνδεθείτε στην υπηρεσία ecobee και να δώσετε εξουσιοδότηση πρόσβασης για το SmartThings. Κάνετε κύλιση προς τα κάτω στη σελίδα 2 και πατήστε το κουμπί "Επιτρ.". -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Επιλέξτε τους θερμοστάτες σας -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Πατήστε παρακάτω για να δείτε τη λίστα με τους θερμοστάτες ecobee που είναι διαθέσιμοι στο λογαριασμό ecobee και να επιλέξετε αυτούς που θέλετε να συνδέσετε στο SmartThings. -'''Tap to choose'''=Πατήστε για να επιλέξετε -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Πατήστε παρακάτω για να δείτε τη λίστα με τους αισθητήρες ecobee που είναι διαθέσιμοι στο λογαριασμό ecobee και να επιλέξετε αυτούς που θέλετε να συνδέσετε στο SmartThings. -'''Tap to choose'''=Πατήστε για να επιλέξετε -'''Select Ecobee Sensors ({{numFound}} found)'''=Επιλογή αισθητήρων Ecobee (βρέθηκαν {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Ο λογαριασμός σας στο ecobee έχει τώρα συνδεθεί στο SmartThings! -'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση. -'''The connection could not be established!'''=Δεν ήταν δυνατή η δημιουργία σύνδεσης! -'''Click 'Done' to return to the menu.'''=Κάντε κλικ στο "Done" (Τέλος) για να επιστρέψετε στο μενού. -'''is connected to SmartThings'''=συνδέθηκε στο SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=αποσυνδέθηκε από το SmartThings, επειδή τα διαπιστευτήρια πρόσβασης άλλαξαν ή έχουν χαθεί. Μεταβείτε στην εφαρμογή Ecobee (Connect) SmartApp και καταχωρήστε ξανά τα διαπιστευτήρια σύνδεσης για το λογαριασμό σας. -'''Your Ecobee thermostat '''=Θερμοστάτης Ecobee -'''Select your ecobee devices'''=Επιλέξτε τις συσκευές σας ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Πατήστε παρακάτω για να προσθέσετε ή να καταργήσετε τους θερμοστάτες που είναι διαθέσιμοι στο λογαριασμό σας ecobee. Οι επιλεγμένοι θερμοστάτες θα συνδεθούν στο SmartThings. -'''Log In'''=Σύνδεση -'''Tap Next to continue to set up your ecobee thermostats.'''=Πατήστε «Επόμενο» για να συνεχίσετε τη ρύθμιση των θερμοστατών ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Πατήστε παρακάτω για να προσθέσετε ή να καταργήσετε τους απομακρυσμένους αισθητήρες που είναι διαθέσιμοι στο λογαριασμό σας ecobee. Οι επιλεγμένοι αισθητήρες θα συνδεθούν στο SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Πατήστε παρακάτω για να προσθέσετε ή να καταργήσετε τους διακόπτες που είναι διαθέσιμοι στο λογαριασμό σας ecobee. Οι επιλεγμένοι διακόπτες θα συνδεθούν στο SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties b/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties deleted file mode 100644 index 2e434f86057..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties +++ /dev/null @@ -1,20 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Connect your Ecobee thermostat to SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=You are connected. -'''Click to enter Ecobee Credentials'''=Click to enter Ecobee Credentials -'''Login'''=Login -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tap below to log in to the ecobee service and authorise SmartThings access. Be sure to scroll down on page 2 and press the ’Allow’ button. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Select Your Thermostats -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings. -'''Tap to choose'''=Tap to choose -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings. -'''Tap to choose'''=Tap to choose -'''Select Ecobee Sensors ({{numFound}} found)'''=Select Ecobee Sensors ({{numFound}} found) -'''Your ecobee Account is now connected to SmartThings!'''=Your ecobee Account is now connected to SmartThings! -'''Click 'Done' to finish setup.'''=Click ’Done’ to finish setup. -'''The connection could not be established!'''=The connection could not be established! -'''Click 'Done' to return to the menu.'''=Click ’Done’ to return to the menu. -'''is connected to SmartThings'''=is connected to SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials. -'''Your Ecobee thermostat '''=Your Ecobee thermostat diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties deleted file mode 100644 index 387a54218c0..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conecte su termostato Ecobee a SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Está conectado. -'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee -'''Login'''=Inicio de sesión -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y autorizar el acceso a SmartThings. Asegúrese de desplazarse hacia abajo a la página 2 y pulsar el botón “Allow” (Permitir). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Seleccionar los termostatos -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores de Ecobee ({{numFound}} encontrados) -'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración. -'''The connection could not be established!'''=¡No se ha podido establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. -'''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. -'''Your Ecobee thermostat '''=Su termostato Ecobee -'''Select your ecobee devices'''=Selecciona tus dispositivos ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pulsa a continuación para añadir o eliminar los termostatos disponibles en tu cuenta de ecobee. Los termostatos seleccionados se conectarán a SmartThings. -'''Log In'''=Iniciar sesión -'''Tap Next to continue to set up your ecobee thermostats.'''=Pulsa Siguiente para continuar con la configuración de tus termostatos ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Pulsa a continuación para añadir o eliminar los sensores remotos disponibles en tu cuenta de ecobee. Los sensores seleccionados se conectarán a SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Pulsa a continuación para añadir o eliminar los interruptores disponibles en tu cuenta de ecobee. Los interruptores seleccionados se conectarán a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties deleted file mode 100644 index 14b3027e7f1..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conecte su termostato Ecobee a SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Está conectado. -'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee -'''Login'''=Inicio de sesión -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y autorizar el acceso a SmartThings. Asegúrese de desplazarse hacia abajo a la página 2 y pulsar el botón “Allow” (Permitir). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Seleccionar los termostatos -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings. -'''Tap to choose'''=Pulsar para seleccionar -'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores de Ecobee ({{numFound}} encontrados) -'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración. -'''The connection could not be established!'''=¡No se ha podido establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. -'''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. -'''Your Ecobee thermostat '''=Su termostato Ecobee -'''Select your ecobee devices'''=Seleccione sus dispositivos ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pulse a continuación para añadir o eliminar los termostatos disponibles en su cuenta de ecobee. Los dispositivos seleccionados se conectarán a SmartThings. -'''Log In'''=Iniciar sesión -'''Tap Next to continue to set up your ecobee thermostats.'''=Pulse Siguiente para continuar con la configuración de los termostatos ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Pulse a continuación para añadir o eliminar los sensores remotos disponibles en su cuenta de ecobee. Los sensores seleccionados se conectarán a SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Pulse a continuación para añadir o eliminar los interruptores disponibles en su cuenta de ecobee. Los interruptores seleccionados se conectarán a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties deleted file mode 100644 index bf026c87491..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties +++ /dev/null @@ -1,20 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conecte el termostato Ecobee a SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Está conectado. -'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee -'''Login'''=Inicio de sesión -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y otorgar acceso a SmartThings. Asegúrese de desplazarse hacia abajo en la página 2 y de presionar el botón 'Allow' ('Permitir'). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Seleccionar Your Thermostats (Sus termostatos) -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que desea conectar a SmartThings. -'''Tap to choose'''=Pulsar para elegir -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que desea conectar a SmartThings. -'''Tap to choose'''=Pulsar para elegir -'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores Ecobee (hay {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ahora está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración. -'''The connection could not be established!'''=¡No fue posible establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en 'Done' ('Listo') para volver al menú. -'''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=no está conectado a SmartThings debido a que la credencial de acceso se cambió o se perdió. Vaya a la SmartApp de Ecobee (Connect) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. -'''Your Ecobee thermostat '''=Su termostato Ecobee diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties deleted file mode 100644 index 6a70d1e52ac..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Ühendage oma termostaat Ecobee teenusega SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Ühendus on loodud. -'''Click to enter Ecobee Credentials'''=Klõpsake, et sisestada teenuse Ecobee volitused -'''Login'''=Sisselogimine -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toksake all, et logida sisse teenusesse ecobee ja autoriseerida teenuse SmartThings juurdepääs. Kerige kindlasti alla lehele 2 ja vajutage nuppu Luba. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Valige oma termostaadid -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toksake all, et näha oma ecobee kontole registreeritud ecobee termostaate ja valige need, mida soovite ühendada teenusega SmartThings. -'''Tap to choose'''=Toksake, et valida -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toksake all, et näha oma ecobee kontole registreeritud ecobee andureid ja valige need, mida soovite ühendada teenusega SmartThings. -'''Tap to choose'''=Toksake, et valida -'''Select Ecobee Sensors ({{numFound}} found)'''=Valige Ecobee andurid (leiti {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Teie ecobee konto on nüüd ühendatud teenusega SmartThings! -'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia. -'''The connection could not be established!'''=Ühenduse loomine nurjus! -'''Click 'Done' to return to the menu.'''=Klõpsake valikut Valmis, et naasta menüüsse. -'''is connected to SmartThings'''=on ühendatud teenusega SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=on teenusest SmartThings lahti ühendatud, kuna juurdepääsu volitus muutus või kadus. Avage rakendus Ecobee (Connect) SmartApp ja sisestage uuesti oma konto sisselogimisandmed. -'''Your Ecobee thermostat '''=Teie Ecobee termostaat -'''Select your ecobee devices'''=Valige oma ecobee seadmed -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toksake allpool, et lisada või eemaldada ecobee konto all olevaid termostaate. Valitud termostaadid ühendatakse teenusega SmartThings. -'''Log In'''=Sisselogimine -'''Tap Next to continue to set up your ecobee thermostats.'''=Toksake käsku Edasi, et jätkata oma ecobee termostaatide seadistamist. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Toksake allpool, et lisada või eemaldada ecobee konto all olevaid kaugandureid. Valitud andurid ühendatakse teenusega SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Toksake allpool, et lisada või eemaldada ecobee konto all olevaid lüliteid. Valitud lülitid ühendatakse teenusega SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties deleted file mode 100644 index cd9eb4b092c..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Yhdistä Ecobee-termostaattisi SmartThingsiin. -'''ecobee'''=ecobee -'''You are connected.'''=Yhteys muodostettu. -'''Click to enter Ecobee Credentials'''=Napsauta ja anna Ecobee-tunnistetiedot -'''Login'''=Kirjautuminen -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Kirjaudu ecobee-palveluun ja myönnä SmartThingsille käyttöoikeudet napauttamalla alla. Vieritä alas sivulle 2 ja paina Allow (Salli) -painiketta. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Valitse termostaatit -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Napauttamalla alla voit tuoda ecobee-tililläsi käytettävissä olevien ecobee-termostaattien luettelon näyttöön ja valita SmartThingsiin yhdistettävät laitteet. -'''Tap to choose'''=Valitse napauttamalla -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Napauttamalla alla voit tuoda ecobee-tililläsi käytettävissä olevien ecobee-tunnistimien luettelon näyttöön ja valita SmartThingsiin yhdistettävät laitteet. -'''Tap to choose'''=Valitse napauttamalla -'''Select Ecobee Sensors ({{numFound}} found)'''=Valitse Ecobee-tunnistimet ({{numFound}} löydetty) -'''Your ecobee Account is now connected to SmartThings!'''=ecobee-tilisi on nyt yhdistetty SmartThingsiin! -'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis). -'''The connection could not be established!'''=Yhteyden muodostaminen epäonnistui! -'''Click 'Done' to return to the menu.'''=Palaa valikkoon napsauttamalla Done (Valmis). -'''is connected to SmartThings'''=on yhdistetty SmartThingsiin -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ei enää ole yhteydessä SmartThingsiin, sillä käyttötunnukset ovat muuttuneet tai kadonneet. Siirry Ecobee (Connect) SmartAppiin ja anna tilisi kirjautumistiedot uudelleen. -'''Your Ecobee thermostat '''=Ecobee-termostaattisi -'''Select your ecobee devices'''=Valitse ecobee-laitteet -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Napauttamalla alla voit lisätä tai poistaa ecobee-tililläsi käytettävissä olevat termostaatit. Valitut termostaatit muodostavat yhteyden SmartThingsiin. -'''Log In'''=Kirjaudu sisään -'''Tap Next to continue to set up your ecobee thermostats.'''=Jatka ecobee-termostaattien määritystä napauttamalla Next (Seuraava). -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Napauttamalla alla voit lisätä tai poistaa ecobee-tililläsi käytettävissä olevat etätunnistimet. Valitut tunnistimet muodostavat yhteyden SmartThingsiin. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Napauttamalla alla voit lisätä tai poistaa ecobee-tililläsi käytettävissä olevat kytkimet. Valitut kytkimet muodostavat yhteyden SmartThingsiin. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties deleted file mode 100644 index c11220a9114..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Connectez votre thermostat Ecobee à SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Vous êtes connecté. -'''Click to enter Ecobee Credentials'''=Cliquez pour saisir les informations d'identification Ecobee -'''Login'''=Connexion -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Appuyez ci-dessous pour vous connecter au service ecobee et autoriser l'accès pour SmartThings. Faites défiler l'écran jusqu'en bas de la page 2 et appuyez sur le bouton Allow (Autoriser). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Sélection de vos thermostats -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des thermostats ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings. -'''Tap to choose'''=Appuyez pour sélectionner -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des capteurs ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings. -'''Tap to choose'''=Appuyez pour sélectionner -'''Select Ecobee Sensors ({{numFound}} found)'''=Sélection des capteurs Ecobee ({{numFound}} trouvé(s)) -'''Your ecobee Account is now connected to SmartThings!'''=Votre compte ecobee est maintenant connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''The connection could not be established!'''=La connexion n'a pas pu être établie ! -'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. -'''is connected to SmartThings'''=est connecté à SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. -'''Your Ecobee thermostat '''=Votre thermostat Ecobee -'''Select your ecobee devices'''=Sélectionnez vos appareils ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Touchez ci-dessous pour ajouter ou retirer des thermostats disponibles dans votre compte ecobee. Les thermostats sélectionnés se connecteront à SmartThings. -'''Log In'''=Connexion -'''Tap Next to continue to set up your ecobee thermostats.'''=Appuyez sur Suivant pour poursuivre la configuration de vos thermostats ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Touchez ci-dessous pour ajouter ou retirer des capteurs de télédétection disponibles dans votre compte ecobee. Les thermostats sélectionnés se connecteront à SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Touchez ci-dessous pour ajouter ou retirer des interrupteurs disponibles dans votre compte ecobee. Les interrupteurs sélectionnés se connecteront à SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties deleted file mode 100644 index 2b065d62c9e..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Connectez votre thermostat Ecobee à SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Vous êtes connecté. -'''Click to enter Ecobee Credentials'''=Cliquez pour saisir les informations d'identification Ecobee -'''Login'''=Connexion -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Appuyez ci-dessous pour vous connecter au service ecobee et autoriser l'accès pour SmartThings. Faites défiler l'écran jusqu'en bas de la page 2 et appuyez sur le bouton Allow (Autoriser). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Sélection de vos thermostats -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des thermostats ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings. -'''Tap to choose'''=Appuyez pour sélectionner -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des capteurs ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings. -'''Tap to choose'''=Appuyez pour sélectionner -'''Select Ecobee Sensors ({{numFound}} found)'''=Sélection des capteurs Ecobee ({{numFound}} trouvé(s)) -'''Your ecobee Account is now connected to SmartThings!'''=Votre compte ecobee est maintenant connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''The connection could not be established!'''=La connexion n'a pas pu être établie ! -'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. -'''is connected to SmartThings'''=est connecté à SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. -'''Your Ecobee thermostat '''=Votre thermostat Ecobee -'''Select your ecobee devices'''=Sélectionnez vos appareils ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Appuyez ci-dessous pour ajouter ou supprimer les thermostats disponibles dans votre compte ecobee. Les thermostats sélectionnés se connecteront à SmartThings. -'''Log In'''=Connexion -'''Tap Next to continue to set up your ecobee thermostats.'''=Appuyez sur Suivant pour poursuivre la configuration de vos thermostats ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Appuyez ci-dessous pour ajouter ou supprimer les télédétecteurs disponibles dans votre compte ecobee. Les détecteurs sélectionnés se connecteront à SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Appuyez ci-dessous pour ajouter ou supprimer les interrupteurs disponibles dans votre compte ecobee. Les interrupteurs sélectionnés se connecteront à SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties deleted file mode 100644 index a65bd0e6ea8..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Povežite termostat Ecobee s uslugom SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Povezani ste. -'''Click to enter Ecobee Credentials'''=Kliknite za unos podataka za prijavu za Ecobee -'''Login'''=Prijava -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Dodirnite u nastavku da biste se prijavili u uslugu ecobee i odobrili pristup za SmartThings. Na 2. se stranici pomaknite prema dolje i pritisnite gumb „Allow” (Dopusti). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Odaberite termostate -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dodirnite u nastavku da biste vidjeli popis termostata ecobee dostupnih na vašem računu za ecobee i odaberite one koje želite povezati s uslugom SmartThings. -'''Tap to choose'''=Dodirnite za odabir -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dodirnite u nastavku da biste vidjeli popis senzora ecobee dostupnih na vašem računu za ecobee i odaberite one koje želite povezati s uslugom SmartThings. -'''Tap to choose'''=Dodirnite za odabir -'''Select Ecobee Sensors ({{numFound}} found)'''=Odaberite senzore Ecobee (pronađeno: {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Račun za ecobee sada je povezan s uslugom SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje. -'''The connection could not be established!'''=Veza se nije uspostavila! -'''Click 'Done' to return to the menu.'''=Kliknite „Done” (Gotovo) za vraćanje na izbornik. -'''is connected to SmartThings'''=povezan je s uslugom SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=nije povezan s uslugom SmartThings jer su se pristupni podaci promijenili ili izgubili. Idite na Ecobee (Connect) SmartApp i ponovno unesite podatke za prijavu na račun. -'''Your Ecobee thermostat '''=Termostat Ecobee -'''Select your ecobee devices'''=Odaberite uređaje ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Dodirnite u nastavku da biste dodali ili uklonili termostate dostupne na računu za ecobee. Odabrani termostati povezat će se s uslugom SmartThings. -'''Log In'''=Prijava -'''Tap Next to continue to set up your ecobee thermostats.'''=Dodirnite Next (Dalje) da biste nastavili s postavljanjem termostata ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Dodirnite u nastavku da biste dodali ili uklonili daljinske senzore dostupne na računu za ecobee. Odabrani senzori povezat će se s uslugom SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Dodirnite u nastavku da biste dodali ili uklonili prekidače dostupne na računu za ecobee. Odabrani prekidači povezat će se s uslugom SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties b/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties deleted file mode 100644 index 4527593558c..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee termosztátot csatlakoztathat a SmartThings rendszerhez. -'''ecobee'''=ecobee -'''You are connected.'''=Kapcsolódott. -'''Click to enter Ecobee Credentials'''=Kattintson az Ecobee-hitelesítőadatok megadásához -'''Login'''=Bejelentkezés -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Az alábbi hivatkozás megérintésével bejelentkezhet az ecobee szolgáltatásba, és engedélyezheti a SmartThings-hozzáférést. Görgessen le a 2. oldalon, és nyomja meg az „Allow” (Engedélyezés) gombot. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=A termosztátok kiválasztása -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Az alábbi hivatkozás megérintésével megjelenítheti az ecobee-fiókjában rendelkezésre álló ecobee termosztátok listáját, és kiválaszthatja azokat, amelyeket csatlakoztatni szeretne a SmartThings rendszerhez. -'''Tap to choose'''=Érintse meg a kiválasztáshoz -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Az alábbi hivatkozás megérintésével megjelenítheti az ecobee-fiókjában rendelkezésre álló ecobee érzékelők listáját, és kiválaszthatja azokat, amelyeket csatlakoztatni szeretne a SmartThings rendszerhez. -'''Tap to choose'''=Érintse meg a kiválasztáshoz -'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee érzékelők kiválasztása ({{numFound}} találat) -'''Your ecobee Account is now connected to SmartThings!'''=Csatlakoztatta ecobee-fiókját a SmartThings rendszerhez! -'''Click 'Done' to finish setup.'''=A telepítés befejezéséhez kattintson a „Done” (Kész) gombra. -'''The connection could not be established!'''=Nem sikerült kapcsolatot létesíteni! -'''Click 'Done' to return to the menu.'''=A menühöz való visszatéréshez kattintson a „Done” (Kész) gombra. -'''is connected to SmartThings'''=kapcsolódott a SmartThings rendszerhez -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=le lett választva a SmartThings rendszerről, mert megváltoztak vagy elvesztek a hozzáférési hitelesítő adatok. Adja meg újra a fiókja bejelentkezési hitelesítő adatait a Ecobee (Connect) SmartApp segítségével. -'''Your Ecobee thermostat '''=Az Ön Ecobee termosztátja -'''Select your ecobee devices'''=Az ecobee eszközök kiválasztása -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Az alábbi lehetőség megérintésével veheti fel, illetve távolíthatja el az ecobee-fiókjában rendelkezésre álló termosztátokat. A kiválasztott eszközök csatlakozni fognak a SmartThings szolgáltatáshoz. -'''Log In'''=Bejelentkezés -'''Tap Next to continue to set up your ecobee thermostats.'''=Érintse meg a Next (Tovább) gombot az ecobee termosztátok beállításának folytatásához. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Az alábbi lehetőség megérintésével veheti fel, illetve távolíthatja el az ecobee-fiókjában rendelkezésre álló távoli érzékelőket. A kiválasztott érzékelők csatlakozni fognak a SmartThings szolgáltatáshoz. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Az alábbi lehetőség megérintésével veheti fel, illetve távolíthatja el az ecobee-fiókjában rendelkezésre álló kapcsolókat. A kiválasztott kapcsolók csatlakozni fognak a SmartThings szolgáltatáshoz. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties b/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties deleted file mode 100644 index 1b7f518acd8..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Connettete il termostato Ecobee a SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Connessione effettuata. -'''Click to enter Ecobee Credentials'''=Fate clic per inserire le credenziali Ecobee -'''Login'''=Accesso -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toccate di seguito per accedere al servizio ecobee e autorizzare l'accesso a SmartThings. Scorrete fino in fondo alla pagina 2 e premete il pulsante “Allow” (Consenti). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Selezionate i termostati -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toccate di seguito per visualizzare l'elenco dei termostati ecobee disponibili nell'account ecobee e selezionate quelli che volete connettere a SmartThings. -'''Tap to choose'''=Toccate per scegliere -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toccate di seguito per visualizzare l'elenco dei sensori ecobee disponibili nell'account ecobee e selezionate quelli che volete connettere a SmartThings. -'''Tap to choose'''=Toccate per scegliere -'''Select Ecobee Sensors ({{numFound}} found)'''=Selezionate i sensori Ecobee ({{numFound}} trovati) -'''Your ecobee Account is now connected to SmartThings!'''=L'account ecobee è ora connesso a SmartThings. -'''Click 'Done' to finish setup.'''=Fate clic su “Done” (Fatto) per terminare la configurazione. -'''The connection could not be established!'''=Non è stato possibile stabilire la connessione. -'''Click 'Done' to return to the menu.'''=Fate clic su “Done” (Fatto) per tornare al menu. -'''is connected to SmartThings'''=connesso a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=disconnesso da SmartThings. Le credenziali di accesso sono state modificate o sono andate perse. Andate alla SmartApp di Ecobee (Connect) e inserite nuovamente le credenziali di accesso all'account. -'''Your Ecobee thermostat '''=Il termostato Ecobee -'''Select your ecobee devices'''=Selezionate i dispositivi ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toccate di seguito per aggiungere o rimuovere i termostati disponibili nell’account ecobee. I termostati selezionati si connetteranno a SmartThings. -'''Log In'''=Accesso -'''Tap Next to continue to set up your ecobee thermostats.'''=Toccate Next (Avanti) per proseguire con la configurazione dei termostati ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Toccate di seguito per aggiungere o rimuovere i sensori remoti disponibili nell’account ecobee. I sensori selezionati si connetteranno a SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Toccate di seguito per aggiungere o rimuovere gli interruttori disponibili nell’account ecobee. Gli interruttori selezionati si connetteranno a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties deleted file mode 100644 index 0dd465aff0f..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee 온도조절기를 SmartThings에 연결하세요. -'''ecobee'''=Ecobee -'''You are connected.'''=연결되었습니다. -'''Click to enter Ecobee Credentials'''=Ecobee 로그인 정보를 입력하려면 클릭하세요 -'''Login'''=로그인 -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ecobee 서비스에 로그인하여 SmartThings를 사용할 수 있도록 인증하려면 아래를 누르세요. 2페이지에서 아래로 스크롤한 후 [허용]을 누르세요. -'''ecobee'''=Ecobee -'''Select Your Thermostats'''=온도조절기 선택 -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee 계정에 등록된 Ecobee 온도조절기 목록을 확인하고 SmartThings에 연결할 기기를 선택하려면 아래를 누르세요. -'''Tap to choose'''=눌러서 선택 -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee 계정에 등록된 Ecobee 센서 목록을 확인하고 SmartThings에 연결할 기기를 선택하려면 아래를 누르세요. -'''Tap to choose'''=눌러서 선택 -'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee 센서 선택 ({{numFound}}개 찾음) -'''Your ecobee Account is now connected to SmartThings!'''=Ecobee 계정이 SmartThings에 연결되었습니다! -'''Click 'Done' to finish setup.'''=설정을 완료하려면 [완료]를 클릭하세요. -'''The connection could not be established!'''=연결을 실행할 수 없습니다! -'''Click 'Done' to return to the menu.'''=메뉴로 돌아가려면 [완료]를 클릭하세요. -'''is connected to SmartThings'''=이(가) SmartThings에 연결되었습니다 -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=이(가) SmartThings에서 연결 해제되었습니다. 로그인 정보가 변경되었거나 유실되었습니다. Ecobee (연결) 스마트앱에서 계정의 로그인 정보를 다시 입력하세요. -'''Your Ecobee thermostat '''=Ecobee 온도조절기 -'''Select your ecobee devices'''=ecobee 기기 선택 -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=ecobee 계정에서 사용할 수 있는 온도조절기를 추가하거나 삭제하려면 아래를 누르세요. 선택된 온도조절기를 SmartThings에 연결합니다. -'''Log In'''=로그인 -'''Tap Next to continue to set up your ecobee thermostats.'''=계속해서 ecobee 온도조절기를 설정하려면 [다음]을 누르세요. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=ecobee 계정에서 사용할 수 있는 원격 센서를 추가하거나 삭제하려면 아래를 누르세요. 선택된 센서를 SmartThings에 연결합니다. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=ecobee 계정에서 사용할 수 있는 스위치를 추가하거나 삭제하려면 아래를 누르세요. 선택된 스위치를 SmartThings에 연결합니다. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties deleted file mode 100644 index 173ef4e7e3c..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Verbind uw Ecobee-thermostaat met SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=U bent verbonden. -'''Click to enter Ecobee Credentials'''=Klik om Ecobee-inloggegevens in te voeren -'''Login'''=Inloggen -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tik hieronder om in te loggen bij uw ecobee-service en toegang door SmartThings toe te staan. Scrol naar beneden op pagina 2 en druk op de knop Allow (Toestaan). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Selecteer uw thermostaten -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tik hieronder om de lijst met ecobee-thermostaten in uw ecobee-account weer te geven en de apparaten te selecteren die u wilt verbinden met SmartThings. -'''Tap to choose'''=Tik om te kiezen -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tik hieronder om de lijst met ecobee-sensoren in uw ecobee-account weer te geven en de apparaten te selecteren die u wilt verbinden met SmartThings. -'''Tap to choose'''=Tik om te kiezen -'''Select Ecobee Sensors ({{numFound}} found)'''=Selecteer Ecobee-sensoren ({{numFound}} gevonden) -'''Your ecobee Account is now connected to SmartThings!'''=Uw ecobee-account is nu verbonden met SmartThings. -'''Click 'Done' to finish setup.'''=Klik op Done (Gereed) om het instellen te voltooien. -'''The connection could not be established!'''=Er kan geen verbinding worden gemaakt. -'''Click 'Done' to return to the menu.'''=Klik op Done (Gereed) om terug te gaan naar het menu. -'''is connected to SmartThings'''=is verbonden met SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=-verbinding met SmartThings is verbroken, omdat de inloggegevens zijn gewijzigd of verloren zijn gegaan. Ga naar de Ecobee (Connect) SmartApp en voer de inloggegevens voor uw account opnieuw in. -'''Your Ecobee thermostat '''=Uw Ecobee-thermostaat -'''Select your ecobee devices'''=Selecteer uw ecobee-apparaten -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tik hieronder om thermostaten die beschikbaar zijn in uw ecobee-account, toe te voegen of te verwijderen. Geselecteerde thermostaten maken verbinding met SmartThings. -'''Log In'''=Inloggen -'''Tap Next to continue to set up your ecobee thermostats.'''=Tik op Volgende om verder te gaan met het instellen van uw ecobee-thermostaten. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Tik hieronder om externe sensoren die beschikbaar zijn in uw ecobee-account, toe te voegen of te verwijderen. Geselecteerde sensoren maken verbinding met SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Tik hieronder om schakelaars die beschikbaar zijn in uw ecobee-account, toe te voegen of te verwijderen. Geselecteerde schakelaars maken verbinding met SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties b/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties deleted file mode 100644 index b38993c2ba0..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Koble Ecobee-termostaten til SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Du er tilkoblet. -'''Click to enter Ecobee Credentials'''=Klikk for å angi Ecobee-informasjon -'''Login'''=Logg på -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Trykk nedenfor for å logge på ecobee-tjenesten og godkjenne SmartThings-tilgang. Pass på å bla ned på side 2 og trykke på Allow (Tillat)-knappen. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Velg termostatene dine -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trykk nedenfor for å se listen over ecobee-termostatene som er tilgjengelige i ecobee-kontoen din, og velg de du vil koble til SmartThings. -'''Tap to choose'''=Trykk for å velge -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trykk nedenfor for å se listen over ecobee-sensorene som er tilgjengelige i ecobee-kontoen din, og velg de du vil koble til SmartThings. -'''Tap to choose'''=Trykk for å velge -'''Select Ecobee Sensors ({{numFound}} found)'''=Velg Ecobee-sensorer (fant {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=ecobee-kontoen din er nå koblet til SmartThings! -'''Click 'Done' to finish setup.'''=Klikk på Done (Ferdig) for å fullføre oppsettet. -'''The connection could not be established!'''=Kunne ikke opprette tilkoblingen! -'''Click 'Done' to return to the menu.'''=Klikk på Done (Ferdig) for å gå tilbake til menyen. -'''is connected to SmartThings'''=er koblet til SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=er koblet fra SmartThings fordi tilgangsinformasjonen ble endret eller mistet. Gå til Ecobee (Connect) SmartApp, og angi påloggingsinformasjonen for kontoen på nytt. -'''Your Ecobee thermostat '''=Ecobee-termostaten -'''Select your ecobee devices'''=Velg ecobee-enhetene dine -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Trykk nedenfor for å legge til eller fjerne termostater som er tilgjengelige i ecobee-kontoen din. Valgte termostater blir koblet til SmartThings. -'''Log In'''=Logg på -'''Tap Next to continue to set up your ecobee thermostats.'''=Trykk på Next (Neste) for å fortsette å sette opp ecobee-termostatene. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Trykk nedenfor for å legge til eller fjerne sensorer som er tilgjengelige i ecobee-kontoen din. Valgte sensorer blir koblet til SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Trykk nedenfor for å legge til eller fjerne brytere som er tilgjengelige i ecobee-kontoen din. Valgte brytere blir koblet til SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties deleted file mode 100644 index b5c48ef48ac..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Połącz termostat Ecobee ze SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Połączono. -'''Click to enter Ecobee Credentials'''=Kliknij, aby wprowadzić poświadczenia Ecobee -'''Login'''=Logowanie -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Dotknij poniżej, aby zalogować się do usługi ecobee i autoryzować dostęp SmartThings. Przewiń w dół na stronie 2 i naciśnij przycisk „Allow” (Zezwól). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Wybierz termostaty -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dotknij poniżej, aby wyświetlić listę termostatów ecobee dostępnych na koncie ecobee, i wybierz te, które chcesz połączyć ze SmartThings. -'''Tap to choose'''=Dotknij, aby wybrać -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dotknij poniżej, aby wyświetlić listę czujników ecobee dostępnych na koncie ecobee, i wybierz te, które chcesz połączyć ze SmartThings. -'''Tap to choose'''=Dotknij, aby wybrać -'''Select Ecobee Sensors ({{numFound}} found)'''=Wybierz czujniki Ecobee (znaleziono {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Konto ecobee jest teraz połączone ze SmartThings. -'''Click 'Done' to finish setup.'''=Kliknij opcję „Done” (Gotowe), aby ukończyć instalację. -'''The connection could not be established!'''=Nie można ustanowić połączenia. -'''Click 'Done' to return to the menu.'''=Kliknij opcję „Done” (Gotowe), aby powrócić do menu. -'''is connected to SmartThings'''=jest połączony ze SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=jest odłączony od SmartThings, ponieważ poświadczenie dostępu zostało zmienione lub utracone. Przejdź do aplikacji Ecobee (Connect) SmartApp i wprowadź ponownie poświadczenia logowania konta. -'''Your Ecobee thermostat '''=Termostat Ecobee -'''Select your ecobee devices'''=Wybierz urządzenia ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Dotknij poniżej, aby dodać lub usunąć termostaty dostępne na koncie ecobee. Wybrane termostaty zostaną połączone ze SmartThings. -'''Log In'''=Logowanie -'''Tap Next to continue to set up your ecobee thermostats.'''=Dotknij opcji Dalej, aby skonfigurować termostaty ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Dotknij poniżej, aby dodać lub usunąć zdalne czujniki dostępne na koncie ecobee. Wybrane czujniki zostaną połączone ze SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Dotknij poniżej, aby dodać lub usunąć przełączniki dostępne na koncie ecobee. Wybrane przełączniki zostaną połączone ze SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties deleted file mode 100644 index cedf11f9b31..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conecte seu termostato Ecobee ao SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Você está conectado. -'''Click to enter Ecobee Credentials'''=Clique para inserir as credenciais do Ecobee -'''Login'''=Conectar -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toque abaixo para entrar no serviço ecobee e autorizar o acesso ao SmartThings. Certifique-se de rolar para baixo na página 2 e pressionar o botão 'Allow' (Permitir). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Selecionar seus termostatos -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de termostatos ecobee disponíveis na sua conta ecobee e selecione os que deseja conectar ao SmartThings. -'''Tap to choose'''=Tocar para escolher -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de sensores ecobee disponíveis na sua conta ecobee e selecione os que deseja conectar ao SmartThings. -'''Tap to choose'''=Tocar para escolher -'''Select Ecobee Sensors ({{numFound}} found)'''=Selecionar sensores Ecobee ({{numFound}} encontrado(s)) -'''Your ecobee Account is now connected to SmartThings!'''=Agora sua conta ecobee está conectada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em 'Done' (Concluído) para concluir a configuração. -'''The connection could not be established!'''=Não foi possível estabelecer a conexão! -'''Click 'Done' to return to the menu.'''=Clique em 'Done' (Concluído) para retornar ao menu. -'''is connected to SmartThings'''=está conectado ao SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=foi desconectado do SmartThings, pois a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e insira novamente suas credenciais de acesso à conta. -'''Your Ecobee thermostat '''=Seu termostato Ecobee -'''Select your ecobee devices'''=Selecionar seus aparelhos ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toque abaixo para adicionar ou remover os termostatos disponíveis na sua conta ecobee. Os termostatos selecionados serão conectados ao SmartThings. -'''Log In'''=Entrar -'''Tap Next to continue to set up your ecobee thermostats.'''=Toque em Avançar para configurar seus termostatos ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Toque abaixo para adicionar ou remover os sensores remotos disponíveis na sua conta ecobee. Os sensores selecionados serão conectados ao SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Toque abaixo para adicionar ou remover os interruptores disponíveis na sua conta ecobee. Os interruptores selecionados serão conectados ao SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties deleted file mode 100644 index d70f944e1e2..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Ligue o seu termóstato Ecobee ao SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Está ligado. -'''Click to enter Ecobee Credentials'''=Clique para introduzir as Credenciais da Ecobee -'''Login'''=Iniciar Sessão -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toque abaixo para iniciar sessão no serviço ecobee e autorizar o acesso ao SmartThings. Certifique-se de que se desloca para baixo na página 2 e prime o botão "Allow" (Permitir). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Seleccionar os seus Termóstatos -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de termóstatos da ecobee disponíveis na sua conta ecobee e seleccione aqueles que pretende ligar ao SmartThings. -'''Tap to choose'''=Toque para escolher -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de sensores da ecobee disponíveis na sua conta ecobee e seleccione aqueles que pretende ligar ao SmartThings. -'''Tap to choose'''=Toque para escolher -'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores da Ecobee ({{numFound}} encontrado) -'''Your ecobee Account is now connected to SmartThings!'''=Agora, a sua Conta ecobee está ligada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em "Done" (Concluir) para terminar a configuração. -'''The connection could not be established!'''=Não foi possível estabelecer a ligação! -'''Click 'Done' to return to the menu.'''=Clique em "Done" (Concluir) para regressar ao menu. -'''is connected to SmartThings'''=está ligado ao SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=foi desligado do SmartThings, porque a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e introduza novamente as suas credenciais de início de sessão na conta. -'''Your Ecobee thermostat '''=O seu termóstato Ecobee -'''Select your ecobee devices'''=Seleccionar os seus dispositivos ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toque abaixo para adicionar ou remover termóstatos disponíveis na sua conta ecobee. Os termóstatos seleccionados irão ligar-se ao SmartThings. -'''Log In'''=Iniciar Sessão -'''Tap Next to continue to set up your ecobee thermostats.'''=Toque em Seguinte para continuar a configurar os seus termóstatos ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Toque abaixo para adicionar ou remover sensores remotos disponíveis na sua conta ecobee. Os sensores seleccionados irão ligar-se ao SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Toque abaixo para adicionar ou remover interruptores disponíveis na sua conta ecobee. Os interruptores seleccionados irão ligar-se ao SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties deleted file mode 100644 index d552f704983..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Conectați termostatul Ecobee la SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Sunteți conectat. -'''Click to enter Ecobee Credentials'''=Faceți clic pentru a introduce acreditările Ecobee -'''Login'''=Conectare -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Atingeți mai jos pentru a vă conecta la serviciul ecobee și a autoriza accesul la SmartThings. Asigurați-vă că ați derulat în jos până la pagina 2 și apăsați butonul „Allow” (Permitere). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Selectați termostatele -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Atingeți mai jos pentru a vizualiza o listă de termostate ecobee disponibile în contul dvs. ecobee și selectați-le pe cele pe care doriți să le conectați la SmartThings. -'''Tap to choose'''=Atingeți pentru a selecta -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Atingeți mai jos pentru a vizualiza o listă de senzori ecobee disponibili în contul dvs. ecobee și selectați-i pe cei pe care doriți să îi conectați la SmartThings. -'''Tap to choose'''=Atingeți pentru a selecta -'''Select Ecobee Sensors ({{numFound}} found)'''=Selectare senzori Ecobee ({{numFound}} găsiți) -'''Your ecobee Account is now connected to SmartThings!'''=Contul dvs. ecobee este acum conectat la SmartThings! -'''Click 'Done' to finish setup.'''=Faceți clic pe „Done” (Efectuat) pentru a finaliza configurarea. -'''The connection could not be established!'''=Nu a putut fi stabilită conexiunea! -'''Click 'Done' to return to the menu.'''=Faceți clic pe „Done” (Efectuat) pentru a reveni la meniu. -'''is connected to SmartThings'''=este conectat la SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=este deconectat de la SmartThings, deoarece acreditările de acces au fost schimbate sau pierdute. Accesați aplicația Ecobee (Connect) SmartApp și reintroduceți acreditările de conectare la cont. -'''Your Ecobee thermostat '''=Termostatul dvs. Ecobee -'''Select your ecobee devices'''=Selectați dispozitivele dvs. ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Atingeți mai jos pentru a adăuga sau elimina termostate disponibile în contul dvs. ecobee. Termostatele selectate se vor conecta la SmartThings. -'''Log In'''=Conectare -'''Tap Next to continue to set up your ecobee thermostats.'''=Atingeți Înainte pentru a continua să configurați termostatele ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Atingeți mai jos pentru a adăuga sau elimina senzorii la distanță disponibili în contul dvs. ecobee. Senzorii selectați se vor conecta la SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Atingeți mai jos pentru a adăuga sau elimina comutatoare disponibile în contul dvs. ecobee. Comutatoarele selectate se vor conecta la SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties deleted file mode 100644 index bfa4b083b0e..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Подключите свой термостат Ecobee к SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Подключено. -'''Click to enter Ecobee Credentials'''=Нажмите для ввода учетных данных Ecobee -'''Login'''=Вход -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Коснитесь ниже, чтобы войти в службу ecobee и предоставить доступ SmartThings. Обязательно прокрутите страницу 2 до самого низа и нажмите кнопку «Разрешить». -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Выберите свои термостаты -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Коснитесь ниже, чтобы отобразить список доступных термостатов ecobee в вашей учетной записи ecobee, и выберите те, которые нужно подключить к SmartThings. -'''Tap to choose'''=Коснитесь, чтобы выбрать -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Коснитесь ниже, чтобы отобразить список доступных датчиков ecobee в вашей учетной записи ecobee, и выберите те, которые нужно подключить к SmartThings. -'''Tap to choose'''=Коснитесь, чтобы выбрать -'''Select Ecobee Sensors ({{numFound}} found)'''=Выбрать датчики Ecobee (найдено {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Теперь ваша учетная запись ecobee подключена к SmartThings! -'''Click 'Done' to finish setup.'''=Для завершения настройки нажмите «Готово». -'''The connection could not be established!'''=Не удалось установить соединение! -'''Click 'Done' to return to the menu.'''=Чтобы вернуться в меню, нажмите «Готово». -'''is connected to SmartThings'''=подключено к SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=отключено от SmartThings, поскольку данные для доступа были изменены или потеряны. Перейдите в Ecobee (Подключить) SmartApp и повторно введите регистрационные данные своей учетной записи. -'''Your Ecobee thermostat '''=Ваш термостат Ecobee -'''Select your ecobee devices'''=Выберите свои устройства ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Чтобы добавить или удалить доступные термостаты в учетной записи ecobee, коснитесь ниже. Выбранные термостаты будут подключены к SmartThings. -'''Log In'''=Войти -'''Tap Next to continue to set up your ecobee thermostats.'''=Чтобы продолжить настройку термостатов ecobee, нажмите “Далее”. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Чтобы добавить или удалить доступные дистанционные датчики в учетной записи ecobee, коснитесь ниже. Выбранные датчики будут подключены к SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Чтобы добавить или удалить доступные переключатели в учетной записи ecobee, коснитесь ниже. Выбранные переключатели будут подключены к SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties deleted file mode 100644 index e0e9fb1ced3..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Pripojte termostat Ecobee k systému SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Ste pripojení. -'''Click to enter Ecobee Credentials'''=Kliknite a zadajte poverenia pre Ecobee -'''Login'''=Prihlásiť sa -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ťuknutím nižšie sa prihláste k službe ecobee a autorizujte prístup do systému SmartThings. Prejdite nadol na stránku 2 a stlačte tlačidlo Allow (Povoliť). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Vyberte termostaty -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ťuknutím nižšie môžete zobraziť zoznam termostatov ecobee dostupných vo vašom konte ecobee a vybrať tie, ktoré chcete pripojiť k systému SmartThings. -'''Tap to choose'''=Ťuknutím vyberte -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ťuknutím nižšie môžete zobraziť zoznam senzorov ecobee dostupných vo vašom konte ecobee a vybrať tie, ktoré chcete pripojiť k systému SmartThings. -'''Tap to choose'''=Ťuknutím vyberte -'''Select Ecobee Sensors ({{numFound}} found)'''=Vyberte senzory Ecobee (nájdené: {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Vaše konto ecobee je teraz prepojené so systémom SmartThings. -'''Click 'Done' to finish setup.'''=Kliknutím na tlačidlo Done (Hotovo) dokončite inštaláciu. -'''The connection could not be established!'''=Nepodarilo sa nadviazať spojenie. -'''Click 'Done' to return to the menu.'''=Kliknutím na tlačidlo Done (Hotovo) sa vráťte do menu. -'''is connected to SmartThings'''=je pripojený k systému SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=je odpojený od systému SmartThings, pretože prístupové poverenia boli zmenené alebo stratené. Prejdite do aplikácie Ecobee (Connect) SmartApp a znova zadajte prihlasovacie poverenia pre konto. -'''Your Ecobee thermostat '''=Váš termostat Ecobee -'''Select your ecobee devices'''=Vyberte svoje zariadenia ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Ťuknutím nižšie môžete pridať alebo odstrániť termostaty dostupné vo vašom konte ecobee. Vybraté termostaty sa pripoja k systému SmartThings. -'''Log In'''=Prihlásiť sa -'''Tap Next to continue to set up your ecobee thermostats.'''=Ťuknutím na tlačidlo Ďalej pokračujte v nastavovaní termostatov ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Ťuknutím nižšie môžete pridať alebo odstrániť diaľkové senzory dostupné vo vašom konte ecobee. Vybraté senzory sa pripoja k systému SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Ťuknutím nižšie môžete pridať alebo odstrániť vypínače dostupné vo vašom konte ecobee. Vybraté vypínače sa pripoja k systému SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties deleted file mode 100644 index c4b71c54066..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Povežite termostat Ecobee s storitvijo SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Povezani ste. -'''Click to enter Ecobee Credentials'''=Kliknite za vnos poverilnic Ecobee -'''Login'''=Prijava -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pritisnite spodaj, da se prijavite v storitev ecobee in odobrite dostop do storitve SmartThings. Pomaknite se na 2. stran in pritisnite gumb »Allow« (Dovoli). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Izberite svoje termostate -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pritisnite spodaj za prikaz seznama termostatov ecobee, ki so na voljo v vašem računu ecobee, in izberite tiste, ki jih želite povezati s storitvijo SmartThings. -'''Tap to choose'''=Pritisnite za izbiranje -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pritisnite spodaj za prikaz seznama senzorjev ecobee, ki so na voljo v vašem računu ecobee, in izberite tiste, ki jih želite povezati s storitvijo SmartThings. -'''Tap to choose'''=Pritisnite za izbiranje -'''Select Ecobee Sensors ({{numFound}} found)'''=Izberite senzorje Ecobee (št. najdenih: {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Vaš račun ecobee je zdaj povezan s storitvijo SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite »Done« (Končano), da zaključite nastavitev. -'''The connection could not be established!'''=Povezave ni bilo mogoče vzpostaviti! -'''Click 'Done' to return to the menu.'''=Kliknite »Done« (Končano), da se vrnete v meni. -'''is connected to SmartThings'''=je povezan s storitvijo SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ni povezan s storitvijo SmartThings, ker so bile poverilnice za dostop spremenjene ali izgubljene. Pojdite v aplikacijo Ecobee (Connect) SmartApp in znova vnesite poverilnice za prijavo v račun. -'''Your Ecobee thermostat '''=Vaš termostat Ecobee -'''Select your ecobee devices'''=Izberite naprave ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pritisnite spodaj, da dodate ali odstranite termostate, ki so na voljo v vašem računu ecobee. Izbrani termostati se bodo povezali s storitvijo SmartThings. -'''Log In'''=Prijava -'''Tap Next to continue to set up your ecobee thermostats.'''=Za nadaljevanje pritisnite Next (Naprej), da nastavite termostate ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Pritisnite spodaj, da dodate ali odstranite oddaljene senzorje, ki so na voljo v vašem računu ecobee. Izbrani senzorji se bodo povezali s storitvijo SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Pritisnite spodaj, da dodate ali odstranite stikala, ki so na voljo v vašem računu ecobee. Izbrana stikala se bodo povezala s storitvijo SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties deleted file mode 100644 index d92f42c06bf..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Lidh termostatin Ecobee me SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Je lidhur. -'''Click to enter Ecobee Credentials'''=Kliko për të futur kredencialet Ecobee -'''Login'''=Login -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Trokit më poshtë për t’u loguar në shërbimin ecobee dhe autorizuar aksesin në SmartThings. Sigurohu që të lundrosh poshtë në faqen 2 dhe të shtypësh butonin ‘Allow’ (Lejo). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Përzgjidh termostatet e tua -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trokit më poshtë për të parë listën e termostateve ecobee që janë në dispozicion në llogarinë tënde ecobee dhe përzgjidh ato që dëshiron të lidhen me SmartThings. -'''Tap to choose'''=Trokit për të zgjedhur -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trokit më poshtë për të parë listën e sensorëve ecobee që janë në dispozicion në llogarinë tënde ecobee dhe përzgjidh ato që dëshiron të lidhen me SmartThings. -'''Tap to choose'''=Trokit për të zgjedhur -'''Select Ecobee Sensors ({{numFound}} found)'''=Përzgjidh sensorët Ecobee (u gjet {{numFound}}) -'''Your ecobee Account is now connected to SmartThings!'''=Llogaria jote ecobee tani është lidhur me SmartThings! -'''Click 'Done' to finish setup.'''=Kliko mbi ‘Done’ (U krye) për ta mbaruar konfigurimin. -'''The connection could not be established!'''=Lidhja nuk u vendos dot! -'''Click 'Done' to return to the menu.'''=Kliko mbi ‘Done’ (U krye) për t’u kthyer në meny. -'''is connected to SmartThings'''=është lidhur me SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=është shkëputur nga SmartThings, sepse kredenciali i aksesit ka ndryshuar ose ka humbur. Shko te Ecobee (Connect) SmartApp dhe futi sërish kredencialet e logimit në llogari. -'''Your Ecobee thermostat '''=Termostati yt Ecobee -'''Select your ecobee devices'''=Përzgjidh pajisjet e tua ecobee -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Trokit më poshtë për të shtuar ose hequr termostate që gjenden në llogarinë tënde ecobee. Termostatet e përzgjedhura do të lidhen me SmartThings. -'''Log In'''=Logohu -'''Tap Next to continue to set up your ecobee thermostats.'''=Trokit mbi Next (Tjetri) për të konfiguruar termostatet e tua ecobee. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Trokit më poshtë për të shtuar ose hequr sensorë në distancë që gjenden në llogarinë tënde ecobee. Sensorët e përzgjedhur do të lidhen me SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Trokit më poshtë për të shtuar ose hequr çelësa që gjenden në llogarinë tënde ecobee. Çelësat e përzgjedhur do të lidhen me SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties deleted file mode 100644 index 2ed4545e50c..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Povežite Ecobee termostat na SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Povezani ste. -'''Click to enter Ecobee Credentials'''=Kliknite da biste uneli Ecobee akreditive -'''Login'''=Login (Prijava) -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Kucnite ispod da biste se prijavili na uslugu ecobee i odobrili pristup aplikaciji SmartThings. Obavezno listajte nadole do stranice broj 2 i pritisnite dugme „Allow” (Dozvoli). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Izaberite termostate -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Kucnite ispod da biste videli listu dostupnih ecobee termostata na svom ecobee nalogu i izaberite one koje želite da povežete na SmartThings. -'''Tap to choose'''=Kucnite da biste odabrali -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Kucnite ispod da biste videli listu dostupnih senzora na svom ecobee nalogu i izaberite one koje želite da povežete na SmartThings. -'''Tap to choose'''=Kucnite da biste odabrali -'''Select Ecobee Sensors ({{numFound}} found)'''=Izaberite Ecobee senzore ({{numFound}} pronađeno) -'''Your ecobee Account is now connected to SmartThings!'''=Vaš ecobee nalog je sada povezan na SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite na „Done” (Gotovo) za kraj konfiguracije. -'''The connection could not be established!'''=Veza nije uspostavljena! -'''Click 'Done' to return to the menu.'''=Kliknite na „Done” (Gotovo) da biste se vratili na meni. -'''is connected to SmartThings'''=je povezan na SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=je prekinuo vezu sa aplikacijom SmartThings zato što su akreditivi za pristup promenjeni ili izgubljeni. Idite na aplikaciju Ecobee (Connect) SmartApp i ponovo unesite akreditive za prijavljivanje na nalog. -'''Your Ecobee thermostat '''=Vaš Ecobee termostat -'''Select your ecobee devices'''=Izaberite ecobee uređaje -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Kucnite ispod da biste dodali ili uklonili dostupne termostate na ecobee nalogu. Izabrani termostati će se povezati na SmartThings. -'''Log In'''=Prijavljivanje -'''Tap Next to continue to set up your ecobee thermostats.'''=Kucnite na Dalje da biste nastavili konfiguraciju ecobee termostata. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Kucnite ispod da biste dodali ili uklonili dostupne daljinske termostate na ecobee nalogu. Izabrani senzori će se povezati na SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Kucnite ispod da biste dodali ili uklonili dostupne prekidače na ecobee nalogu. Izabrani prekidači će se povezati na SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties deleted file mode 100644 index ea957914439..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Anslut din Ecobee-termostat till SmartThings. -'''ecobee'''=ecobee -'''You are connected.'''=Du är ansluten. -'''Click to enter Ecobee Credentials'''=Klicka för att ange dina Ecobee-inloggningsuppgifter -'''Login'''=Logga in -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tryck nedan för att logga in på ecobee-tjänsten och ge SmartThings åtkomst. Rulla ned till sidan 2 och tryck på knappen Allow (Tillåt). -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Välj dina termostater -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryck nedan om du vill se listan med ecobee-termostater som är tillgängliga i ditt ecobee-konto och välj dem du vill ansluta till SmartThings. -'''Tap to choose'''=Tryck för att välja -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryck nedan om du vill se listan med ecobee-givare som är tillgängliga i ditt ecobee-konto och välj dem du vill ansluta till SmartThings. -'''Tap to choose'''=Tryck för att välja -'''Select Ecobee Sensors ({{numFound}} found)'''=Välj Ecobee-givare ({{numFound}} hittades) -'''Your ecobee Account is now connected to SmartThings!'''=Ditt ecobee-konto är nu anslutet till SmartThings! -'''Click 'Done' to finish setup.'''=Klicka på Done (Klart) för att slutföra konfigurationen. -'''The connection could not be established!'''=Det gick inte att upprätta anslutningen! -'''Click 'Done' to return to the menu.'''=Klicka på Done (Klart) för att återgå till menyn. -'''is connected to SmartThings'''=är ansluten till SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=är frånkopplad från SmartThings, eftersom inloggningsuppgifterna har ändrats eller gått förlorade. Starta Ecobee (Connect) SmartApp och ange kontots inloggningsuppgifter igen. -'''Your Ecobee thermostat '''=Din Ecobee-termostat -'''Select your ecobee devices'''=Välj dina ecobee-enheter -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tryck nedan om du vill lägga till eller ta bort termostater som är tillgängliga i ditt ecobee-konto. De valda termostaterna ansluter till SmartThings. -'''Log In'''=Logga in -'''Tap Next to continue to set up your ecobee thermostats.'''=Fortsätt ställa in ecobee-termostaterna genom att trycka på Next (Nästa). -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=Tryck nedan om du vill lägga till eller ta bort fjärrsensorer som är tillgängliga i ditt ecobee-konto. De valda sensorerna ansluter till SmartThings. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=Tryck nedan om du vill lägga till eller ta bort strömbrytare som är tillgängliga i ditt ecobee-konto. De valda strömbrytarna ansluter till SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties b/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties deleted file mode 100644 index 57a2f36f35b..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=เชื่อมต่อตัวควบคุมอุณหภูมิ Ecobee ของคุณเข้ากับ SmartThings -'''ecobee'''=Ecobee -'''You are connected.'''=คุณได้เชื่อมต่อแล้ว -'''Click to enter Ecobee Credentials'''=คลิกเพื่อใส่ ข้อมูลยืนยันตัวตน Ecobee -'''Login'''=เข้าสู่ระบบ -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=แตะด้านล่างเพื่อเข้าสู่บริการ Ecobee และอนุญาตการเข้าถึงของ SmartThings ดูให้แน่ใจว่าได้เลื่อนลงมาที่หน้า 2 แล้วกดปุ่ม 'อนุญาต' -'''ecobee'''=Ecobee -'''Select Your Thermostats'''=เลือกตัวควบคุมอุณหภูมิของคุณ -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=แตะที่ด้านล่างเพื่อดูรายการตัวควบคุมอุณหภูมิ Ecobee ที่มีอยู่ในบัญชีผู้ใช้ Ecobee ของคุณ และเลือกตัวควบคุมอุณหภูมิที่คุณต้องการจะเชื่อมต่อกับ SmartThings -'''Tap to choose'''=แตะเพื่อเลือก -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=แตะที่ด้านล่างเพื่อดูรายการเซ็นเซอร์ Ecobee ที่มีอยู่ในบัญชีผู้ใช้ Ecobee ของคุณ และเลือกเซ็นเซอร์ที่คุณต้องการจะเชื่อมต่อกับ SmartThings -'''Tap to choose'''=แตะเพื่อเลือก -'''Select Ecobee Sensors ({{numFound}} found)'''=เลือกเซ็นเซอร์ Ecobee ({{numFound}} found) -'''Your ecobee Account is now connected to SmartThings!'''=ตอนนี้บัญชีผู้ใช้ Ecobee ของคุณเชื่อมต่อกับ SmartThings แล้ว -'''Click 'Done' to finish setup.'''=คลิก 'เสร็จสิ้น' เพื่อทำการตั้งค่าให้เสร็จสิ้น -'''The connection could not be established!'''=ไม่สามารถสร้างการเชื่อมต่อได้! -'''Click 'Done' to return to the menu.'''=คลิก 'เสร็จสิ้น' เพื่อกลับไปยังเมนู -'''is connected to SmartThings'''={{deviceName}} เชื่อมต่อกับ SmartThings แล้ว -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''={{deviceName}} ถูกตัดการเชื่อมต่อจาก SmartThings เนื่องจากข้อมูลการเข้าถึงถูกเปลี่ยนแปลงหรือหายไป กรุณาไปที่ Ecobee (การเชื่อมต่อ) SmartApp และใส่ข้อมูลยืนยันตัวตนการเข้าสู่บัญชีผู้ใช้ของคุณอีกครั้ง -'''Your Ecobee thermostat '''=ตัวควบคุมอุณหภูมิ Ecobee ของคุณ -'''Select your ecobee devices'''=เลือกอุปกรณ์ ecobee ของคุณ -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=แตะด้านล่างเพื่อเพิ่มหรือลบตัวควบคุมอุณหภูมิที่พร้อมใช้งานในบัญชี ecobee ของคุณ ตัวควบคุมอุณหภูมิที่เลือกจะเชื่อมต่อกับ SmartThings -'''Log In'''=เข้าสู่ระบบ -'''Tap Next to continue to set up your ecobee thermostats.'''=แตะ ถัดไป เพื่อดำเนินการตั้งค่าตัวควบคุมอุณหภูมิ ecobee ต่อ -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=แตะด้านล่างเพื่อเพิ่มหรือลบเซ็นเซอร์ระยะไกลที่พร้อมใช้งานในบัญชี ecobee ของคุณ เซ็นเซอร์ที่เลือกจะเชื่อมต่อกับ SmartThings -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=แตะด้านล่างเพื่อเพิ่มหรือลบสวิตช์ที่พร้อมใช้งานในบัญชี ecobee ของคุณ สวิตช์ที่เลือกจะเชื่อมต่อกับ SmartThings diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties deleted file mode 100644 index 59f4e905ff3..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee termostatınızı SmartThings'e bağlayın. -'''ecobee'''=ecobee -'''You are connected.'''=Bağlantı kurdunuz. -'''Click to enter Ecobee Credentials'''=Ecobee Kimlik Bilgilerinizi girmek için tıklayın -'''Login'''=Oturum aç -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ecobee servisinde oturum açmak ve SmartThings erişimine izin vermek için aşağıya dokunun. Ekranı 2. sayfaya kaydırdığınızdan emin olun ve 'İzin Ver' tuşuna basın. -'''ecobee'''=ecobee -'''Select Your Thermostats'''=Termostatlarınızı Seçin -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee hesabınızda mevcut olan ecobee termostatlarının listesini görüntülemek için aşağıya dokunun ve SmartThings'e bağlamak istediklerinizi seçin. -'''Tap to choose'''= seçmek için dokunun -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee hesabınızda mevcut olan ecobee sensörlerinin listesini görüntülemek için aşağıya dokunun ve SmartThings'e bağlamak istediklerinizi seçin. -'''Tap to choose'''= seçmek için dokunun -'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee Sensörlerini seçin ({{numFound}} bulundu) -'''Your ecobee Account is now connected to SmartThings!'''=Ecobee Hesabınız artık SmartThings'e bağlandı! -'''Click 'Done' to finish setup.'''=Kurulumu bitirmek için 'Bitti' öğesine tıklayın. -'''The connection could not be established!'''=Bağlantı kurulamadı! -'''Click 'Done' to return to the menu.'''=Menüye dönmek için 'Bitti' öğesine tıklayın. -'''is connected to SmartThings'''={{cihazİsmi}} SmartThings'e bağlandı -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=Erişim kimlik doğruları değiştirildiğinden veya kaybolduğundan {{cihazİsmi}} ile SmartThings arasındaki bağlantı kesildi. Lütfen Ecobee (Connect) SmartApp'e gidin ve hesabınızın oturum açma kimlik bilgilerini tekrar girin. -'''Your Ecobee thermostat '''=Ecobee termostatınız -'''Select your ecobee devices'''=ecobee Cihazlarınızı seçin -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=ecobee hesabınızdaki kullanılabilir termostatları eklemek veya kaldırmak için aşağıya dokunun. Seçilen termostatlar SmartThings'e bağlanır. -'''Log In'''=Oturum Açın -'''Tap Next to continue to set up your ecobee thermostats.'''=ecobee termostatlarınızı kurmaya devam etmek için İleri ögesine dokunun. -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=ecobee hesabınızdaki kullanılabilir sensörleri eklemek veya kaldırmak için aşağıya dokunun. Seçilen sensörler SmartThings'e bağlanır. -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=ecobee hesabınızdaki kullanılabilir anahtarları eklemek veya kaldırmak için aşağıya dokunun. Seçilen anahtarlar SmartThings'e bağlanır. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties b/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties deleted file mode 100644 index a927eb82b41..00000000000 --- a/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties +++ /dev/null @@ -1,26 +0,0 @@ -'''Connect your Ecobee thermostat to SmartThings.'''=将 Ecobee 恒温器连接至 SmartThings。 -'''ecobee'''=ecobee -'''You are connected.'''=已连接。 -'''Click to enter Ecobee Credentials'''=点击以输入 Ecobee 凭据 -'''Login'''=登录 -'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=点击下方以登录 ecobee 服务并授予 SmartThings 访问权限。务必在第 2 页上向下滚动,然后按下“允许”按钮。 -'''ecobee'''=ecobee -'''Select Your Thermostats'''=选择恒温器 -'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=点击下方以查看 ecobee 帐户中可用 ecobee 恒温器的列表,然后选择要连接至 SmartThings 的恒温器。 -'''Tap to choose'''=点击以选择 -'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=点击下方以查看 ecobee 帐户中可用 ecobee 传感器的列表,然后选择要连接至 SmartThings 的传感器。 -'''Tap to choose'''=点击以选择 -'''Select Ecobee Sensors ({{numFound}} found)'''=选择 Ecobee 传感器 (发现 {{numFound}} 个) -'''Your ecobee Account is now connected to SmartThings!'''=ecobee 帐户现在已连接至 SmartThings! -'''Click 'Done' to finish setup.'''=单击“完成”以完成设置。 -'''The connection could not be established!'''=无法建立连接! -'''Click 'Done' to return to the menu.'''=单击“完成”返回菜单。 -'''is connected to SmartThings'''=已连接至 SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=已从 SmartThings 断开,因为访问凭据已更改或丢失。请转到 Ecobee (连接) SmartApp,然后重新输入您的帐户登录凭据。 -'''Your Ecobee thermostat '''=您的 Ecobee 恒温器 -'''Select your ecobee devices'''=选择您的 ecobee 设备 -'''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=点击下方可添加或删除 ecobee 帐户中的恒温器。选定的恒温器将连接到 SmartThings。 -'''Log In'''=登录 -'''Tap Next to continue to set up your ecobee thermostats.'''=点击下一步继续设置您的 ecobee 恒温器。 -'''Tap below to add or remove remote sensors available in your ecobee account. Selected sensors will connect to SmartThings.'''=点击下方可添加或删除 ecobee 帐户中可用的远程传感器。选定的传感器将连接到 SmartThings。 -'''Tap below to add or remove switches available in your ecobee account. Selected switches will connect to SmartThings.'''=点击下方添加或删除您的 ecobee 帐户中可用的开关。选定的开关将连接到 SmartThings。 From fa029dee992088e2c5430c970e8df5cd9201445d Mon Sep 17 00:00:00 2001 From: Focalcrest-Madi <58587489+Focalcrest-Madi@users.noreply.github.com> Date: Mon, 6 Dec 2021 17:43:07 +0800 Subject: [PATCH 089/184] DevWs for Focalcrest containing containing ZigBee Switch (#76710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for Focalcrest containing containing ZigBee Switch * Fix: replace 4 spaces to 1 tab * Fix: indentations(replace 4 spaces to 1 tab) * Fix:indentations Line 125 (replace 4 spaces to 1 tab) --- .../smartthings/zigbee-switch.src/zigbee-switch.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 497833cad67..765ed7cb010 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -117,9 +117,11 @@ metadata { fingerprint manufacturer: "Jasco Products", model: "43102", deviceJoinName: "Enbrighten Outlet", ocfDeviceType: "oic.d.smartplug" //Enbrighten, In-Wall Smart Outlet 43102, Raw Description: 01 0104 0100 00 06 0000 0003 0004 0005 0006 0B05 02 000A 0019 fingerprint manufacturer: "Jasco Products", model: "43076", deviceJoinName: "Enbrighten Switch" //Enbrighten, In-Wall Smart Switch 43076, Raw Description: 01 0104 0100 00 06 0000 0003 0004 0005 0006 0B05 02 000A 0019 - // Focalcrest + // Focalcrest/Evvr fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", outClusters: "0019", manufacturer: "Focalcrest", model: "SRB01", deviceJoinName: "Focalcrest Switch" // In-Wall Relay Switch - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "EVVR", model: "SRB01A", deviceJoinName: "Evvr Switch" // Evvr IRS + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "EVVR", model: "SRB02A", deviceJoinName: "Evvr Switch" // Evvr IRS Lite + // SiHAS Switch fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z1", deviceJoinName: "SiHAS Switch" } From a4aa7b862c70558e70ba885489fd1918cb97f3bc Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Tue, 7 Dec 2021 00:59:35 +0400 Subject: [PATCH 090/184] DevWs for HELTUN containing containing HE-HLS01 Handler 'Binary Switch' (#76116) * DevWs for HELTUN containing containing HE-HLS01 Handler 'Binary Switch' * Changed "polling" capability to "Health Check" Minor changes * Spacing changes * Removed device model * placed comments // right after the code * Defined each device setting explicitly some minor improvements * Formmating * Minor Improvement * Reformatting remove HubActions * Formmating * fixed a type in parameters description * changed inClusters as requested * fixed spacing * fixed formatting Co-authored-by: Artur Sargsyan --- .../heltun-hls01-switch.groovy | 310 ++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 devicetypes/heltun/heltun-hls01-switch.src/heltun-hls01-switch.groovy diff --git a/devicetypes/heltun/heltun-hls01-switch.src/heltun-hls01-switch.groovy b/devicetypes/heltun/heltun-hls01-switch.src/heltun-hls01-switch.groovy new file mode 100644 index 00000000000..821ecf413b6 --- /dev/null +++ b/devicetypes/heltun/heltun-hls01-switch.src/heltun-hls01-switch.groovy @@ -0,0 +1,310 @@ +/** + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HELTUN HLS01 Switch", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true) { + capability "Energy Meter" + capability "Power Meter" + capability "Switch" + capability "Temperature Measurement" + capability "Voltage Measurement" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", inClusters:"0x25", deviceJoinName: "HELTUN Switch" //model: "000A" + } + preferences { + input ( + title: "HE-HLS01 | HELTUN High Load Switch", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + +def initialize() { + runIn(3, "checkParam") +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) {result = zwaveEvent(cmd)} + return result +} + +def updated() { + initialize() +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if ( needConfig ) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if ( state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue) { + state."$parameter".state = "configured" + } + else { + state."$parameter".state = "error" + } + configParam() +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def externalTemp = 1 + def map = [:] + if (externalTemp == cmd.sensorType) { + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = locaScale + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + sendEvent(map) + } else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + sendEvent(map) + } else if (cmd.scale == 4) { + map.name = "voltage" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "V" + sendEvent(map) + } else if (cmd.scale == 5) { + map.name = "current" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "A" + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = Calendar.getInstance(location.timeZone) + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)){ + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + def state = cmd.value ? "on" : "off" + sendEvent(name: "switch", value: state) +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [zwaveHubNodeId]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def roundC (tempInC) { + return (Math.round(tempInC.toDouble() * 2))/2 +} + +def refresh() { + def cmds = [] + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() //get Temperature + cmds << zwave.meterV3.meterGet(scale: 0).format() //get kWh + cmds << zwave.meterV3.meterGet(scale: 2).format() //get Watts + cmds << zwave.meterV3.meterGet(scale: 4).format() //get Voltage + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() //get channel association + sendHubCommand(cmds, 1200) + runIn(10, "checkParam") +} + +def ping() { + refresh() +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +def on() { + delayBetween([ + zwave.basicV1.basicSet(value: 0xFF).format(), + zwave.switchBinaryV1.switchBinaryGet().format() + ]) +} + +def off() { + delayBetween([ + zwave.basicV1.basicSet(value: 0x00).format(), + zwave.switchBinaryV1.switchBinaryGet().format() + ]) +} + +def configure() { + ping() +} + +private parameterMap() {[ +[title: "Relay Output Mode", description: "This Parameter determines the type of load connected to the device relay output. The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum"], + +[title: "Floor Sensor Resistance", description: "If an external floor NTC temperature sensor is used it is necessary to select the correct resistance value in kiloOhms (kΩ) of the sensor", + name: "Selected Floor Resistance in kΩ", paramNum: 10, size: 1, default: 10, type: "number", min: 1, max: 100, unit: "kΩ"], + +[title: "Temperature Sensor Calibration", description: "This Parameter defines the offset value for floor temperature. This value will be added or subtracted from the floor temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 17, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + +[title: "Auto On/Off", description: "If this function is enabled the device will switch Off the relay output when there is no consumption and switch On the output again when the load is reconnected. It is possible to set a delay for Auto Off and Auto On functions in configurations (Auto Off Timeout) & (Auto On Reconnect Timeout) below", + name: "Selected Mode", options: [ + 0: "Auto On/Off Disabled", + 1: "Auto On/Off Enabled" + ], paramNum: 23, size: 1, default: "0", type: "enum"], + +[title: "Auto Off Timeout", description: "If Auto On/Off is enabled, it is possible to delay the Auto Off function. The output will be switched Off when there is no consumption for the interval defined in minutes", + name: "Seleced Auto Off Timeout in minutes", paramNum: 24, size: 1, default: 0, type: "number", min: 0, max: 120, unit: "min"], + +[title: "Auto On Reconnect Timeout", description: "If Auto On/Off is enabled, it is possible to delay the Auto On function. When the load is reconnected the relay output will be switched On after the time defined in minutes", + name: "Seleced Auto On Reconnect Timeout in minutes", paramNum: 25, size: 1, default: 5, type: "number", min: 0, max: 120, unit: "min"], + +[title: "High Load Timeout Protection: Power Threshold", description: "If the HLS01 is used to control an electric socket, you can configure the device so that it automatically switch Off the socket if the potentially dangerous high load is connected longer than allowable time set below (High Load Timeout Protection: Time Threshold). Set the threshold value in watts, reaching which the connected load will be considered high The value of this parameter can be set from 100 to 3500 in watts. Use the value 0 if there is a need to disable this function.", + name: "Selected Power Threshold in watts", paramNum: 26, size: 2, default: 0, type: "number", min: 0 , max: 3500, unit: "W"], + +[title: "High Load Timeout Protection: Time Threshold", description: "If High Load Timeout Protection is activated: Power Threshold is enabled, use this parameter to set the threshold value in minutes. If the load is connected longer than this value, the device will automatically switch Off the socket. Use the value 0 if there is a need to disable this function.", + name: "Selected Time Threshold in minutes", paramNum: 27, size: 2, default: 0, type: "number", min: 0 , max: 1440, unit: "min"], + +[title: "External Input: Hold Control Mode", description: "This Parameter defines how the relay should react while holding the button connected to the external input. The options are: Hold is disabled, Operate like click, Momentary Switch: When the button is held, the relay output state is ON, as soon as the button is released the relay output state changes to OFF, Reversed Momentary: When the button is held, the relay output state is OFF, as soon as the button is released the relay output state changes to ON.", + name: "Selected Hold Control Mode", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary" + ], paramNum: 41, size: 1, default: "2", type: "enum"], + +[title: "Hold Mode Duration for External Input S1", description: "This parameter specifies the time the device needs to recognize a hold mode when the button connected to an external input is held (key closed). This parameter is available on firmware V1.3 or higher", + name: "Selected Duration in milliseconds", paramNum: 46, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms"], + +[title: "External Input: Click Control Mode", description: "This Parameter defines how the relay should react when clicking the button connected to the external input. The options are: Click is disabled, Toggle switch: relay inverts state (ON to OFF, OFF to ON), Only On: Relay switches to ON state only, Only Off: Relay switches to OFF state only, Timer: On > Off: Relay output switches to ON state (contacts are closed) then after a specified time switches back to OFF state (contacts are open). The time is specified in 'Relay Timer Mode Duration' below, Timer: Off > On: Relay output switches to OFF state (contacts are open) then after a specified time switches back to On state (contacts are closed). The time is specified in 'Relay Timer Mode Duration' below ", + name: "Selected Click Control Mode", options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 51, size: 1, default: "1", type: "enum"], + +[title: "Relay Timer Mode Duration", description: "This parameters specify the duration in seconds for the Timer modes for Click Control Mode above. Press the button and the relay output goes to ON/OFF for the specified time then changes back to OFF/ON. If the value is set to “0” the relay output will operate as a short contact (duration is about 0.5 sec)", + name: "Selected Timer Mode Duration in seconds", paramNum: 71, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + +[title: "Retore Relay State", description: "This parameter determines if the last relay state should be restored after power failure or not. This parameter is available on firmware V1.5 or higher", + name: "Selected Mode", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 66, size: 1, default: "0", type: "enum"], + +[title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Energy Consumption Meter Report", description: "This Parameter determines the change in the load power resulting in the consumption report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Change Percentage", paramNum: 142, size: 1, default: 25, type: "number", min: 0 , max: 50, unit: "%"], + +[title: "Sensors Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends to the gateway reports from its external NTC temperature sensor even if there are not changes in the values. This Parameter defines the interval between consecutive reports", + name: "Selected Energy Report Interval in minutes", paramNum: 143, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "External Temperature Sensor Report Threshold", description: "This Parameter determines the change in temperature level resulting in temperature sensors report being sent to the gateway. The value of this Parameter should be x10 for °C, e.g. for 0.4°C use value 4. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Threshold in °Cx10", paramNum: 144, size: 1, default: 2, type: "number", min: 0 , max: 100, unit: " °Cx10"], + +[title: "Overheat Protection", description: "You can define the maximum limit of temperature, reaching which the device will automatically switch Off the load. Use the value 0 if there is a need to disable this function", + name: "Selected Limit in °C", paramNum: 153, size: 2, default: 60, type: "number", min: 0 , max: 120, unit: " °C"], + +[title: "Over-Load Protection", description: "You can define the maximum power in Watt for connected load. The device will automatically switch off the output if the power consumed by the connected load exceeds this limit. Use the value 0 if there is a need to disable this function.", + name: "Selected Limit in Watts", paramNum: 155, size: 2, default: 3500, type: "number", min: 0 , max: 4000, unit: "W"], + +[title: "Over-Voltage Protection", description: "The device constantly monitors the voltage of your electricity network. You can define the maximum voltage of network exceeding which the device will automatically switch off the output. Use the value 0 if there is a need to disable this function.", + name: "Selected Upper Limit in Volts", paramNum: 156, size: 2, default: 260, type: "number", min: 120 , max: 280, unit: "V"], + +[title: "Voltage Drop Protection", description: "You can define the minimum voltage of your electricity network. If the voltage of the network drops bellow the determined level the device will automatically switch off the output. Use the value 0 if there is a need to disable this function.", + name: "Selected Lower Limit in Volts", paramNum: 157, size: 2, default: 90, type: "number", min: 80 , max: 240, unit: "V"] + +]} From 2bd112a74b37995ab80b19c41797981c7f5cbdd1 Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Tue, 7 Dec 2021 01:02:04 +0400 Subject: [PATCH 091/184] DevWs for HELTUN containing containing HE-HLS01 Handler (#76161) * DevWs for HELTUN containing containing HE-HLS01 Handler * Removed device model * Formatting * Added parameters Formmating * Minor Improvement * Reformatting remove HubActions Separated getModeMap * Formmating * changed inClusters as requested * fixed formatting Co-authored-by: Artur Sargsyan --- .../heltun-hls01-thermostat.groovy | 441 ++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 devicetypes/heltun/heltun-hls01-thermostat.src/heltun-hls01-thermostat.groovy diff --git a/devicetypes/heltun/heltun-hls01-thermostat.src/heltun-hls01-thermostat.groovy b/devicetypes/heltun/heltun-hls01-thermostat.src/heltun-hls01-thermostat.groovy new file mode 100644 index 00000000000..f6575d6bc3b --- /dev/null +++ b/devicetypes/heltun/heltun-hls01-thermostat.src/heltun-hls01-thermostat.groovy @@ -0,0 +1,441 @@ +/** + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HELTUN HLS01 Thermostat", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, ocfDeviceType: "oic.d.thermostat") { + capability "Energy Meter" + capability "Power Meter" + capability "Temperature Measurement" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Voltage Measurement" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", inClusters: "0x42,0x40,0x43", deviceJoinName: "HELTUN Thermostat" //model: "000A" + } + preferences { + input ( + title: "HE-HLS01 | HELTUN High Load Switch", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + if (it.title != null) { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + } + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + + +def updated() { + initialize() +} + +def initialize() { + runIn(3, "checkParam") +} + +def parse(String description) { + def cmd = zwave.parse(description) + if (cmd) { + return zwaveEvent(cmd) + } +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if ( needConfig ) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if ( state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue) { + state."$parameter".state = "configured" + } + else { + state."$parameter".state = "error" + } + configParam() +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def deviceMode = numToModeMap[cmd.mode.toInteger()] + sendEvent(name: "thermostatMode", data:[supportedThermostatModes: state.supportedModes], value: deviceMode) + //if mode is off -> change stepoint value to 0 + if (cmd.mode == 0) { + sendEvent(name: "heatingSetpoint", value: 0, unit: locaScale) + } + sendHubCommand(zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: cmd.mode.toInteger()).format()) //getSetpoint +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def typeTemperature = 1 + def map = [:] + if (typeTemperature == cmd.sensorType) { + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = locaScale + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + sendEvent(map) + }else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + sendEvent(map) + }else if (cmd.scale == 4) { + map.name = "voltage" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "V" + sendEvent(map) + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd) { + def state = (cmd.operatingState == 1) ? "heating" : "idle" //DeviceScale + sendEvent(name: "thermostatOperatingState", value: state) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def deviceTemp = cmd.scaledValue + def setPoint = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + def mode = modeToNumMap[device.currentValue("thermostatMode")] + if (mode == 0) {setPoint = 0} + sendEvent(name: "heatingSetpoint", value: setPoint, unit: locaScale) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) { + def tSupportedModes = [] + if(cmd.heat) { tSupportedModes << "heat" } + if(cmd.autoChangeover) { tSupportedModes << "autochangeover" } + if(cmd.dryAir) { tSupportedModes << "dryair" } + if(cmd.energySaveHeat) { tSupportedModes << "energysaveheat" } + if(cmd.away) { tSupportedModes << "away" } + if(cmd.off) { tSupportedModes << "off" } + state.supportedModes = tSupportedModes + sendEvent(name: "supportedThermostatModes", value: tSupportedModes, displayed: false) +} + +def setHeatingSetpoint(tValue) { + def cmds = [] + def mode = device.currentValue("thermostatMode") + def currentMode = modeToNumMap[mode] + def temp = state.heatingSetpoint = tValue.toDouble() //temp got fromm the app + def tempInC = (getTemperatureScale() == "F" ? roundC(fahrenheitToCelsius(temp)) : temp) //If not C, Convert to C + cmds << zwave.thermostatSetpointV2.thermostatSetpointSet(setpointType: currentMode, scale: 0, precision: 1, scaledValue: tempInC).format() + + // Sync temp, opState, setPoint + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: currentMode).format() + sendHubCommand(cmds) +} + +def setThermostatMode(String value) { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeSet(mode: modeToNumMap[value]).format() + cmds << zwave.thermostatModeV2.thermostatModeGet().format() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: modeToNumMap[value]).format() + sendHubCommand(cmds) +} + +def getNumToModeMap() { + [ + 0 : "off", + 1 : "heat", + 8 : "dryair", + 10 : "autochangeover", + 11 : "energysaveheat", + 13 : "away" + ] +} + +def getModeToNumMap() { + [ + "off": 0, + "heat": 1, + "dryair": 8, + "autochangeover": 10, + "energysaveheat": 11, + "away": 13 + ] +} + +def roundC (tempInC) { + return (Math.round(tempInC.toDouble() * 2))/2 +} + +def refresh() { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeGet().format() //get thermostatmode + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() //Temperature + cmds << zwave.meterV3.meterGet(scale: 0).format() //get kWh + cmds << zwave.meterV3.meterGet(scale: 2).format() //get Watts + cmds << zwave.meterV3.meterGet(scale: 4).format() //get Voltage + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() //get Thermostat Operating State + cmds << zwave.clockV1.clockGet().format() //get clock + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() //get channel association + cmds << zwave.thermostatModeV2.thermostatModeSupportedGet().format() //get supported modes + sendHubCommand(cmds, 1200) + runIn(10, "checkParam") +} + +def ping() { + refresh() +} + +def configure() { + ping() +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [zwaveHubNodeId]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = Calendar.getInstance(location.timeZone) + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)){ + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +def off() { + setThermostatMode("off") +} + +def heat() { + setThermostatMode("heat") +} + +def emergencyHeat() { + setThermostatMode("emergencyHeat") +} + +private parameterMap() {[ +[title: "Relay Output Mode", description: "This Parameter determines the type of load connected to the device relay output. The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum"], + +[title: "External Input Mode", description: "This parameter defines how the thermostat should react when pressing the button connected to the external input. The options are: Disabled, Toggle Switch: if the external input is shorted (with Sx or Line) the Thermostat switches to the operating mode selected in the External Input Action bellow and switches to OFF mode when the external input is open, Toggle Switch Reverse: Toggle Switch Reverse” mode: if the external input is shorted the Thermostat switches to OFF mode and switches to the operating mode selected in the External Input Action bellow when the input is open, Momentary Switch: each press of button (shorten of input) will consistently change the mode to the operating mode selected in External Input Action bellow", + name: "Selected External Input Mode", options: [ + 0: "Disabled", + 1: "Toggle Switch", + 2: "Toggle Switch Reverse", + 3: "Momentary Switch" + ], paramNum: 8, size: 1, default: "0", type: "enum"], + +[title: "External Input Action", description: "This parameter allows selection of which Operating Mode the HE-HLS01 should revert to when the external input is shorted.", + name: "Selected External Input Action", options: [ + 1: "Heat", + 2: "Auto Cangeover", + 3: "Dry Air", + 4: "Energy Save Heat", + 5: "Away" + ], paramNum: 9, size: 1, default: "1", type: "enum"], + +[title: "Floor Sensor Resistance", description: "If an external floor NTC temperature sensor is used it is necessary to select the correct resistance value in kiloOhms (kΩ) of the sensor", + name: "Selected Floor Resistance in kΩ", paramNum: 10, size: 1, default: 10, type: "number", min: 1, max: 100, unit: "kΩ"], + +[title: "Temperature Sensor Calibration", description: "This Parameter defines the offset value for floor temperature. This value will be added or subtracted from the floor temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 17, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + +[title: "Temperature Hysteresis", description: "This Parameter defines the hysteresis value for temperature control. The HE-HLS01 will stabilize the temperature with selected hysteresis. For example, if the SET POINT is set for 25°C and HYSTERESIS is set for 0.5°C the HE-HLS01 will change the state to IDLE when the temperature reaches 25.0°C, but it will change the state to HEATING if the temperature drops lower than 24.5°C.The value of this Parameter should be x10 e.g. for 0.5°C set the value 5.", + name: "Selected Hysteresis in °Cx10", paramNum: 18, size: 1, default: 5, type: "number", min: 2, max: 100, unit: " °Cx10"], + +[title: "Dry Mode Timeout", description: "By choosing Dry Mode, the device will increase the temperature to the selected Set Point and keep it for the time specified in this parameter. A time range of 1 to 720 minutes (12 hours) can be set. As the Dry Time passes, the Thermostat will automatically change to the Mode set in the 'Mode to Switch After Dry Mode Operation Complete' configuration bellow.", + name: "Selected Dry Mode Timeout in minutes", paramNum: 25, size: 2, default: 30, type: "number", min: 1, max: 270, unit: "min"], + +[title: "Mode to Switch After Dry Mode Operation Complete", description: "This Parameter indicates the mode that will be set after Dry Time.", + name: "Selected Mode to Switch", options: [ + 1: "Heat", + 2: "Auto Cangeover", + 4: "Energy Save Heat", + 5: "Away", + 6: "Off" + ], paramNum: 26, size: 1, default: "1", type: "enum"], + +[title: "Schedule Time", description: "Use these Parameters to set the Morning, Day, Evening and Night start times manually for the Temperature Schedule. The value of these Parameters has format HHMM, e.g. for 08:00 use value 0800 (time without a colon). From 00:00 to 23:59 can be selected.", + name: "Selected Morning Start Time", paramNum: 41, size: 2, default: 600, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Day Start Time", paramNum: 42, size: 2, default: 900, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Evening Start Time", paramNum: 43, size: 2, default: 1800, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Night Start Time", paramNum: 44, size: 2, default: 2300, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[title: "Schedule Temperature", description: "Use these Parameters to set the temperature for each day Schedule manually. The value of this Parameter should be x10, e.g., for 22.5°C set value 225. From 1°C (value 10) to 110°C (value 1100) can be selected.", + name: "Monday Morning Temperature in °Cx10", paramNum: 45, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Monday Day Temperature in °Cx10", paramNum: 46, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Monday Evening Temperature in °Cx10", paramNum: 47, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Monday Night Temperature in °Cx10", paramNum: 48, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Tuesday Morning Temperature in °Cx10", paramNum: 49, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Tuesday Day Temperature in °Cx10", paramNum: 50, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Tuesday Evening Temperature in °Cx10", paramNum: 51, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Tuesday Night Temperature in °Cx10", paramNum: 52, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Wednesday Morning Temperature in °Cx10", paramNum: 53, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Wednesday Day Temperature in °Cx10", paramNum: 54, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Wednesday Evening Temperature in °Cx10", paramNum: 55, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Wednesday Night Temperature in °Cx10", paramNum: 56, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Thursday Morning Temperature in °Cx10", paramNum: 57, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Thursday Day Temperature in °Cx10", paramNum: 58, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Thursday Evening Temperature in °Cx10", paramNum: 59, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Thursday Night Temperature in °Cx10", paramNum: 60, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Friday Morning Temperature in °Cx10", paramNum: 61, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Friday Day Temperature in °Cx10", paramNum: 62, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Friday Evening Temperature in °Cx10", paramNum: 63, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Friday Night Temperature in °Cx10", paramNum: 64, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Saturday Morning Temperature in °Cx10", paramNum: 65, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Saturday Day Temperature in °Cx10", paramNum: 66, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Saturday Evening Temperature in °Cx10", paramNum: 67, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Saturday Night Temperature in °Cx10", paramNum: 68, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Sunday Morning Temperature in °Cx10", paramNum: 69, size: 2, default: 240, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Sunday Day Temperature in °Cx10", paramNum: 70, size: 2, default: 200, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Sunday Evening Temperature in °Cx10", paramNum: 71, size: 2, default: 230, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[name: "Sunday Night Temperature in °Cx10", paramNum: 72, size: 2, default: 180, type: "number", min: 10, max: 1100, unit: " °Cx10"], + +[title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Energy Consumption Meter Report", description: "This Parameter determines the change in the load power resulting in the consumption report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Change Percentage", paramNum: 142, size: 1, default: 25, type: "number", min: 0 , max: 50, unit: "%"], + +[title: "Sensors Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends to the gateway reports from its external NTC temperature sensor even if there are not changes in the values. This Parameter defines the interval between consecutive reports", + name: "Selected Energy Report Interval in minutes", paramNum: 143, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "External Temperature Sensor Report Threshold", description: "This Parameter determines the change in temperature level resulting in temperature sensors report being sent to the gateway. The value of this Parameter should be x10 for °C, e.g. for 0.4°C use value 4. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Threshold in °Cx10", paramNum: 144, size: 1, default: 2, type: "number", min: 0 , max: 100, unit: " °Cx10"], + +[title: "Overheat Protection", description: "You can define the maximum limit of temperature, reaching which the device will automatically switch Off the load. Use the value 0 if there is a need to disable this function", + name: "Selected Limit in °C", paramNum: 153, size: 2, default: 60, type: "number", min: 0 , max: 120, unit: " °C"], + +[title: "Over-Load Protection", description: "You can define the maximum power in Watt for connected load. The device will automatically switch off the output if the power consumed by the connected load exceeds this limit. Use the value 0 if there is a need to disable this function.", + name: "Selected Limit in Watts", paramNum: 155, size: 2, default: 3500, type: "number", min: 0 , max: 4000, unit: "W"], + +[title: "Over-Voltage Protection", description: "The device constantly monitors the voltage of your electricity network. You can define the maximum voltage of network exceeding which the device will automatically switch off the output. Use the value 0 if there is a need to disable this function.", + name: "Selected Upper Limit in Volts", paramNum: 156, size: 2, default: 260, type: "number", min: 120 , max: 280, unit: "V"], + +[title: "Voltage Drop Protection", description: "You can define the minimum voltage of your electricity network. If the voltage of the network drops bellow the determined level the device will automatically switch off the output. Use the value 0 if there is a need to disable this function.", + name: "Selected Lower Limit in Volts", paramNum: 157, size: 2, default: 90, type: "number", min: 80 , max: 240, unit: "V"], + +]} \ No newline at end of file From d7d342be832359b3272476e348115cd0d515dc9f Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Tue, 7 Dec 2021 01:05:53 +0400 Subject: [PATCH 092/184] DevWs for HELTUN containing containing HE-HT01 Handler X (#76617) * DevWs for HELTUN containing containing HE-HT01 Handler X * child device * Reformatting remove HubActions Separated getModeMap * Formmating * changes in parameters description * fixed formatting Co-authored-by: Artur Sargsyan --- .../he-temperature.src/he-temperature.groovy | 27 + .../heltun-ht01-thermostat.groovy | 539 ++++++++++++++++++ 2 files changed, 566 insertions(+) create mode 100644 devicetypes/heltun/he-temperature.src/he-temperature.groovy create mode 100644 devicetypes/heltun/heltun-ht01-thermostat.src/heltun-ht01-thermostat.groovy diff --git a/devicetypes/heltun/he-temperature.src/he-temperature.groovy b/devicetypes/heltun/he-temperature.src/he-temperature.groovy new file mode 100644 index 00000000000..f5e3458ceb4 --- /dev/null +++ b/devicetypes/heltun/he-temperature.src/he-temperature.groovy @@ -0,0 +1,27 @@ +/** + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HE-TEMPERATURE", namespace: "HELTUN", author: "Sarkis Kabrailian", ocfDeviceType: "oic.d.thermostat") { + capability "Temperature Measurement" + } +} + +def ping() { + parent.refresh() +} + +def refresh() { + parent.refresh() +} + diff --git a/devicetypes/heltun/heltun-ht01-thermostat.src/heltun-ht01-thermostat.groovy b/devicetypes/heltun/heltun-ht01-thermostat.src/heltun-ht01-thermostat.groovy new file mode 100644 index 00000000000..141d5b7e8dd --- /dev/null +++ b/devicetypes/heltun/heltun-ht01-thermostat.src/heltun-ht01-thermostat.groovy @@ -0,0 +1,539 @@ +/** + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HELTUN HT01 Thermostat", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, ocfDeviceType: "oic.d.thermostat", mcdSync: true) { + capability "Energy Meter" + capability "Power Meter" + capability "Relative Humidity Measurement" + capability "Temperature Measurement" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Illuminance Measurement" + capability "Voltage Measurement" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", model: "0001", deviceJoinName: "HELTUN Thermostat" + } + preferences { + input ( + title: "HE-HT01 | HELTUN Heating Thermostat", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + if (it.title != null) { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + } + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + +private channelNumber(String N) { + N.split(":")[-1] as Integer +} + +def installed() { + state.oldLabel = device.label + def childName = "${device.displayName} Floor Temperature" + def existingChildren = getChildDevices() + def floorTemperatureid = "${device.deviceNetworkId}:${1}" + def childExists = (existingChildren.find {child -> child.getDeviceNetworkId() == floorTemperatureid} != NULL) + if (!childExists) { + addChildDevice("HE-TEMPERATURE", floorTemperatureid, device.hubId,[completedSetup: true, label: childName, isComponent: true, componentName: "FloorTemperature", componentLabel: "FloorTemperature"]) + } +} + +def parse(String description) { + def cmd = zwave.parse(description) + if (cmd) { + return zwaveEvent(cmd) + } +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if ( needConfig ) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if ( state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue){ + state."$parameter".state = "configured" + } + else { + state."$parameter".state = "error" + } + configParam() +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def deviceMode = numToModeMap[cmd.mode.toInteger()] + sendEvent(name: "thermostatMode", data:[supportedThermostatModes: state.supportedModes], value: deviceMode) + //if mode is off -> change stepoint value to 0 + if (cmd.mode == 0) { + sendEvent(name: "heatingSetpoint", value: 0, unit: locaScale) + } + sendHubCommand(zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: cmd.mode.toInteger()).format()) //getSetpoint +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + def floorTemperature = 24 + def roomTemperature = 1 + def himidity = 5 + def illuminance = 3 + def locaScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def child = childDevices?.find {channelNumber(it.deviceNetworkId) == 1 } + if (roomTemperature == cmd.sensorType) { + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = locaScale + sendEvent(map) + } else if (floorTemperature == cmd.sensorType) { + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = locaScale + child?.sendEvent(map) + } else if (himidity == cmd.sensorType) { + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + sendEvent(map) + } else if (illuminance == cmd.sensorType) { + map.name = "illuminance" + map.value = cmd.scaledSensorValue + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + } else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + }else if (cmd.scale == 4) { + map.name = "voltage" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "V" + } + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd) { + def state = (cmd.operatingState == 1) ? "heating" : "idle" + sendEvent(name: "thermostatOperatingState", value: state) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { + def locaScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def deviceTemp = cmd.scaledValue + def setPoint = (deviceScale == locaScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + def mode = modeToNumMap[device.currentValue("thermostatMode")] + if (mode == 0) {setPoint = 0} + sendEvent(name: "heatingSetpoint", value: setPoint, unit: locaScale) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) { + def tSupportedModes = [] + if(cmd.heat) { tSupportedModes << "heat" } + if(cmd.autoChangeover) { tSupportedModes << "autochangeover" } + if(cmd.dryAir) { tSupportedModes << "dryair" } + if(cmd.energySaveHeat) { tSupportedModes << "energysaveheat" } + if(cmd.away) { tSupportedModes << "away" } + if(cmd.off) { tSupportedModes << "off" } + state.supportedModes = tSupportedModes + sendEvent(name: "supportedThermostatModes", value: tSupportedModes, displayed: false) +} + +def setHeatingSetpoint(tValue) { + def cmds = [] + def mode = device.currentValue("thermostatMode") + def currentMode = modeToNumMap[mode] + def temp = state.heatingSetpoint = tValue.toDouble() //temp got fromm the app + def tempInC = (getTemperatureScale() == "F" ? roundC(fahrenheitToCelsius(temp)) : temp) //If not C, Convert to C + cmds << zwave.thermostatSetpointV2.thermostatSetpointSet(setpointType: currentMode, scale: 0, precision: 1, scaledValue: tempInC).format() + // Sync temp, opState, setPoint + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: currentMode).format() + sendHubCommand(cmds) +} + +def setThermostatMode(String value) { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeSet(mode: modeToNumMap[value]).format() + cmds << zwave.thermostatModeV2.thermostatModeGet().format() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: modeToNumMap[value]).format() + sendHubCommand(cmds) +} + +def getNumToModeMap() { + [ + 0 : "off", + 1 : "heat", + 8 : "dryair", + 10 : "autochangeover", + 11 : "energysaveheat", + 13 : "away" + ] +} + +def getModeToNumMap() { + [ + "off": 0, + "heat": 1, + "dryair": 8, + "autochangeover": 10, + "energysaveheat": 11, + "away": 13 + ] +} + +def roundC (tempInC) { + return (Math.round(tempInC.toDouble() * 2))/2 +} + +def updated() { + def childName = "${device.displayName} Floor Temperature" + if (childDevices && device.label != state.oldLabel) { + childDevices.each {it.setLabel(childName)} + state.oldLabel = device.label + } + initialize() +} + +def initialize() { + runIn(3, "checkParam") +} + +def ping() { + refresh() +} + +def refresh() { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeGet().format() //get thermostatmode + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() //roomTemperature + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:24).format() //floorTemperature + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3).format() //Humidity + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5).format() //Illuminance + cmds << zwave.meterV3.meterGet(scale: 0).format() //get kWh + cmds << zwave.meterV3.meterGet(scale: 2).format() //get Watts + cmds << zwave.meterV3.meterGet(scale: 4).format() //get Voltage + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() //get Thermostat Operating State + cmds << zwave.clockV1.clockGet().format() //get Clock + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() //get channel association + cmds << zwave.thermostatModeV2.thermostatModeSupportedGet().format() //get supported modes + sendHubCommand(cmds, 1200) + runIn(15, "checkParam") +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [1]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: 1).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def configure() { + ping() +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = Calendar.getInstance(location.timeZone) + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)){ + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +def off() { + setThermostatMode("off") +} + +def heat() { + setThermostatMode("heat") +} + +def emergencyHeat() { + setThermostatMode("emergencyHeat") +} + +private parameterMap() {[ +[title: "Display Brightness Control", description: "The HE-HT01 can adjust its display brightness automatically depending on the illumination of the ambient environment and also allows to control it manually.", + name: "Selected Brightness Level", options: [ + 0: "Auto", + 1: "Level 1 (Lowest)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (Highest)" + ], paramNum: 5, size: 1, default: "0", type: "enum"], + +[title: "Touch Sensor Sensitivity Threshold", description: "This Parameter allows to adjust the Touch Buttons Sensitivity. Note: Setting the sensitivity too high can lead to false touch detection. We recommend not changing this Parameter unless there is a special need to do so.", + name: "Selected Touch Sensitivity", options: [ + 1: "Level 1 (Low sensitivity)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (High sensitivity)" + ], paramNum: 6, size: 1, default: "6", type: "enum"], + +[title: "Relay Output Mode", description: "This Parameter determines the type of load connected to the device relay output. The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum"], + +[title: "External Input Mode", description: "This parameter defines how the thermostat should react when pressing the button connected to the external input. The options are: Disabled, Toggle Switch: if the external input is shorted (with Sx or Line) the Thermostat switches to the operating mode selected in the External Input Action bellow and switches to OFF mode when the external input is open, Toggle Switch Reverse: Toggle Switch Reverse” mode: if the external input is shorted the Thermostat switches to OFF mode and switches to the operating mode selected in the External Input Action bellow when the input is open, Momentary Switch: each press of button (shorten of input) will consistently change the mode to the operating mode selected in External Input Action bellow", + name: "Selected External Input Mode", options: [ + 0: "Disabled", + 1: "Toggle Switch", + 2: "Toggle Switch Reverse", + 3: "Momentary Switch" + ], paramNum: 8, size: 1, default: "0", type: "enum"], + +[title: "External Input Action", description: "This parameter allows selection of which Operating Mode the HE-HT01 should revert to when the external input is shorted.", + name: "Selected External Input Action", options: [ + 1: "Heat", + 2: "Auto Cangeover", + 3: "Dry Air", + 4: "Energy Save Heat", + 5: "Away", + 6: "Off" + ], paramNum: 9, size: 1, default: "6", type: "enum"], + +[title: "Source Sensor", description: "1) A – Air sensor: Regulation (heating control) is based on the SET POINT applied to the internal room air temperature sensor. 2) AF – Air sensor plus floor sensor: Regulation is based on SET POINT applied to the internal room temperature sensor but also controlled by the floor temperature sensor ensuring that the floor temperature remains within the floor temperature limits specified bellow. 3) F – Floor sensor: Regulation is based on the SET POINT applied to the external floor temperature sensor. 4) FA – Floor sensor plus air sensor: Regulation is based on SET POINT applied to the external floor sensor but is also controlled by the internal air temperature sensor ensuring that the air temperature remains within the air temperature limits specified bellow. 5) t – Time regulator: Regulation is based on the time settings for heating which will be ON during the (ON time) and OFF during the (OFF Time) specified in the configurations bellow. This cycle will be repeated constantly. 6) tA – Time regulator + Air sensor: Regulation is based on the ON & OFF times specified in the configurations bellow but also controlled by the internal air temperature sensor ensuring that the room temperature remains within the air temperature limits specified bellow. 7) tF – Time regulator + Floor sensor Parameters: Regulation is based on the ON & OFF times specified in the configurations bellow but also controlled by the floor temperature sensor ensuring that the floor temperature remains within the floor temperature limits specified bellow.", + name: "Selected Source Sensor", options: [ + 1: "Air Sensor", + 2: "Air + Floor Sensors", + 3: "Floor Sensor", + 4: "Floor + Air Sensors", + 5: "Time Regulator", + 6: "Time + Air Sensor", + 7: "Time + Floor Sensor" + ], paramNum: 11, size: 1, default: "3", type: "enum"], + +[name: "Air Temperature Minimum in °Cx10", paramNum: 12, size: 2, default: 210, type: "number", min: 10, max: 360, unit: " °Cx10"], + +[name: "Air Temperature Maximum in °Cx10", paramNum: 13, size: 2, default: 270, type: "number", min: 20, max: 370, unit: " °Cx10"], + +[name: "Floor Temperature Minimum in °Cx10", paramNum: 14, size: 2, default: 180, type: "number", min: 10, max: 360, unit: " °Cx10"], + +[name: "Floor Temperature Maximum in °Cx10", paramNum: 15, size: 2, default: 320, type: "number", min: 20, max: 370, unit: " °Cx10"], + +[name: "Time Regulation ON Time in minutes", paramNum: 23, size: 2, default: 30, type: "number", min: 10, max: 240, unit: "min"], + +[name: "Time Regulation OFF Time in minutes", paramNum: 24, size: 2, default: 30, type: "number", min: 20, max: 240, unit: "min"], + +[title: "Floor Sensor Resistance", description: "If an external floor NTC temperature sensor is used it is necessary to select the correct resistance value in kiloOhms (kΩ) of the sensor", + name: "Selected Floor Resistance in kΩ", paramNum: 10, size: 1, default: 10, type: "number", min: 1, max: 100, unit: "kΩ"], + +[title: "Floor Temperature Calibration", description: "This Parameter defines the offset value for floor temperature. This value will be added or subtracted from the floor temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 16, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + +[title: "Air Temperature Calibration", description: "This Parameter defines the offset value for room air temperature. This value will be added or subtracted from the air temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 17, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + +[title: "Temperature Hysteresis", description: "This Parameter defines the hysteresis value for temperature control. The HE-HT01 will stabilize the temperature with selected hysteresis. For example, if the SET POINT is set for 25°C and HYSTERESIS is set for 0.5°C the HE-HT01 will change the state to IDLE when the temperature reaches 25.0°C, but it will change the state to HEATING if the temperature drops lower than 24.5°C.The value of this Parameter should be x10 e.g. for 0.5°C set the value 5.", + name: "Selected Hysteresis in °Cx10", paramNum: 18, size: 1, default: 5, type: "number", min: 2, max: 100, unit: " °Cx10"], + +[title: "Dry Time", description: "By choosing Dry Mode, the device will increase the temperature to the selected Set Point and keep it for the time specified in this parameter. A time range of 1 to 720 minutes (12 hours) can be set. As the Dry Time passes, the Thermostat will automatically change to the Mode set in the 'Mode to Switch After Dry Mode Operation Complete' configuration bellow.", + name: "Selected Dry Time in minutes", paramNum: 25, size: 2, default: 30, type: "number", min: 5, max: 90, unit: "min"], + +[title: "Mode to Switch After Dry Mode Operation Complete", description: "This Parameter indicates the mode that will be set after Dry Time.", + name: "Selected Mode to Switch", options: [ + 1: "Heat", + 2: "Auto Cangeover", + 4: "Energy Save Heat", + 5: "Away", + 6: "Off" + ], paramNum: 26, size: 1, default: "1", type: "enum"], + +[title: "Child Lock Restriction Level", description: "This parameter specifies the restriction level of Child Lock feature where it allows you to choose which touch buttons/features of HE-HT01 should be disabled temporarily while the device is locked. Choosing level 1 will lock all the buttons, choosing level 2 will let you change the setpoint and lock the remaining buttons, choosing level 3 will let you change the setpoint and the operating mode, and lock the remaining buttons. This parameter is available on firmware V2.4 or higher", + name: "Selected Restriction Level", options: [ + 1: "level 1 (Strictest)", + 2: "level 2", + 3: "level 3 (least strict)" + ], paramNum: 40, size: 1, default: "1", type: "enum"], + +[title: "Schedule Time", description: "Use these Parameters to set the Morning, Day, Evening and Night start times manually for the Temperature Schedule. The value of these Parameters has format HHMM, e.g. for 08:00 use value 0800 (time without a colon). From 00:00 to 23:59 can be selected.", + name: "Selected Morning Start Time", paramNum: 41, size: 2, default: 600, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Day Start Time", paramNum: 42, size: 2, default: 900, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Evening Start Time", paramNum: 43, size: 2, default: 1800, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Night Start Time", paramNum: 44, size: 2, default: 2300, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[title: "Schedule Temperature", description: "Use these Parameters to set the temperature for each day Schedule manually. The value of this Parameter should be x10, e.g., for 22.5°C set value 225. From 1°C (value 10) to 110°C (value 1100) can be selected.", + name: "Monday Morning Temperature in °Cx10", paramNum: 45, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Day Temperature in °Cx10", paramNum: 46, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Evening Temperature in °Cx10", paramNum: 47, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Night Temperature in °Cx10", paramNum: 48, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Morning Temperature in °Cx10", paramNum: 49, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Day Temperature in °Cx10", paramNum: 50, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Evening Temperature in °Cx10", paramNum: 51, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Night Temperature in °Cx10", paramNum: 52, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Morning Temperature in °Cx10", paramNum: 53, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Day Temperature in °Cx10", paramNum: 54, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Evening Temperature in °Cx10", paramNum: 55, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Night Temperature in °Cx10", paramNum: 56, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Morning Temperature in °Cx10", paramNum: 57, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Day Temperature in °Cx10", paramNum: 58, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Evening Temperature in °Cx10", paramNum: 59, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Night Temperature in °Cx10", paramNum: 60, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Morning Temperature in °Cx10", paramNum: 61, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Day Temperature in °Cx10", paramNum: 62, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Evening Temperature in °Cx10", paramNum: 63, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Night Temperature in °Cx10", paramNum: 64, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Morning Temperature in °Cx10", paramNum: 65, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Day Temperature in °Cx10", paramNum: 66, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Evening Temperature in °Cx10", paramNum: 67, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Night Temperature in °Cx10", paramNum: 68, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Morning Temperature in °Cx10", paramNum: 69, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Day Temperature in °Cx10", paramNum: 70, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Evening Temperature in °Cx10", paramNum: 71, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Night Temperature in °Cx10", paramNum: 72, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Energy Consumption Meter Report", description: "This Parameter determines the change in the load power resulting in the consumption report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Change Percentage", paramNum: 142, size: 1, default: 25, type: "number", min: 0 , max: 50, unit: "%"], + +[title: "Sensors Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends to the gateway reports from its external NTC temperature sensor even if there are not changes in the values. This Parameter defines the interval between consecutive reports", + name: "Selected Energy Report Interval in minutes", paramNum: 143, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Air & Floor Temperature Sensors Report Threshold", description: "This Parameter determines the change in temperature level (in °C) resulting in temperature sensors report being sent to the gateway. The value of this Parameter should be x10 for °C, e.g. for 0.4°C use value 4. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Temperature Threshold in °Cx10", paramNum: 144, size: 1, default: 2, type: "number", min: 0 , max: 100, unit: " °Cx10"], + +[title: "Humidity Sensor Report Threshold", description: "This Parameter determines the change in humidity level in % resulting in humidity sensors report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Humidity Threshold in %", paramNum: 145, size: 1, default: 2, type: "number", min: 0 , max: 25, unit: "%"], + +[title: "Light Sensor Report Threshold", description: "This Parameter determines the change in the ambient environment illuminance level resulting in a light sensors report being sent to the gateway. From 10% to 99% can be selected. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Light Sensor Threshold in %", paramNum: 146, size: 1, default: 50, type: "number", min: 0 , max: 99, unit: "%"] + +]} \ No newline at end of file From e6c9affb7a15e486a53c6d27478b454ea486a17a Mon Sep 17 00:00:00 2001 From: jwg-123 <51741592+jwg-123@users.noreply.github.com> Date: Tue, 7 Dec 2021 17:39:12 +0800 Subject: [PATCH 093/184] DevWs for www.easyiot.tech containing containing ZigBee RGBW Bulb (#76714) * DevWs for www.easyiot.tech containing containing ZigBee RGBW Bulb Co-authored-by: jiang wegang --- .../smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 17001cf5738..65dadbc811a 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -105,6 +105,8 @@ metadata { fingerprint manufacturer: "Ajax online Ltd", model: "AJ_ZB30_GU10", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" // Raw Description: 0B 0104 010D 01 08 0000 0003 0004 0005 0006 0008 0300 1000 00 // Shenzhen C-Lux fingerprint manufacturer: "Shenzhen C-Lux", model: "CL000ZB", deviceJoinName: "C-Lux Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" + // www.easyiot.tech + fingerprint manufacturer: "eWeLight", model: "ZB-CL01", deviceJoinName: "easyiot Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" } // UI tile definitions From 385a42c2242fc911283d906c7f4ecaf47f3b62cd Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Thu, 9 Dec 2021 17:53:21 +0900 Subject: [PATCH 094/184] DevWs for SHINA SYSTEM containing containing ZigBee Lock Without Codes (#76888) --- .../zigbee-lock-without-codes.groovy | 1 + 1 file changed, 1 insertion(+) 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 index 36626a03291..bc718e0efb3 100644 --- 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 @@ -28,6 +28,7 @@ metadata { fingerprint profileId:"0104, 000A", inClusters:"0000, 0001, 0003, 0009, 0020,0101, 0B05", outclusters:"000A, 0019, 0B05", manufacturer:"Danalock", model:"V3-BTZB", deviceJoinName:"Danalock Door Lock" //Danalock V3 Smart Lock fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0500, 0101", outClusters: "0019", model: "E261-KR0B0Z0-HA", deviceJoinName: "C2O Door Lock", mnmn: "SmartThings", vid: "C2O-ZigBee-Lock" //C2O Lock + fingerprint profileId:"0104", inClusters:"0000, 0001, 0003, 0020,0101", outclusters:"0003,0004, 0019", manufacturer:"ShinaSystem", model:"DLM-300Z", deviceJoinName:"SiHAS Door Lock" //SiHAS Door Lock } From 329411950001a24a6eac6b5dac55749b2b1157ba Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 21 Dec 2021 18:33:03 +0800 Subject: [PATCH 095/184] DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch (#77178) * DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch * Add my fingerprint based on the latest code in the main repository * In the DTH file "Z-Wave Metering Switch", we have added support for anther new product (ZW38M). * delete the fingerprint for ZW38M, we'll add it at the next update. Co-authored-by: Winnie Wen --- .../zwave-metering-switch.src/zwave-metering-switch.groovy | 1 + 1 file changed, 1 insertion(+) 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 170107bfdba..5fa98c6b5ca 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -53,6 +53,7 @@ metadata { fingerprint mfr: "0154", prod: "0003", model: "000A", deviceJoinName: "POPP Outlet", ocfDeviceType: "oic.d.smartplug" //EU //POPP Smart Outdoor Plug fingerprint mfr: "010F", prod: "1F01", model: "1000", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Fibaro walli Outlet //Fibaro Outlet fingerprint mfr: "0312", prod: "FF00", model: "FF0E", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP21ZP + fingerprint mfr: "0312", prod: "FF00", model: "FF0F", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP22ZP } // simulator metadata From acdd873187705e857cf7010529aa04946bd249df Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 21 Dec 2021 20:06:43 +0900 Subject: [PATCH 096/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#76887) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * Update sihas-multipurpose-sensor.groovy remove unnecessary space. --- .../sihas-multipurpose-sensor.groovy | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index 94ca4fef5ce..d94e8d9a213 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -29,12 +29,13 @@ metadata { capability "Sensor" capability "Contact Sensor" capability "afterguide46998.peopleCounter" + capability "afterguide46998.inOutDirection" fingerprint inClusters: "0000,0001,0003,0020,0400,0402,0405,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "USM-300Z", deviceJoinName: "SiHAS MultiPurpose Sensor", mnmn: "SmartThings", vid: "generic-motion-6" fingerprint inClusters: "0000,0001,0003,0020,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "OSM-300Z", deviceJoinName: "SiHAS Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2", ocfDeviceType: "x.com.st.d.sensor.motion" fingerprint inClusters: "0000,0003,0402,0001,0405", outClusters: "0004,0003,0019", manufacturer: "ShinaSystem", model: "TSM-300Z", deviceJoinName: "SiHAS Temperature/Humidity Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Temp/Humidity_Sensor", ocfDeviceType: "oic.d.thermostat" fingerprint inClusters: "0000,0001,0003,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "DSM-300Z", deviceJoinName: "SiHAS Contact Sensor", mnmn: "SmartThings", vid: "generic-contact-3", ocfDeviceType: "x.com.st.d.sensor.contact" - fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "15962fd0-22b8-352e-9641-de640d672bb6", ocfDeviceType: "x.com.st.d.sensor.motion" + fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "23d6139c-b108-3467-9ddb-6a177d6cc1df", ocfDeviceType: "x.com.st.d.sensor.motion" } preferences { section { @@ -198,13 +199,26 @@ private Map getContactResult(value) { } private Map getAnalogInputResult(value) { - Float f = Float.intBitsToFloat(value.intValue()) - int pc = f.round(0) - String descriptionText = "${device.displayName} : $pc" + Float fpc = Float.intBitsToFloat(value.intValue()) + def prevInOut = device.currentState('inOutDir')?.value + int pc = ((int)(fpc*10))/10 //people counter + int inout = ((int)(fpc*10).round(0))%10; // inout direction : .1 = in, .2 = out, .0 = ready + if(inout>2) inout = 2 + String inoutString = ( (inout==1) ? "in" : (inout==2) ? "out":"ready") + String descriptionText1 = "${device.displayName} : $pc" + String descriptionText2 = "${device.displayName} : $inoutString" + log.debug "[$fpc] = people: $pc, dir: $inout, $inoutString" + + if((inout != "ready") && (prevInOut == inoutString)) { + sendEvent(name: "inOutDir", value: "ready", displayed: true) + } + + sendEvent(name: "peopleCounter", value: pc, displayed: true, descriptionText: descriptionText1 ) + return [ - name : 'peopleCounter', - value : pc, - descriptionText: descriptionText, + name : 'inOutDir', + value : inoutString, + descriptionText: descriptionText2, translatable : true ] } From c71525492410622f197f3f908bf04983d76eda04 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 22 Dec 2021 19:36:07 +0800 Subject: [PATCH 097/184] DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch (#77205) * DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch * add support for ZW38M Co-authored-by: Winnie Wen --- .../zwave-metering-switch.src/zwave-metering-switch.groovy | 1 + 1 file changed, 1 insertion(+) 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 5fa98c6b5ca..102b4f7ba1e 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -54,6 +54,7 @@ metadata { fingerprint mfr: "010F", prod: "1F01", model: "1000", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Fibaro walli Outlet //Fibaro Outlet fingerprint mfr: "0312", prod: "FF00", model: "FF0E", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP21ZP fingerprint mfr: "0312", prod: "FF00", model: "FF0F", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP22ZP + fingerprint mfr: "0312", prod: "FF00", model: "FF11", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Power Meter Plug, ZW38M } // simulator metadata From b2414dc352ccbdd00038366f147708f1d0b3d831 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Thu, 30 Dec 2021 16:13:13 +0800 Subject: [PATCH 098/184] DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch (#77211) * DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Metering Switch * add new product supported for N4003 Co-authored-by: Winnie Wen --- .../zwave-metering-switch.src/zwave-metering-switch.groovy | 1 + 1 file changed, 1 insertion(+) 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 102b4f7ba1e..5e42d7558a4 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -55,6 +55,7 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF0E", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP21ZP fingerprint mfr: "0312", prod: "FF00", model: "FF0F", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Smart Plug Meter, MP22ZP fingerprint mfr: "0312", prod: "FF00", model: "FF11", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Power Meter Plug, ZW38M + fingerprint mfr: "0312", prod: "AC01", model: "4003", deviceJoinName: "New One Outlet", ocfDeviceType: "oic.d.smartplug" //Mini Power Meter Plug, N4003 } // simulator metadata From fbf4a2dbec5e292f11f5d65441e7d77751658155 Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Tue, 4 Jan 2022 17:42:25 +0800 Subject: [PATCH 099/184] DevWs for CoolKit Technology Co.,Ltd containing containing eWeLink Button (#77263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 啦啦 王 --- devicetypes/smartthings/ikea-button.src/ikea-button.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy index b7a48ada477..3b0996944e6 100644 --- a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy +++ b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy @@ -33,7 +33,7 @@ metadata { fingerprint manufacturer: "KE", model: "TRADFRI open/close remote", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_open/close_remote" // raw description 01 0104 0203 01 07 0000 0001 0003 0009 0020 1000 FC7C 07 0003 0004 0006 0008 0019 0102 1000 //IKEA TRÅDFRI Open/Close Remote fingerprint manufacturer: "SOMFY", model: "Situo 4 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_Situo4_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 fingerprint manufacturer: "SOMFY", model: "Situo 1 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 - fingerprint inClusters: "0000, 0001, 0003", outClusters: "0003, 0006", manufacturer: "eWeLink", model: "WB01", deviceJoinName: "eWeLink Button" //eWeLink Button + fingerprint inClusters: "0000, 0001, 0003", outClusters: "0003, 0006", manufacturer: "eWeLink", model: "WB01", deviceJoinName: "eWeLink Button" //eWeLink Button WB01 fingerprint inClusters: "0000, 0001, 0003, 0020, FC57", outClusters: "0003, 0006, 0019", manufacturer: "eWeLink", model: "SNZB-01P", deviceJoinName: "eWeLink Button" //eWeLink Button } From 1366986462a5699e7d597307b43442e5c50d01d0 Mon Sep 17 00:00:00 2001 From: Tae kyun Lee <64769321+tklee2020@users.noreply.github.com> Date: Wed, 5 Jan 2022 03:37:51 +0900 Subject: [PATCH 100/184] DevWs for eZEX containing containing Zigbee Power Meter (#77221) * DevWs for eZEX containing containing Zigbee Power Meter * re organized indents * modified indent * modified indent * as requested, "import groovy.json.JsonSlurper" has been added Co-authored-by: TK LEE --- .../zigbee-power-meter.groovy | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy index 36b48b6e924..9aa0486afa6 100644 --- a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy +++ b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy @@ -1,3 +1,4 @@ + /** * Copyright 2019 SmartThings * @@ -12,6 +13,7 @@ * */ import physicalgraph.zigbee.zcl.DataType +import groovy.json.JsonSlurper metadata { definition (name: "Zigbee Power Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", vid: "SmartThings-smartthings-Aeon_Home_Energy_Meter") { @@ -21,6 +23,7 @@ metadata { capability "Health Check" capability "Sensor" capability "Configuration" + capability "Power Consumption Report" fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Energy Monitor" //Smart Sub-meter(CT Type) fingerprint profileId: "0104", deviceId:"0007", inClusters: "0000,0003,0702", outClusters: "000A", manufacturer: "Develco", model: "ZHEMI101", deviceJoinName: "frient Energy Monitor" // frient External Meter Interface (develco) 02 0104 0007 00 03 0000 0003 0702 01 000A @@ -104,6 +107,36 @@ def parse(String description) { map.name = "energy" map.value = zigbee.convertHexToInt(it.value)/(energyDivisor * 1000) map.unit = "kWh" + + if (isEZEX()) { + def currentEnergy = zigbee.convertHexToInt(it.value) / 1000 + def prevPowerConsumption = device.currentState("powerConsumption")?.value + Map previousMap = prevPowerConsumption ? new groovy.json.JsonSlurper().parseText(prevPowerConsumption) : [:] + def deltaEnergy = calculateDelta(currentEnergy, previousMap) + def currentTimestamp = Calendar.getInstance().timeInMillis + def prevTimestamp = device.currentState("powerConsumption")?.date?.time + if (prevTimestamp == null) prevTimestamp = 0L + def timeDiff = currentTimestamp - prevTimestamp + log.debug "currentTimestamp= $currentTimestamp, prevTimestamp= $prevTimestamp, timeDiff= $timeDiff" + log.debug "deltaEnergy= $deltaEnergy" + if (deltaEnergy < 0) { + Map reportMap = [:] + reportMap["energy"] = currentEnergy + reportMap["deltaEnergy"] = 0 + sendEvent("name": "powerConsumption", "value": reportMap.encodeAsJSON(), displayed: false) + } else { + if (timeDiff >= 15 * 60 * 1000) { + Map reportMap = [:] + reportMap["energy"] = currentEnergy + if (timeDiff < 24 * 60 * 60 * 1000) { + reportMap["deltaEnergy"] = deltaEnergy + } else { + reportMap["deltaEnergy"] = 0 + } + sendEvent("name": "powerConsumption", "value": reportMap.encodeAsJSON(), displayed: false) + } + } + } } } @@ -157,3 +190,17 @@ private Boolean isFrientSensor() { private Boolean isPMM300Z1() { device.getDataValue("model") == "PMM-300Z1" } + +private Boolean isEZEX() { + device.getDataValue("model") == "E240-KR080Z0-HA" +} + +BigDecimal calculateDelta(BigDecimal currentEnergy, Map previousMap) { + if (previousMap?.'energy' == null) { + log.debug "prevEnergy is null" + return 0 + } + BigDecimal lastAccumulated = BigDecimal.valueOf(previousMap['energy']) + log.debug "currentEnergy= $currentEnergy, prevEnergy= $lastAccumulated" + return currentEnergy.subtract(lastAccumulated) +} \ No newline at end of file From 6bad939acebc80ab058f2ec71d6e4da6467782db Mon Sep 17 00:00:00 2001 From: Tae kyun Lee <64769321+tklee2020@users.noreply.github.com> Date: Wed, 5 Jan 2022 03:37:51 +0900 Subject: [PATCH 101/184] DevWs for eZEX containing containing Zigbee Power Meter (#77221) * DevWs for eZEX containing containing Zigbee Power Meter * re organized indents * modified indent * modified indent * as requested, "import groovy.json.JsonSlurper" has been added Co-authored-by: TK LEE --- .../zigbee-power-meter.groovy | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy index 36b48b6e924..9aa0486afa6 100644 --- a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy +++ b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy @@ -1,3 +1,4 @@ + /** * Copyright 2019 SmartThings * @@ -12,6 +13,7 @@ * */ import physicalgraph.zigbee.zcl.DataType +import groovy.json.JsonSlurper metadata { definition (name: "Zigbee Power Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", vid: "SmartThings-smartthings-Aeon_Home_Energy_Meter") { @@ -21,6 +23,7 @@ metadata { capability "Health Check" capability "Sensor" capability "Configuration" + capability "Power Consumption Report" fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Energy Monitor" //Smart Sub-meter(CT Type) fingerprint profileId: "0104", deviceId:"0007", inClusters: "0000,0003,0702", outClusters: "000A", manufacturer: "Develco", model: "ZHEMI101", deviceJoinName: "frient Energy Monitor" // frient External Meter Interface (develco) 02 0104 0007 00 03 0000 0003 0702 01 000A @@ -104,6 +107,36 @@ def parse(String description) { map.name = "energy" map.value = zigbee.convertHexToInt(it.value)/(energyDivisor * 1000) map.unit = "kWh" + + if (isEZEX()) { + def currentEnergy = zigbee.convertHexToInt(it.value) / 1000 + def prevPowerConsumption = device.currentState("powerConsumption")?.value + Map previousMap = prevPowerConsumption ? new groovy.json.JsonSlurper().parseText(prevPowerConsumption) : [:] + def deltaEnergy = calculateDelta(currentEnergy, previousMap) + def currentTimestamp = Calendar.getInstance().timeInMillis + def prevTimestamp = device.currentState("powerConsumption")?.date?.time + if (prevTimestamp == null) prevTimestamp = 0L + def timeDiff = currentTimestamp - prevTimestamp + log.debug "currentTimestamp= $currentTimestamp, prevTimestamp= $prevTimestamp, timeDiff= $timeDiff" + log.debug "deltaEnergy= $deltaEnergy" + if (deltaEnergy < 0) { + Map reportMap = [:] + reportMap["energy"] = currentEnergy + reportMap["deltaEnergy"] = 0 + sendEvent("name": "powerConsumption", "value": reportMap.encodeAsJSON(), displayed: false) + } else { + if (timeDiff >= 15 * 60 * 1000) { + Map reportMap = [:] + reportMap["energy"] = currentEnergy + if (timeDiff < 24 * 60 * 60 * 1000) { + reportMap["deltaEnergy"] = deltaEnergy + } else { + reportMap["deltaEnergy"] = 0 + } + sendEvent("name": "powerConsumption", "value": reportMap.encodeAsJSON(), displayed: false) + } + } + } } } @@ -157,3 +190,17 @@ private Boolean isFrientSensor() { private Boolean isPMM300Z1() { device.getDataValue("model") == "PMM-300Z1" } + +private Boolean isEZEX() { + device.getDataValue("model") == "E240-KR080Z0-HA" +} + +BigDecimal calculateDelta(BigDecimal currentEnergy, Map previousMap) { + if (previousMap?.'energy' == null) { + log.debug "prevEnergy is null" + return 0 + } + BigDecimal lastAccumulated = BigDecimal.valueOf(previousMap['energy']) + log.debug "currentEnergy= $currentEnergy, prevEnergy= $lastAccumulated" + return currentEnergy.subtract(lastAccumulated) +} \ No newline at end of file From 54dacf6ed3dbbcee6ff9a915d146c1853a66fd76 Mon Sep 17 00:00:00 2001 From: Tae kyun Lee <64769321+tklee2020@users.noreply.github.com> Date: Wed, 5 Jan 2022 15:37:33 +0900 Subject: [PATCH 102/184] DevWs for eZEX containing containing ZigBee Switch and 1 more (#77207) * DevWs for eZEX containing containing ZigBee Switch and 1 more * Comments are modified Co-authored-by: TK LEE --- .../zigbee-multi-switch.groovy | 36 +++++++++++++++---- .../zigbee-switch.src/zigbee-switch.groovy | 8 +++-- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index 04194274d74..e9889fd7c2e 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -27,12 +27,24 @@ metadata { command "childOn", ["string"] command "childOff", ["string"] - // EZEX - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR2N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR3N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR4N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR5N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR6N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + // eZEX 1st Generation Switches + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR2N0Z0-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR3N0Z0-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR4N0Z0-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR5N0Z0-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR6N0Z0-HA", deviceJoinName: "eZEX Switch 1" + // eZEX 2nd Generation Switches + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR2N0Z1-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR3N0Z1-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR4N0Z1-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR5N0Z1-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR6N0Z1-HA", deviceJoinName: "eZEX Switch 1" + // eZEX 3rd Generation Switches + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR2N0Z2-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR3N0Z2-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR4N0Z2-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR5N0Z2-HA", deviceJoinName: "eZEX Switch 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR6N0Z2-HA", deviceJoinName: "eZEX Switch 1" fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "074b3ffba5a045b7afd94c47079dd553", deviceJoinName: "Orvibo Switch 1" //Orvibo 2 Gang Switch 1 fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "9f76c9f31b4c4a499e3aca0977ac4494", deviceJoinName: "Orvibo Switch 1" //Orvibo 3 Gang Switch 1 @@ -267,6 +279,8 @@ private getChildCount() { case "HY0097": case "HS2SW3L-EFR-3.0": case "E220-KR3N0Z0-HA": + case "E220-KR3N0Z1-HA": + case "E220-KR3N0Z2-HA": case "ZB-SW03": case "JZ-ZB-003": case "PM-S340-ZB": @@ -277,23 +291,31 @@ private getChildCount() { case "HS6SW3A-W-EF-3.0": return 3 case "E220-KR4N0Z0-HA": + case "E220-KR4N0Z1-HA": + case "E220-KR4N0Z2-HA": case "ZB-SW04": case "JZ-ZB-004": case "SBM300Z4": return 4 case "E220-KR5N0Z0-HA": + case "E220-KR5N0Z1-HA": + case "E220-KR5N0Z2-HA": case "ZB-SW05": case "JZ-ZB-005": case "SBM300Z5": return 5 case "E220-KR6N0Z0-HA": + case "E220-KR6N0Z1-HA": + case "E220-KR6N0Z2-HA": case "ZB-SW06": case "JZ-ZB-006": case "SBM300Z6": return 6 case "E220-KR2N0Z0-HA": + case "E220-KR2N0Z1-HA": + case "E220-KR2N0Z2-HA": case "SBM300Z2": default: return 2 } -} +} \ No newline at end of file diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 765ed7cb010..90e3e0d3636 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -35,8 +35,12 @@ metadata { // LELLKI fingerprint profileId: "0104", inClusters: "0000,0003,0004,00005,0006", outClusters: "0000", manufacturer: "LELLKI", model: "JZ-ZB-001", deviceJoinName: "LELLKI Switch" - // EZEX - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR1N0Z0-HA", deviceJoinName: "eZEX Switch" //EZEX Switch + // eZEX 1st Generation Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR1N0Z0-HA", deviceJoinName: "eZEX Switch" + // eZEX 2nd Generation Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR1N0Z1-HA", deviceJoinName: "eZEX Switch" + // eZEX 3rd Generation Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR1N0Z2-HA", deviceJoinName: "eZEX Switch" // GDKES fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0001", deviceJoinName: "GDKES Switch" //GDKES Smart Switch From 83f0e435df54581ce6ed942a2581a53f41d8b301 Mon Sep 17 00:00:00 2001 From: Ryan Greyling Date: Thu, 6 Jan 2022 11:20:33 -0600 Subject: [PATCH 103/184] Cleanup duplicate capabilities Fibaro Heat Controller defines the capability Thermostat Mode twice --- .../fibaro-heat-controller.src/fibaro-heat-controller.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy index 3822c837b42..c535e6ab08d 100644 --- a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy +++ b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy @@ -20,7 +20,6 @@ metadata { capability "Thermostat Heating Setpoint" capability "Health Check" capability "Thermostat" - capability "Thermostat Mode" capability "Temperature Measurement" command "setThermostatSetpointUp" From 495e4c74448c587e2769bbd6384a31c882c71628 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 11 Jan 2022 15:21:15 +0900 Subject: [PATCH 104/184] DevWs for SHINA SYSTEM containing containing ZigBee Lock Without Codes (#77212) * DevWs for SHINA SYSTEM containing containing ZigBee Lock Without Codes * Update zigbee-lock-without-codes.groovy --- .../zigbee-lock-without-codes.groovy | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) 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 index bc718e0efb3..a7dd8ac9ad5 100644 --- 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 @@ -25,10 +25,11 @@ metadata { capability "Battery" capability "Configuration" capability "Health Check" + capability "Contact Sensor" fingerprint profileId:"0104, 000A", inClusters:"0000, 0001, 0003, 0009, 0020,0101, 0B05", outclusters:"000A, 0019, 0B05", manufacturer:"Danalock", model:"V3-BTZB", deviceJoinName:"Danalock Door Lock" //Danalock V3 Smart Lock fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0500, 0101", outClusters: "0019", model: "E261-KR0B0Z0-HA", deviceJoinName: "C2O Door Lock", mnmn: "SmartThings", vid: "C2O-ZigBee-Lock" //C2O Lock - fingerprint profileId:"0104", inClusters:"0000, 0001, 0003, 0020,0101", outclusters:"0003,0004, 0019", manufacturer:"ShinaSystem", model:"DLM-300Z", deviceJoinName:"SiHAS Door Lock" //SiHAS Door Lock + fingerprint profileId:"0104", inClusters:"0000, 0001, 0003, 0020,0101", outclusters:"0003,0004, 0019", manufacturer:"ShinaSystem", model:"DLM-300Z", deviceJoinName:"SiHAS Door Lock", vid:"8019e83a-2ddc-3720-a88c-3cf74186c3ce", mnmn:"SmartThingsCommunity" //SiHAS Door Lock } @@ -69,6 +70,7 @@ 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_DOORSTATE() { 0x0003 } private getDOORLOCK_ATTR_LOCKSTATE() { 0x0000 } private getIAS_ATTR_ZONE_STATUS() { 0x0002 } @@ -115,6 +117,8 @@ def refresh() { cmds += zigbee.readAttribute(CLUSTER_IAS_ZONE, IAS_ATTR_ZONE_STATUS) } + if (isSiHASLock()) cmds += zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_DOORSTATE) + return cmds } @@ -138,7 +142,7 @@ def initialize() { cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,DataType.ENUM8, 0, 3600, null) cmds += zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,DataType.UINT8, 600, 21600, 0x01) cmds += zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) - + if (isSiHASLock()) cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_DOORSTATE,DataType.ENUM8, 0, 3600, null) cmds += refresh() } @@ -217,6 +221,16 @@ private def parseAttributeResponse(String description) { runIn(1, "delayLockEvent", [overwrite: true, forceForLocallyExecuting: true, data: [map: responseMap]]) return [:] } + } else if (clusterInt == CLUSTER_DOORLOCK && attrInt == DOORLOCK_ATTR_DOORSTATE) { + def value = Integer.parseInt(descMap.value, 16) + responseMap.name = "contact" + if (value == 0) { + responseMap.value = "open" + responseMap.descriptionText = "open state" + } else if (value == 1) { + responseMap.value = "closed" + responseMap.descriptionText = "closed state" + } } else { return null } @@ -306,4 +320,8 @@ private Boolean secondsPast(timestamp, seconds) { private boolean isC2OLock() { device.getDataValue("model") == "E261-KR0B0Z0-HA" -} \ No newline at end of file +} + +private boolean isSiHASLock() { + device.getDataValue("model") == "DLM-300Z" +} From 27bac3c71d6840c4f0435457d7f2fe41100fdfe9 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 12 Jan 2022 20:00:12 +0800 Subject: [PATCH 105/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug (#77213) Co-authored-by: Winnie Wen --- .../min-smart-plug.src/min-smart-plug.groovy | 96 +++++-------------- 1 file changed, 24 insertions(+), 72 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy index ffb60b0eee4..3b2613d40de 100644 --- a/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy +++ b/devicetypes/sky-nie/min-smart-plug.src/min-smart-plug.groovy @@ -1,7 +1,7 @@ /** - * Min Smart Plug v2.2.0 + * Min Smart Plug v3.0.0 * - * Models: MINOSTON (MP21Z) And Eva Logik (ZW30) / MINOSTON (MS10Z) + * Models: MINOSTON (MP21Z) And New One Mini Smart Plug (N4001) * * Author: * winnie (sky-nie) @@ -10,6 +10,10 @@ * * Changelog: * + * 3.0.0 (09/07/2021) + * - Remove the support for the products of MS10ZS MS12ZS ZW30 ZW30S and ZW30TS, + * they will be independent in another DTH file + * * 2.2.0 (09/22/2021) * - Remove the function related to CentralScene-the function did not achieve the expected effect, * and it can be replaced by the Automation function in the SmartThings APP @@ -79,31 +83,16 @@ metadata { fingerprint mfr: "0312", prod: "C000", model: "C009", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" // old MP21Z fingerprint mfr: "0312", prod: "FF00", model: "FF0C", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //MP21Z Minoston Mini Smart Plug fingerprint mfr: "0312", prod: "AC01", model: "4001", deviceJoinName: "New One Outlet", ocfDeviceType: "oic.d.smartplug" // N4001 New One Mini Smart Plug - fingerprint mfr: "0312", prod: "EE00", model: "EE01", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS10ZS Minoston Smart Switch - fingerprint mfr: "0312", prod: "EE00", model: "EE03", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS12ZS Minoston Smart on/off Toggle Switch - fingerprint mfr: "0312", prod: "A000", model: "A005", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30 - fingerprint mfr: "0312", prod: "BB00", model: "BB01", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30S Evalogik Smart on/off Switch - fingerprint mfr: "0312", prod: "BB00", model: "BB03", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30TS Evalogik Smart on/off Toggle Switch } preferences { - getConfigParamInput(ledModeParam) - getConfigParamInput(autoOffIntervalParam) - getConfigParamInput(autoOnIntervalParam) - getConfigParamInput(powerFailureRecoveryParam) - input "disclaimer", "paragraph", - title: "WARNING", - description: "Configuring for 'Paddle Control'is only valid for the devices with product number of MS10ZS, MS12ZS, ZW30, ZW30S, ZW30TS(one of them)", - required: false - getConfigParamInput(paddleControlParam) - } -} - -private getConfigParamInput(param) { - if (param.range) { - input "configParam${param.num}", "number", title: "${param.name}:", required: false, defaultValue: "${param.value}", range: param.range - } else { - input "configParam${param.num}", "enum", title: "${param.name}:", required: false, defaultValue: "${param.value}", options: param.options + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options + } + } } } @@ -319,42 +308,24 @@ private getConfigParams() { ledModeParam, autoOffIntervalParam, autoOnIntervalParam, - powerFailureRecoveryParam, - paddleControlParam + powerFailureRecoveryParam ] } -private static getPaddleControlOptions() { - return [ - "0":"Normal", - "1":"Reverse", - "2":"Toggle" - ] -} - -private getPaddleControlParam() { - def num = isButtonAvailable()? 1 : 1000 - return getParam(num, "Paddle Control", 1, 0, paddleControlOptions) -} - private getLedModeParam() { - def num = isButtonAvailable()? 2 : 1 - return getParam(num, "LED Indicator Mode", 1, 0, alternativeLedOptions) + return getParam(1, "LED Indicator Mode", 1, 0, alternativeLedOptions) } private getAutoOffIntervalParam() { - def num = isButtonAvailable()? 4 : 2 - return getParam(num, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") + return getParam(2, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getAutoOnIntervalParam() { - def num = isButtonAvailable()? 6 : 4 - return getParam(num, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") + return getParam(4, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") } private getPowerFailureRecoveryParam() { - def num = isButtonAvailable()? 8 : 6 - return getParam(num, "Power Failure Recovery", 1, 0, powerFailureRecoveryOptions) + return getParam(6, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) } private getParam(num, name, size, defaultVal, options = null, range = null) { @@ -380,20 +351,11 @@ private static setDefaultOption(options, defaultVal) { } private getAlternativeLedOptions() { - if (isButtonAvailable()) { - return [ - "0":"On When On", - "1":"Off When On", - "2":"Always Off" - ] - } else { - return [ - "0":"Off When On", - "1":"On When On", - "2":"Always Off", - "3":"Always On" - ] - } + return [ + "0":"On When On", + "1":"Off When On", + "2":"Always Off" + ] } private static getPowerFailureRecoveryOptions() { @@ -418,14 +380,4 @@ private logDebug(msg) { private logTrace(msg) { log.trace "$msg" -} - -private isButtonAvailable() { - if (device == null) { - log.error "isButtonAvailable device = null" - return true - } else { - log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" - return "${device.rawDescription}".contains("model:EE01") || "${device.rawDescription}".contains("model:EE03") || "${device.rawDescription}".contains("model:A005") || "${device.rawDescription}".contains("model:BB01") || "${device.rawDescription}".contains("model:BB03") - } -} +} \ No newline at end of file From 1f4a292516852ee6203551d65166b588a069cf0f Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Wed, 12 Jan 2022 20:03:01 +0800 Subject: [PATCH 106/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer (#77214) Co-authored-by: Winnie Wen --- .../min-smart-plug-dimmer.groovy | 76 ++++--------------- 1 file changed, 16 insertions(+), 60 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index 1a92fad2b4d..ef33c87f9cc 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -1,5 +1,5 @@ /** - * Min Smart Plug Dimmer v2.2.0 + * Min Smart Plug Dimmer v3.0.0 * * Models: MINOSTON (MP21ZD MP22ZD/ZW39S ZW96SD) * @@ -10,6 +10,10 @@ * * Changelog: * + * 3.0.0 (09/07/2021) + * - Remove the support for the products of MS11ZS MS13ZS ZW31S and ZW31TS, + * they will be independent in another DTH file + * * 2.2.0 (09/22/2021) * - Remove the function related to CentralScene-the function did not achieve the expected effect, * and it can be replaced by the Automation function in the SmartThings APP @@ -102,39 +106,16 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF0D", deviceJoinName: "Minoston Smart Plug Dimmer", ocfDeviceType: "oic.d.smartplug" //MP21ZD fingerprint mfr: "0312", prod: "FF07", model: "FF03", deviceJoinName: "Minoston Outdoor Dimmer", ocfDeviceType: "oic.d.smartplug" //MP22ZD fingerprint mfr: "0312", prod: "AC01", model: "4002", deviceJoinName: "New One Smart Plug Dimmer", ocfDeviceType: "oic.d.smartplug" //N4002 - fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS11ZS Minoston Smart Dimmer Switch - fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS13ZS Minoston Smart Toggle Dimmer Switch - fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31S Evalogik Smart Dimmer Switch - fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31TS Evalogik Smart Toggle Dimmer Switch } preferences { - getConfigParamInput(ledModeParam) - getConfigParamInput(autoOffIntervalParam) - getConfigParamInput(autoOnIntervalParam) - getConfigParamInput(powerFailureRecoveryParam) - getConfigParamInput(pushDimmingDurationParam) - getConfigParamInput(holdDimmingDurationParam) - getConfigParamInput(minimumBrightnessParam) - input "disclaimer", "paragraph", - title: "WARNING", - description: "Configuring for 'Night Light Settings' is only valid for the devices with product number of MP21ZD、MP22ZD、N4002(one of them)", - required: false - getConfigParamInput(nightLightParam) - input "disclaimer", "paragraph", - title: "WARNING", - description: "Configuring for 'Maximum Brightness' and 'Paddle Control' are only valid for the devices with product number of MS11ZS、MS13ZS、ZW31S、ZW31TS(one of them)", - required: false - getConfigParamInput(maximumBrightnessParam) - getConfigParamInput(paddleControlParam) - } -} - -private getConfigParamInput(param) { - if (param.range) { - input "configParam${param.num}", "number", title: "${param.name}:", required: false, defaultValue: "${param.value}", range: param.range - } else { - input "configParam${param.num}", "enum", title: "${param.name}:", required: false, defaultValue: "${param.value}", options: param.options + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options + } + } } } @@ -317,24 +298,11 @@ private getConfigParams() { powerFailureRecoveryParam, pushDimmingDurationParam, holdDimmingDurationParam, - minimumBrightnessParam, - maximumBrightnessParam, - paddleControlParam - ] -} + minimumBrightnessParam -private static getPaddleControlOptions() { - return [ - "0":"Normal", - "1":"Reverse", - "2":"Toggle" ] } -private getPaddleControlParam() { - return getParam(1, "Paddle Control", 1, 0, paddleControlOptions) -} - private getLedModeParam() { return getParam(2, "LED Indicator Mode", 1, 0, ledModeOptions) } @@ -352,13 +320,11 @@ private getNightLightParam() { } private getPowerFailureRecoveryParam() { - def defaultVal = isButtonAvailable()? 0:2 - return getParam(8, "Power Failure Recovery", 1, defaultVal, powerFailureRecoveryOptions) + return getParam(8, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) } private getPushDimmingDurationParam() { - def defaultVal = isButtonAvailable()? 1:2 - return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, defaultVal, null, "0..10") + return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, 2, null, "0..10") } private getHoldDimmingDurationParam() { @@ -507,14 +473,4 @@ private sendSwitchEvents(rawVal, type) { if (rawVal) { sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") } -} - -private isButtonAvailable() { - if (device == null) { - log.error "isButtonAvailable device = null" - return true - } else { - log.debug "isButtonAvailable device.rawDescription = ${device.rawDescription}" - return "${device.rawDescription}".contains("model:EE02") || "${device.rawDescription}".contains("model:EE04") || "${device.rawDescription}".contains("model:BB02") || "${device.rawDescription}".contains("model:BB04") - } -} +} \ No newline at end of file From 688ecee3f562493c1785d2889ee3a6dc5b33b4cf Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 18 Jan 2022 17:23:18 +0800 Subject: [PATCH 107/184] DevWs for NIE-TECH CO., LTD. containing containing In-Wall Smart Switch (#77215) Co-authored-by: Winnie Wen --- .../in-wall-smart-switch.groovy | 362 ++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 devicetypes/sky-nie/in-wall-smart-switch.src/in-wall-smart-switch.groovy diff --git a/devicetypes/sky-nie/in-wall-smart-switch.src/in-wall-smart-switch.groovy b/devicetypes/sky-nie/in-wall-smart-switch.src/in-wall-smart-switch.groovy new file mode 100644 index 00000000000..0172d61c52c --- /dev/null +++ b/devicetypes/sky-nie/in-wall-smart-switch.src/in-wall-smart-switch.groovy @@ -0,0 +1,362 @@ +/** + * In-Wall Smart Switch v1.0.0 + * + * Models: MS10ZS/MS12ZS/ZW30/ZW30S/ZW30TS + * + * Author: + * winnie (sky-nie) + * + * Documentation: + * + * Changelog: + * + * 1.0.0 (12/22/2021) + * - Initial Release + * + * Reference: + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/eva-logik-in-wall-smart-switch.src/eva-logik-in-wall-smart-switch.groovy + * + * 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 groovy.json.JsonOutput + +metadata { + definition (name: "In-Wall Smart Switch", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-switch") { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Configuration" + capability "Refresh" + capability "Health Check" + + attribute "firmwareVersion", "string" + attribute "syncStatus", "string" + + fingerprint mfr: "0312", prod: "EE00", model: "EE01", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS10ZS Minoston Smart Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE03", deviceJoinName: "Minoston Switch", ocfDeviceType: "oic.d.switch" //MS12ZS Minoston Smart on/off Toggle Switch + fingerprint mfr: "0312", prod: "A000", model: "A005", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30 + fingerprint mfr: "0312", prod: "BB00", model: "BB01", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30S Evalogik Smart on/off Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB03", deviceJoinName: "Evalogik Switch", ocfDeviceType: "oic.d.switch" //ZW30TS Evalogik Smart on/off Toggle Switch + } + + preferences { + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options + } + } + } +} + +def installed() { + logDebug "installed()..." + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +private static def getCheckInterval() { + // These are battery-powered devices, and it's not very critical + // to know whether they're online or not – 12 hrs + return (60 * 60 * 3) + (5 * 60) +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 5000)) { + state.lastUpdated = new Date().time + logDebug "updated()..." + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + runIn(5, executeConfigureCmds, [overwrite: true]) + } + return [] +} + +def configure() { + logDebug "configure()..." + if (state.resyncAll == null) { + state.resyncAll = true + runIn(8, executeConfigureCmds, [overwrite: true]) + } else { + if (!pendingChanges) { + state.resyncAll = true + } + executeConfigureCmds() + } + return [] +} + +def executeConfigureCmds() { + runIn(6, refreshSyncStatus) + + def cmds = [] + + configParams.each { param -> + def storedVal = getParamStoredValue(param.num) + def paramVal = param.value + if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + + state.resyncAll = false + if (cmds) { + sendHubCommand(cmds, 500) + } + return [] +} + +def ping() { + logDebug "ping()..." + return [ switchBinaryGetCmd() ] +} + +def on() { + logDebug "on()..." + return [ switchBinarySetCmd(0xFF) ] +} + +def off() { + logDebug "off()..." + return [ switchBinarySetCmd(0x00) ] +} + +def refresh() { + logDebug "refresh()..." + refreshSyncStatus() + return [ switchBinaryGetCmd() ] +} + +private switchBinaryGetCmd() { + return secureCmd(zwave.switchBinaryV1.switchBinaryGet()) +} + +private switchBinarySetCmd(val) { + return secureCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: val)) +} + +private secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s") || ("0x98" in device?.rawDescription?.split(" "))) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + log.error("secureCmd exception", ex) + return cmd.format() + } +} + +def parse(String description) { + def result = [] + try { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result += zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + } catch (e) { + log.error "${e}" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + logTrace "SecurityMessageEncapsulation: ${cmd}" + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + def result = [] + if (encapsulatedCmd) { + result += zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + logTrace "ConfigurationReport: ${cmd}" + sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) + runIn(4, refreshSyncStatus) + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + logDebug "${param.name}(#${param.num}) = ${val}" + state["configVal${param.num}"] = val + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logTrace "VersionReport: ${cmd}" + def subVersion = String.format("%02d", cmd.applicationSubVersion) + def fullVersion = "${cmd.applicationVersion}.${subVersion}" + sendEvent(name: "firmwareVersion", value: fullVersion) + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + logTrace "BasicReport: ${cmd}" + sendSwitchEvents(cmd.value, "physical") + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + logTrace "SwitchBinaryReport: ${cmd}" + sendSwitchEvents(cmd.value, "digital") + return [] +} + +private sendSwitchEvents(rawVal, type) { + def switchVal = (rawVal == 0xFF) ? "on" : "off" + sendEvent(name: "switch", value: switchVal, displayed: true, type: type) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" + return [] +} + +def refreshSyncStatus() { + def changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +private static getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x27: 1, // Switch All + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 + ] +} + +private getPendingChanges() { + return configParams.count { "${it.value}" != "${getParamStoredValue(it.num)}" } +} + +private getParamStoredValue(paramNum) { + return safeToInt(state["configVal${paramNum}"] , null) +} + +private getConfigParams() { + return [ + ledModeParam, + autoOffIntervalParam, + autoOnIntervalParam, + powerFailureRecoveryParam, + paddleControlParam + ] +} + +private static getPaddleControlOptions() { + return [ + "0":"Normal", + "1":"Reverse", + "2":"Toggle" + ] +} + +private getPaddleControlParam() { + return getParam(1, "Paddle Control", 1, 0, paddleControlOptions) +} + +private getLedModeParam() { + return getParam(2, "LED Indicator Mode", 1, 0, alternativeLedOptions) +} + +private getAutoOffIntervalParam() { + return getParam(4, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getAutoOnIntervalParam() { + return getParam(6, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getPowerFailureRecoveryParam() { + return getParam(8, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) +} + +private getParam(num, name, size, defaultVal, options = null, range = null) { + def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + def map = [num: num, name: name, size: size, value: val] + if (options) { + map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value + map.options = setDefaultOption(options, defaultVal) + } + if (range) { + map.range = range + } + return map +} + +private static setDefaultOption(options, defaultVal) { + return options?.collectEntries { k, v -> + if ("${k}" == "${defaultVal}") { + v = "${v} [DEFAULT]" + } + ["$k": "$v"] + } +} + +private getAlternativeLedOptions() { + return [ + "0":"Off When On", + "1":"On When On", + "2":"Always Off", + "3":"Always On" + ] +} + +private static getPowerFailureRecoveryOptions() { + return [ + "0":"Turn Off", + "1":"Turn On", + "2":"Restore Last State" + ] +} + +private static safeToInt(val, defaultVal = 0) { + return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal +} + +private static isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +private logDebug(msg) { + log.debug "$msg" +} + +private logTrace(msg) { + log.trace "$msg" +} \ No newline at end of file From 21ab092dd47d3f016c836c8dcef0dcf08894e8ec Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 18 Jan 2022 17:30:03 +0800 Subject: [PATCH 108/184] DevWs for NIE-TECH CO., LTD. containing containing In-Wall Smart Switch Dimmer (#77216) Co-authored-by: Winnie Wen --- .../in-wall-smart-switch-dimmer.groovy | 427 ++++++++++++++++++ 1 file changed, 427 insertions(+) create mode 100644 devicetypes/sky-nie/in-wall-smart-switch-dimmer.src/in-wall-smart-switch-dimmer.groovy diff --git a/devicetypes/sky-nie/in-wall-smart-switch-dimmer.src/in-wall-smart-switch-dimmer.groovy b/devicetypes/sky-nie/in-wall-smart-switch-dimmer.src/in-wall-smart-switch-dimmer.groovy new file mode 100644 index 00000000000..c8d7bb77d01 --- /dev/null +++ b/devicetypes/sky-nie/in-wall-smart-switch-dimmer.src/in-wall-smart-switch-dimmer.groovy @@ -0,0 +1,427 @@ +/** + * In-Wall Smart Switch Dimmer v1.0.0 + * + * Models: MS11ZS/MS13ZS/ZW31S/ZW31TS + * + * Author: + * winnie (sky-nie) + * + * Documentation: + * + * Changelog: + * + * 1.0.0 (12/22/2021) + * - Initial Release + * + * Reference: + * https://github.com/krlaframboise/SmartThings/blob/master/devicetypes/krlaframboise/eva-logik-in-wall-smart-dimmer.src/eva-logik-in-wall-smart-dimmer.groovy + * + * 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 groovy.json.JsonOutput + +metadata { + definition (name: "In-Wall Smart Switch Dimmer", namespace: "sky-nie", author: "winnie", mnmn: "SmartThings", vid:"generic-dimmer") { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Switch Level" + capability "Configuration" + capability "Refresh" + capability "Health Check" + + attribute "firmwareVersion", "string" + attribute "lastCheckIn", "string" + attribute "syncStatus", "string" + + fingerprint mfr: "0312", prod: "0004", model: "EE02", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS11ZS Minoston Smart Dimmer Switch + fingerprint mfr: "0312", prod: "EE00", model: "EE04", deviceJoinName: "Minoston Dimmer Switch", ocfDeviceType: "oic.d.switch" //MS13ZS Minoston Smart Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB02", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31S Evalogik Smart Dimmer Switch + fingerprint mfr: "0312", prod: "BB00", model: "BB04", deviceJoinName: "Evalogik Dimmer Switch", ocfDeviceType: "oic.d.switch" //ZW31TS Evalogik Smart Toggle Dimmer Switch + } + + preferences { + configParams.each { + if (it.range) { + input "configParam${it.num}", "number", title: "${it.name}:", required: false, defaultValue: "${it.value}", range: it.range + } else { + input "configParam${it.num}", "enum", title: "${it.name}:", required: false, defaultValue: "${it.value}", options: it.options + } + } + } +} + +def ping() { + logDebug "ping()..." + return [ switchMultilevelGetCmd() ] +} + +def refresh() { + logDebug "refresh()..." + refreshSyncStatus() + return [ switchMultilevelGetCmd() ] +} + +private switchMultilevelGetCmd() { + return secureCmd(zwave.switchMultilevelV3.switchMultilevelGet()) +} + +def installed() { + logDebug "installed()..." + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +private static def getCheckInterval() { + // These are battery-powered devices, and it's not very critical + // to know whether they're online or not – 12 hrs + return (60 * 60 * 3) + (5 * 60) +} + +def updated() { + if (!isDuplicateCommand(state.lastUpdated, 5000)) { + state.lastUpdated = new Date().time + logDebug "updated()..." + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + runIn(5, executeConfigureCmds, [overwrite: true]) + } + return [] +} + +def configure() { + logDebug "configure()..." + if (state.resyncAll == null) { + state.resyncAll = true + runIn(8, executeConfigureCmds, [overwrite: true]) + } else { + if (!pendingChanges) { + state.resyncAll = true + } + executeConfigureCmds() + } + return [] +} + +def executeConfigureCmds() { + runIn(6, refreshSyncStatus) + + def cmds = [] + + configParams.each { param -> + def storedVal = getParamStoredValue(param.num) + def paramVal = param.value + if (state.resyncAll || ("${storedVal}" != "${paramVal}")) { + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: paramVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + + state.resyncAll = false + if (cmds) { + sendHubCommand(cmds, 500) + } + return [] +} + +def parse(String description) { + def result = [] + try { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + result += zwaveEvent(cmd) + } else { + logDebug "Unable to parse description: $description" + } + sendEvent(name: "lastCheckIn", value: convertToLocalTimeString(new Date()), displayed: false) + } catch (e) { + log.error "$e" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + logTrace "SecurityMessageEncapsulation: ${cmd}" + def encapCmd = cmd.encapsulatedCommand(commandClassVersions) + def result = [] + if (encapCmd) { + result += zwaveEvent(encapCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + logTrace "ConfigurationReport: ${cmd}" + sendEvent(name: "syncStatus", value: "Syncing...", displayed: false) + runIn(4, refreshSyncStatus) + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + logDebug "${param.name}(#${param.num}) = ${val}" + state["configParam${param.num}"] = val + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } + return [] +} + +def refreshSyncStatus() { + def changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: $cmd" + return [] +} + +private secureCmd(cmd) { + try { + if (zwaveInfo?.zw?.contains("s") || ("0x98" in device?.rawDescription?.split(" "))) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } + } catch (ex) { + log.error("secureCmd exception", ex) + return cmd.format() + } +} + +private static getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x26: 3, // Switch Multilevel + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x71: 3, // Notification + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 + ] +} + +private getPendingChanges() { + return configParams.count { "${it.value}" != "${getParamStoredValue(it.num)}" } +} + +private getParamStoredValue(paramNum) { + return safeToInt(state["configParam${paramNum}"] , null) +} + +// Configuration Parameters +private getConfigParams() { + [ + ledModeParam, + autoOffIntervalParam, + autoOnIntervalParam, + powerFailureRecoveryParam, + pushDimmingDurationParam, + holdDimmingDurationParam, + minimumBrightnessParam, + maximumBrightnessParam, + paddleControlParam + ] +} + +private static getPaddleControlOptions() { + return [ + "0":"Normal", + "1":"Reverse", + "2":"Toggle" + ] +} + +private getPaddleControlParam() { + return getParam(1, "Paddle Control", 1, 0, paddleControlOptions) +} + +private getLedModeParam() { + return getParam(2, "LED Indicator Mode", 1, 0, ledModeOptions) +} + +private getAutoOffIntervalParam() { + return getParam(4, "Auto Turn-Off Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getAutoOnIntervalParam() { + return getParam(6, "Auto Turn-On Timer(0, Disabled; 1 - 65535 minutes)", 4, 0, null, "0..65535") +} + +private getPowerFailureRecoveryParam() { + return getParam(8, "Power Failure Recovery", 1, 2, powerFailureRecoveryOptions) +} + +private getPushDimmingDurationParam() { + return getParam(9, "Push Dimming Duration(0, Disabled; 1 - 10 Seconds)", 1, 1, null, "0..10") +} + +private getHoldDimmingDurationParam() { + return getParam(10, "Hold Dimming Duration(1 - 10 Seconds)", 1, 4, null, "1..10") +} + +private getMinimumBrightnessParam() { + return getParam(11, "Minimum Brightness(0, Disabled; 1 - 99:1% - 99%)", 1, 10, null,"0..99") +} + +private getMaximumBrightnessParam() { + return getParam(12, "Maximum Brightness(0, Disabled; 1 - 99:1% - 99%)", 1, 99, null,"0..99") +} + +private getParam(num, name, size, defaultVal, options = null, range = null) { + def val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + def map = [num: num, name: name, size: size, value: val] + if (options) { + map.valueName = options?.find { k, v -> "${k}" == "${val}" }?.value + map.options = setDefaultOption(options, defaultVal) + } + if (range) { + map.range = range + } + return map +} + +private static setDefaultOption(options, defaultVal) { + return options?.collectEntries { k, v -> + if ("${k}" == "${defaultVal}") { + v = "${v} [DEFAULT]" + } + ["$k": "$v"] + } +} + +private static getLedModeOptions() { + return [ + "0":"Off When On", + "1":"On When On", + "2":"Always Off", + "3":"Always On" + ] +} + +private static getPowerFailureRecoveryOptions() { + return [ + "0":"Turn Off", + "1":"Turn On", + "2":"Restore Last State" + ] +} + +private static validateRange(val, defaultVal, lowVal, highVal) { + val = safeToInt(val, defaultVal) + if (val > highVal) { + return highVal + } else if (val < lowVal) { + return lowVal + } else { + return val + } +} + +private static safeToInt(val, defaultVal = 0) { + return "${val}"?.isInteger() ? "${val}".toInteger() : defaultVal +} + +private convertToLocalTimeString(dt) { + def timeZoneId = location?.timeZone?.ID + if (timeZoneId) { + return dt.format("MM/dd/yyyy hh:mm:ss a", TimeZone.getTimeZone(timeZoneId)) + } else { + return "$dt" + } +} + +private static isDuplicateCommand(lastExecuted, allowedMil) { + !lastExecuted ? false : (lastExecuted + allowedMil > new Date().time) +} + +private logDebug(msg) { + log.debug "$msg" +} + +private logTrace(msg) { + log.trace "$msg" +} + +def on() { + logDebug "on()..." + return [ basicSetCmd(0xFF) ] +} + +def off() { + logDebug "off()..." + return [ basicSetCmd(0x00) ] +} + +def setLevel(level) { + logDebug "setLevel($level)..." + return setLevel(level, 1) +} + +def setLevel(level, duration) { + logDebug "setLevel($level, $duration)..." + if (duration > 30) { + duration = 30 + } + return [ switchMultilevelSetCmd(level, duration) ] +} + +private basicSetCmd(val) { + return secureCmd(zwave.basicV1.basicSet(value: val)) +} + +private switchMultilevelSetCmd(level, duration) { + def levelVal = validateRange(level, 99, 0, 99) + def durationVal = validateRange(duration, 1, 0, 100) + return secureCmd(zwave.switchMultilevelV3.switchMultilevelSet(dimmingDuration: durationVal, value: levelVal)) +} + +def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logTrace "VersionReport: ${cmd}" + def subVersion = String.format("%02d", cmd.applicationSubVersion) + def fullVersion = "${cmd.applicationVersion}.${subVersion}" + sendEvent(name: "firmwareVersion", value:fullVersion, displayed: true, type: null) + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + logTrace "BasicReport: ${cmd}" + sendSwitchEvents(cmd.value, "physical") + return [] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { + logTrace "SwitchMultilevelReport: ${cmd}" + sendSwitchEvents(cmd.value, "digital") + return [] +} + +private sendSwitchEvents(rawVal, type) { + def switchVal = rawVal ? "on" : "off" + sendEvent(name: "switch", value:switchVal, displayed: true, type: type) + if (rawVal) { + sendEvent(name: "level", value:rawVal, displayed: true, type: type, unit:"%") + } +} \ No newline at end of file From e67104b8ae753972564ec76ea7d99f7b2a191d28 Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 18 Jan 2022 10:11:37 -0800 Subject: [PATCH 109/184] CHAD-7380 Corrects Schlage fingerprint We got a report that this fingerprint had been incorrect for some time. --- devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy index 39af5e53372..c228bbcd676 100644 --- a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy +++ b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy @@ -43,7 +43,7 @@ metadata { //zw:Fs type:4003 mfr:0090 prod:0003 model:0742 ver:4.10 zwv:4.34 lib:03 cc:5E,72,5A,98,73,7A sec:86,80,62,63,85,59,71,70,4E,8B,4C,5D role:07 ff:8300 ui:8300 fingerprint mfr:"0090", prod:"0003", model:"0742", deviceJoinName: "Kwikset Door Lock" //Kwikset Obsidian Lock // Schlage - fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Door Lock" //Schlage Touchscreen Deadbolt Door Lock + fingerprint mfr:"003B", prod:"6349", model:"5044", deviceJoinName: "Schlage Door Lock" //Schlage Touchscreen Deadbolt Door Lock fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Door Lock" //Schlage Touchscreen Deadbolt Door Lock fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Door Lock" //Schlage Connected Keypad Lever Door Lock fingerprint mfr:"003B", prod:"0001", model:"0468", deviceJoinName: "Schlage Door Lock" //BE468ZP //Schlage Connect Smart Deadbolt Door Lock From 7beff203315716e8afc4edf577172ff7bb375cfb Mon Sep 17 00:00:00 2001 From: AltyorFig <95210115+AltyorFig@users.noreply.github.com> Date: Wed, 19 Jan 2022 11:40:50 +0100 Subject: [PATCH 110/184] DevWs for NodOn containing containing NodOn multi Switch (#77465) * DevWs for NodOn containing containing NodOn multi Switch * insert NodOn fingerprint into smartthings / Zigbee Switch * Delete device NodOn multi switch * fix indentations fingerprint * update the last version of zigbee switch and check the indentation of our brand * change deviceJoinName: "NodOn Switch" --- devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 90e3e0d3636..d64ae59efc6 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -77,6 +77,9 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "Leviton", model: "DG15S", deviceJoinName: "Leviton Switch" //Leviton Lumina RF Switch fingerprint manufacturer: "Leviton", model: "DG15A", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Zigbee Plug-In Switch DG15A, Raw Description: 01 0104 010A 00 06 0000 0003 0004 0005 0006 0B05 01 0019 + // NodOn + fingerprint profileId: "0104", deviceId: "0002", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-1-20", deviceJoinName: "NodOn Switch" + // Orvibo fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "095db3379e414477ba6c2f7e0c6aa026", deviceJoinName: "Orvibo Switch" //Orvibo Smart Switch fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "fdd5fce51a164c7ab73b2f4d8d84c88e", deviceJoinName: "Orvibo Outlet", ocfDeviceType: "oic.d.smartplug" //Orvibo Smart Outlet From a5269f8b26f6840cb3f1622936317d9ff45911c8 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Thu, 20 Jan 2022 17:01:53 +0900 Subject: [PATCH 111/184] DevWs for SHINA SYSTEM containing containing Zigbee Power Meter (#77282) * DevWs for SHINA SYSTEM containing containing Zigbee Power Meter * Update sihas-zigbee-power-meter.groovy fix indentation * Update sihas-zigbee-power-meter.groovy Energy min reporting : 1 -> 5 seconds * Update sihas-zigbee-power-meter.groovy Fix indentations. * Update sihas-zigbee-power-meter.groovy add space after if --- .../sihas-zigbee-power-meter.groovy | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy diff --git a/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy b/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy new file mode 100644 index 00000000000..fd7d4091644 --- /dev/null +++ b/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy @@ -0,0 +1,162 @@ +/** + * Copyright 2022 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: "SiHAS Zigbee Power Meter", namespace: "shinasys", author: "SHINA SYSTEM", mnmn: "SmartThingsCommunity", ocfDeviceType: "x.com.st.d.energymeter", vid: "92543bd9-8a3c-3c8a-b43a-036a6a4bea9d") { + capability "Energy Meter" + capability "Power Meter" + capability "Refresh" + capability "Health Check" + capability "Sensor" + capability "Configuration" + capability "Voltage Measurement" + capability "afterguide46998.currentMeasurement" + capability "afterguide46998.frequencyMeasurement" + capability "afterguide46998.powerfactorMeasurement" + capability "Temperature Measurement" + + fingerprint profileId: "0104", manufacturer: "ShinaSystem", model: "PMM-300Z2", deviceJoinName: "SiHAS Energy Monitor" // Single Phase, SIHAS Power Meter 01 0104 0000 01 06 0000 0004 0003 0B04 0702 0402 02 0004 0019 + fingerprint profileId: "0104", manufacturer: "ShinaSystem", model: "PMM-300Z3", deviceJoinName: "SiHAS Energy Monitor" // Three Phase, SIHAS Power Meter 01 0104 0000 01 06 0000 0004 0003 0B04 0702 0402 02 0004 0019 + } +} + +def getATTRIBUTE_READING_INFO_SET() { 0x0000 } +def getATTRIBUTE_HISTORICAL_CONSUMPTION() { 0x0400 } +def getATTRIBUTE_ACTIVE_POWER() { 0x050B } +def getATTRIBUTE_FREQUENCY() { 0x0300 } +def getATTRIBUTE_VOLTAGE() { 0x0505 } +def getATTRIBUTE_CURRENT() { 0x0508 } +def getATTRIBUTE_POWERFACTOR() { 0x0510 } +def getTEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 } + +def convertHexToInt24Bit(value) { + int result = zigbee.convertHexToInt(value) + if (result & 0x800000) { + result |= 0xFF000000 + } + return result +} + +def parse(String description) { + log.debug "description is $description" + if (description?.startsWith('temperature:')) { //parse temperature + List result = [] + def map = [:] + map.name = description.split(": ")[0] + map.value = description.split(": ")[1] + map.unit = getTemperatureScale() + log.debug "${device.displayName}: Reported temperature is ${map.value}°$map.unit" + return createEvent(map) + } else { + List result = [] + def descMap = zigbee.parseDescriptionAsMap(description) + log.debug "Desc Map: $descMap" + + List attrData = [[clusterInt: descMap.clusterInt ,attrInt: descMap.attrInt, value: descMap.value, isValidForDataType: descMap.isValidForDataType]] + descMap.additionalAttrs.each { + attrData << [clusterInt: descMap.clusterInt, attrInt: it.attrInt, value: it.value, isValidForDataType: it.isValidForDataType] + } + attrData.each { + def map = [:] + if (it.isValidForDataType && (it.value != null)) { + if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { + log.debug "meter" + map.name = "power" + map.value = convertHexToInt24Bit(it.value)/powerDivisor + map.unit = "W" + } else if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { + log.debug "energy" + map.name = "energy" + map.value = zigbee.convertHexToInt(it.value)/energyDivisor + map.unit = "kWh" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_FREQUENCY) { + log.debug "frequency" + map.name = "frequency" + map.value = zigbee.convertHexToInt(it.value)/frequencyDivisor + map.unit = "Hz" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_VOLTAGE) { + log.debug "voltage" + map.name = "voltage" + map.value = zigbee.convertHexToInt(it.value)/voltageDivisor + map.unit = "V" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_CURRENT) { + log.debug "current" + map.name = "current" + map.value = zigbee.convertHexToInt(it.value)/currentDivisor + map.unit = "A" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_POWERFACTOR) { + log.debug "power factor $it.value" + map.name = "powerFactor" + map.value = (byte) zigbee.convertHexToInt(it.value)/powerFactorDivisor + map.unit = "%" + } else if (it.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && it.attrInt == TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE) { + log.debug "temperature" + map.name = "temperature" + map.unit = getTemperatureScale() + map.value = zigbee.parseHATemperatureValue("temperature: " + (zigbee.convertHexToInt(it.value)), "temperature: ", tempScale) + log.debug "${device.displayName}: Reported temperature is ${map.value}°$map.unit" + } + } + + if (map) { + result << createEvent(map) + } + log.debug "Parse returned $map" + } + return result + } +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return refresh() +} + +def refresh() { + log.debug "refresh " + zigbee.simpleMeteringPowerRefresh() + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR) + + zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE) +} + +def configure() { + def configCmds = [] + // this device will send instantaneous demand and current summation delivered every 1 minute + sendEvent(name: "checkInterval", value: 2 * 60 + 10 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + + log.debug "Configuring Reporting" + configCmds = zigbee.simpleMeteringPowerConfig() + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 5, 600, 1) + + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY, DataType.UINT16, 10, 600, 3) + /* 3 unit : 0.3Hz */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE, DataType.UINT16, 5, 600, 3) + /* 3 unit : 0.3V */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT, DataType.UINT16, 5, 600, 1) + /* 1 unit : 0.01A */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR, DataType.INT8, 10, 600, 1) + /* 1 unit : 0.1% */ + zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 20, 300, 10 /* 1 uint : 0.1C */) + return configCmds + refresh() +} + +private getActivePowerDivisor() { 1 } +private getPowerDivisor() { 1 } +private getEnergyDivisor() { 1000 } +private getFrequencyDivisor() { 10 } +private getVoltageDivisor() { 10 } +private getCurrentDivisor() { 100 } +private getPowerFactorDivisor() { 1 } From 0efe39641f0eb03f07e8552910f4ca8640fca9c2 Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Tue, 25 Jan 2022 22:33:26 +0400 Subject: [PATCH 112/184] DevWs for HELTUN containing containing HELTUN RS01 Switch (#76678) * DevWs for HELTUN containing containing HELTUN RS01 Switch * Child Devices * fixed spacing * fix identation * Changed child device to "smartthings", "Child Button" * Spacing fix * Delete he-button.groovy * Formating * Spacing * Formating * Changing "HE-RELAY" child name to "Heltun Child Relay" Spacing fix * Delete he-relay.groovy Co-authored-by: Artur Sargsyan --- .../heltun-child-relay.groovy | 38 ++ .../heltun-rs01-switch.groovy | 637 ++++++++++++++++++ 2 files changed, 675 insertions(+) create mode 100644 devicetypes/heltun/heltun-child-relay.src/heltun-child-relay.groovy create mode 100644 devicetypes/heltun/heltun-rs01-switch.src/heltun-rs01-switch.groovy diff --git a/devicetypes/heltun/heltun-child-relay.src/heltun-child-relay.groovy b/devicetypes/heltun/heltun-child-relay.src/heltun-child-relay.groovy new file mode 100644 index 00000000000..244c56a3ef6 --- /dev/null +++ b/devicetypes/heltun/heltun-child-relay.src/heltun-child-relay.groovy @@ -0,0 +1,38 @@ +/** + * + * + * Copyright 2021 Sarkis Kabrailian + * + * 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: "Heltun Child Relay", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, ocfDeviceType: "oic.d.switch") { + capability "Switch" + capability "Power Meter" + capability "Refresh" + capability "Health Check" + } +} + +def ping() { + parent.refresh() +} + +def on() { + parent.childOn(device.deviceNetworkId) +} + +def off() { + parent.childOff(device.deviceNetworkId) +} + +def refresh() { + parent.refresh() +} \ No newline at end of file diff --git a/devicetypes/heltun/heltun-rs01-switch.src/heltun-rs01-switch.groovy b/devicetypes/heltun/heltun-rs01-switch.src/heltun-rs01-switch.groovy new file mode 100644 index 00000000000..15de86ad802 --- /dev/null +++ b/devicetypes/heltun/heltun-rs01-switch.src/heltun-rs01-switch.groovy @@ -0,0 +1,637 @@ +/** + * HELTUN RS01 Switch + * + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HELTUN RS01 Switch", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, mcdSync: true, ocfDeviceType: "oic.d.switch") { + capability "Switch" + capability "Energy Meter" + capability "Power Meter" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", model: "0009", deviceJoinName: "HELTUN" + } + preferences { + input ( + title: "HE-RS01 | HELTUN Relay Switch", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + if (it.title != null) { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + } + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if ( needConfig ) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if ( state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue) { + state."$parameter".state = "configured" + } + else { + state."$parameter".state = "error" + } + configParam() +} + +def updated() { + if (childDevices && device.label != state.oldLabel) { + childDevices.each { + def newLabel = getChildName(channelNumber(it.deviceNetworkId)) + it.setLabel(newLabel) + } + state.oldLabel = device.label + } + initialize() +} + +def initialize() { + runIn(3, "checkParam") +} + +def installed() { + def numberOfButtons = 5 + state.oldLabel = device.label + def existingChildren = getChildDevices() + for (i in 1..numberOfButtons) { + def buttonNetworkId = "${device.deviceNetworkId}:${i+10}" + def relayNetworkId = "${device.deviceNetworkId}:${i}" + def childRelayExists = (existingChildren.find {child -> child.getDeviceNetworkId() == relayNetworkId} != NULL) + def childButtonExists = (existingChildren.find {child -> child.getDeviceNetworkId() == buttonNetworkId} != NULL) + if (!childRelayExists) { + addChildDevice("HELTUN", "Heltun Child Relay", relayNetworkId, device.hubId,[completedSetup: true, label: getChildName(i), isComponent: false]) + } + if (!childButtonExists ) { + def child = addChildDevice("smartthings", "Child Button", buttonNetworkId, device.hubId, [completedSetup: true, label: getChildName(i+10), isComponent: true, componentName: "button$i", componentLabel: "Button ${i}"]) + } + } + initialize() +} + +private getChildName(channelNumber) { + if (channelNumber in 1..5) { + return "${device.displayName} " + "${"Switch"} " + "${channelNumber}" + } + else if (channelNumber in 11..16) { + return "${device.displayName} " + "${"Button"} " + "${channelNumber-10}" + } +} + +private channelNumber(String deviceNetworkId) { + deviceNetworkId.split(":")[-1] as Integer +} + +def parse(String description) { + def cmd = zwave.parse(description) + if (cmd) { + return zwaveEvent(cmd) + } +} + +private void setState(value, endpoint = null) { + def map = [ + encap(zwave.basicV1.basicSet(value: value), endpoint), + encap(zwave.switchBinaryV1.switchBinaryGet(), endpoint), + ] + sendHubCommand(map, 500) +} + +private encap(cmd, endpoint) { + if (endpoint) { + zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd).format() + } else { + cmd.format() + } +} + +def on() { + def map = [ + encap(zwave.basicV1.basicSet(value: 0xFF), 0xFF), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2), + encap(zwave.switchBinaryV1.switchBinaryGet(), 3), + encap(zwave.switchBinaryV1.switchBinaryGet(), 4), + encap(zwave.switchBinaryV1.switchBinaryGet(), 5) + ] + sendHubCommand(map, 100) +} + +def off() { + def map = [ + encap(zwave.basicV1.basicSet(value: 0), 0xFF), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2), + encap(zwave.switchBinaryV1.switchBinaryGet(), 3), + encap(zwave.switchBinaryV1.switchBinaryGet(), 4), + encap(zwave.switchBinaryV1.switchBinaryGet(), 5) + ] + sendHubCommand(map, 100) +} + +def childOn(childId) { + setState(0xFF, channelNumber(childId)) +} + +def childOff(childId) { + setState(0, channelNumber(childId)) +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + sendEvent(map) + } else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + sendEvent(map) + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + def state + def buttonN + switch (cmd.keyAttributes as Integer) { + case 0: + state = "pushed" + buttonN = cmd.sceneNumber + break + case 1: + state = "up" + buttonN = cmd.sceneNumber + break + case 2: + state = "held" + buttonN = cmd.sceneNumber + break + } + if (buttonN) { + def buttonId = buttonN + 10 + def child = childDevices?.find {channelNumber(it.deviceNetworkId) == buttonId } + child?.sendEvent([name: "button", value: state, data: [buttonNumber: 1], isStateChange: true]) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + def endPoint = cmd.sourceEndPoint + def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) + def value = encapsulatedCommand.value + def childDevice = childDevices?.find {channelNumber(it.deviceNetworkId) == endPoint } + def corrRelCons = 0 + def corRelParam = 11 + endPoint + def param = parameterMap().find( {it.paramNum == corRelParam } ).name + def paramState = state."$param" + if (paramState){ + corrRelCons = paramState.value + } + if (childDevice) { + childDevice.sendEvent(name: "switch", value: value ? "on" : "off") + if (value) { + sendEvent(name: "switch", value: "on") + childDevice.sendEvent(name: "power", value: corrRelCons, unit: "W") + } else { + childDevice.sendEvent(name: "power", value: 0, unit: "W") + if (!childDevices.any { it.currentValue("switch") == "on" }) { + sendEvent(name: "switch", value: "off") + } + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = Calendar.getInstance(location.timeZone) + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)){ + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [0, zwaveHubNodeId, 0]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,0]).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def configure() { + refresh() +} + +def refresh() { + def cmds = [] + for (i in 1..5){ + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), i) + } + cmds << zwave.clockV1.clockGet().format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() + sendHubCommand(cmds, 1200) + runIn(15, "checkParam") +} + +def ping() { + refresh() +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +private parameterMap() {[ + [ + title: "Relays Output Mode", description: "These Parameters determine the type of loads connected to the device relay outputs. The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", name: "Selected Relay 1 Mode", + options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Relay 2 Mode", + options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 8, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Relay 3 Mode", + options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 9, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Relay 4 Mode", + options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 10, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Relay 5 Mode", + options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 11, size: 1, default: "0", type: "enum" + ], + [ + title: "Relays Load Power", description: "These parameters are used to specify the loads power that are connected to the device outputs (Relays). Using your connected device’s power consumption specification (see associated owner’s manual), set the load in Watts for the outputs bellow:", + name: "Selected Relay 1 Load Power in Watts", paramNum: 12, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W" + ], + [ + name: "Selected Relay 2 Load Power in Watts", paramNum: 13, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W" + ], + [ + name: "Selected Relay 3 Load Power in Watts", paramNum: 14, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W" + ], + [ + name: "Selected Relay 4 Load Power in Watts", paramNum: 15, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W" + ], + [ + name: "Selected Relay 5 Load Power in Watts", paramNum: 16, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W" + ], + [ + title: "Hold Control Mode for external inputs S1-S5", description: "This Parameter defines how the relay should react while holding the button connected to the corresponding external input. The options are: Hold is disabled, Operate like click, Momentary Switch: When the button is held, the relay output state is ON, as soon as the button is released the relay output state changes to OFF, Reversed Momentary: When the button is held, the relay output state is OFF, as soon as the button is released the relay output state changes to ON, Toggle: When the button is held or released the relay output state will toggle its state (ON to OFF or OFF to ON).", name: "Selected Hold Control Mode for S1", + options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 41, size: 1, default: "2", type: "enum" + ], + [ + name: "Selected Hold Control Mode for S2", + options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 42, size: 1, default: "2", type: "enum" + ], + [ + name: "Selected Hold Control Mode for S3", + options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 43, size: 1, default: "2", type: "enum" + ], + [ + name: "Selected Hold Control Mode for S4", + options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 44, size: 1, default: "2", type: "enum" + ], + [ + name: "Selected Hold Control Mode for S5", + options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 45, size: 1, default: "2", type: "enum" + ], + [ + title: "Hold Mode Duration for External Inputs S1-S5", description: "These Parameters specify the time the device needs to recognize a hold mode when the button connected to an external input is held (key closed). These parameters are available on firmware V1.4 or higher", + name: "Selected Duration for S1 in milliseconds", paramNum: 46, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms" + ], + [ + name: "Selected Duration for S2 in milliseconds", paramNum: 47, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms" + ], + [ + name: "Selected Duration for S3 in milliseconds", paramNum: 48, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms" + ], + [ + name: "Selected Duration for S4 in milliseconds", paramNum: 49, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms" + ], + [ + name: "Selected Duration for S5 in milliseconds", paramNum: 50, size: 2, default: 500, type: "number", min: 200 , max: 5000, unit: "ms" + ], + [ + title: "Click control mode for external inputs S1-S5", description: "These Parameters defines how the relay should react when clicking the button connected to the corresponding external input. The options are: Click is disabled, Toggle switch: relay inverts state (ON to OFF, OFF to ON), Only On: Relay switches to ON state only, Only Off: Relay switches to OFF state only, Timer: On > Off: Relay output switches to ON state (contacts are closed) then after a specified time switches back to OFF state (contacts are open). The time is specified in 'Relay Timer Mode Duration' below, Timer: Off > On: Relay output switches to OFF state (contacts are open) then after a specified time switches back to On state (contacts are closed). The time is specified in 'Relay Timer Mode Duration' below ", name: "Selected Click Control Mode for S1", + options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 51, size: 1, default: "1", type: "enum" + ], + [ + name: "Selected Click Control Mode for S2", + options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 52, size: 1, default: "1", type: "enum" + ], + [ + name: "Selected Click Control Mode for S3", + options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 53, size: 1, default: "1", type: "enum" + ], + [ + name: "Selected Click Control Mode for S4", options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 54, size: 1, default: "1", type: "enum" + ], + [ + name: "Selected Click Control Mode for S5", + options: [ + 0: "Click is disabled", + 1: "Toggle Switch", + 2: "Only On", + 3: "Only Off", + 4: "Timer: On > Off", + 5: "Timer: Off > On" + ], paramNum: 55, size: 1, default: "1", type: "enum" + ], + [ + title: "Relays Timer Mode Duration", description: "These parameters specify the duration in seconds for the Timer modes for Click Control Mode above. Press the button and the relay output goes to ON/OFF for the specified time then changes back to OFF/ON. If the value is set to “0” the relay output will operate as a short contact (duration is about 0.5 sec)", + name: "Selected Relay 1 Timer Mode Duration in seconds", paramNum: 71, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s" + ], + [ + name: "Selected Relay 2 Timer Mode Duration in seconds", paramNum: 72, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s" + ], + [ + name: "Selected Relay 3 Timer Mode Duration in seconds", paramNum: 73, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s" + ], + [ + name: "Selected Relay 4 Timer Mode Duration in seconds", paramNum: 74, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s" + ], + [ + name: "Selected Relay 5 Timer Mode Duration in seconds", paramNum: 75, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s" + ], + [ + title: "External Input Number for Relays Output Control", description: "These Parameters defines the relays control source.", name: "Selected Relay 1 Control Source", + options: [ + 0: "Controlled by gateway", + 1: "Controlled by S1", + 2: "Controlled by S2", + 3: "Controlled by S3", + 4: "Controlled by S4", + 5: "Controlled by S5" + ], paramNum: 61, size: 1, default: "1", type: "enum" + ], + [ + name: "Selected Relay 2 Control Source", + options: [ + 0: "Controlled by gateway", + 1: "Controlled by S1", + 2: "Controlled by S2", + 3: "Controlled by S3", + 4: "Controlled by S4", + 5: "Controlled by S5" + ], paramNum: 62, size: 1, default: "2", type: "enum" + ], + [ + name: "Selected Relay 3 Control Source", + options: [ + 0: "Controlled by gateway", + 1: "Controlled by S1", + 2: "Controlled by S2", + 3: "Controlled by S3", + 4: "Controlled by S4", + 5: "Controlled by S5" + ], paramNum: 63, size: 1, default: "3", type: "enum" + ], + [ + name: "Selected Relay 4 Control Source", + options: [ + 0: "Controlled by gateway", + 1: "Controlled by S1", + 2: "Controlled by S2", + 3: "Controlled by S3", + 4: "Controlled by S4", + 5: "Controlled by S5" + ], paramNum: 64, size: 1, default: "4", type: "enum" + ], + [ + name: "Selected Relay 5 Control Source", + options: [ + 0: "Controlled by gateway", + 1: "Controlled by S1", + 2: "Controlled by S2", + 3: "Controlled by S3", + 4: "Controlled by S4", + 5: "Controlled by S5" + ], paramNum: 65, size: 1, default: "5", type: "enum" + ], + [ + title: "Retore Relays State", description: "This parameter determines if the last relay state should be restored after power failure or not. These parameters are available on firmware V1.4 or higher", name: "Selected Mode for Relay 1", + options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 66, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Mode for Relay 2", + options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 67, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Mode for Relay 3", + options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 68, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Mode for Relay 4", + options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 69, size: 1, default: "0", type: "enum" + ], + [ + name: "Selected Mode for Relay 5", + options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 70, size: 1, default: "0", type: "enum" + ], + [ + title: "Relay Inverse Mode", description: "The values in this Parameter specify the relays that will operate in inverse mode. Relays can operate in an inverse mode in two different ways: 1. When the first and the second relays are connected to two different external switches. In this case, after pressing a button, the corresponding relay connected to that button will toggle its state (ON to OFF or OFF to ON), and the other relay will be switched OFF. 2. When two relays are connected to the same external switch. In this case, the relays will operate in roller shutter mode and their behavior will follow these four cycles: a - 1st press of button: the first relay will be switched ON, the second relay will be switched OFF, b - 2nd press of button: both relays will be switched OFF, c - 3rd press of button: the second relay will be switched ON, the first relay will be switched OFF, d - 4th press of button: both relays will be switched OFF. ≡ Note: In this mode, both relays cannot be switched ON at the same time (i.e. simultaneously). ≡ Note: Switching OFF one relay will always operate before switching ON another relay to prevent both relays from being ON at the same time.", name: "Group 1", + options: [ + 0: "Disabled", + 12: "1st & 2nd Relay", + 13: "1st & 3rd Relay", + 14: "1st & 4th Relay", + 15: "1st & 5th Relay", + 23: "2nd & 3rd Relay", + 24: "2nd & 4th Relay", + 25: "2nd & 5th Relay", + 34: "3rd & 4th Relay", + 35: "3rd & 5th Relay", + 45: "4th & 5th Relay" + ], paramNum: 101, size: 1, default: "0", type: "enum" + ], + [ + name: "Group 2", + options: [ + 0: "Disabled", + 12: "1st & 2nd Relay", + 13: "1st & 3rd Relay", + 14: "1st & 4th Relay", + 15: "1st & 5th Relay", + 23: "2nd & 3rd Relay", + 24: "2nd & 4th Relay", + 25: "2nd & 5th Relay", + 34: "3rd & 4th Relay", + 35: "3rd & 5th Relay", + 45: "4th & 5th Relay" + ], paramNum: 102, size: 1, default: "0", type: "enum" + ], + [ + title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min" + ], + [ + title: "Control Energy Meter Report", description: "This Parameter determines if the change in the energy meter will result in a report being sent to the gateway. Note: When the device is turning ON, the consumption data will be sent to the gateway once, even if the report is disabled.", name: "Sending Energy Meter Reports", + options: [ + 0: "Disabled", + 1: "Enabled" + ], paramNum: 142, size: 1, default: "1", type: "enum" + ] +]} \ No newline at end of file From 467fbf2218569a39e5c271417358e70f1969fa73 Mon Sep 17 00:00:00 2001 From: mikesip Date: Wed, 26 Jan 2022 10:23:57 -0700 Subject: [PATCH 113/184] Update fibaro-heat-controller.groovy --- .../fibaro-heat-controller.src/fibaro-heat-controller.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy index c535e6ab08d..6483e7c6683 100644 --- a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy +++ b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy @@ -27,6 +27,7 @@ metadata { command "switchMode" fingerprint mfr: "010F", prod: "1301", model: "1000", deviceJoinName: "Fibaro Thermostat" //Fibaro Heat Controller + fingerprint mfr: "010F", prod: "1301", model: "1001", deviceJoinName: "Fibaro Thermostat" //Fibaro Heat Controller } tiles(scale: 2) { @@ -367,4 +368,4 @@ private changeTemperatureSensorStatus(status) { state.isChildOnline = (status == "online") def map = [name: "DeviceWatch-DeviceStatus", value: status] sendEventToChild(map, true) -} \ No newline at end of file +} From 936f000c203c4259ff359cc0aa2543493d553624 Mon Sep 17 00:00:00 2001 From: AltyorFig <95210115+AltyorFig@users.noreply.github.com> Date: Thu, 27 Jan 2022 10:22:48 +0100 Subject: [PATCH 114/184] DevWs for NodOn containing containing NodOn lighting Switch (#77558) * DevWs for NodOn containing containing NodOn lighting Switch --- .../zigbee-multi-switch.src/zigbee-multi-switch.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index e9889fd7c2e..4be9b697ea0 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -90,6 +90,10 @@ metadata { fingerprint manufacturer: "LELLKI", model: "JZ-ZB-005", deviceJoinName: "LELLKI Switch 1" //LELLKI 5 Gang Switch 1 // Raw Description 01 0104 0100 00 05 0000 0003 0004 0005 0006 01 0000 fingerprint manufacturer: "LELLKI", model: "JZ-ZB-006", deviceJoinName: "LELLKI Switch 1" //LELLKI 6 Gang Switch 1 + + // NodOn + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 0008, FC57", outClusters: "0021", manufacturer: "NodOn", model: "SIN-4-2-20", deviceJoinName: "NodOn Light 1" + // SiHAS Switch (2~6 Gang) fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z2", deviceJoinName: "SiHAS Switch 1" fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z3", deviceJoinName: "SiHAS Switch 1" From 1db5257c626bada1716d95a05e6161d44efe4074 Mon Sep 17 00:00:00 2001 From: AltyorFig <95210115+AltyorFig@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:31:23 +0100 Subject: [PATCH 115/184] DevWs for NodOn containing containing NodOn Roller Shutter (#77656) * DevWs for NodOn containing containing NodOn Roller Shutter * change devicejoinname in NodOn Window Treatment --- .../zigbee-window-shade.src/zigbee-window-shade.groovy | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) mode change 100755 => 100644 devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy diff --git a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy old mode 100755 new mode 100644 index 6bb2b707b3a..0bc16af7238 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -27,6 +27,9 @@ metadata { capability "Switch Level" command "pause" + + // NodOn + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0021", manufacturer: "NodOn", model: "SIN-4-RS-20", deviceJoinName: "NodOn Window Treatment" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "eZEX Window Treatment" // SY-IoT201-BD //SOMFY Blind Controller/eZEX fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.6", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) @@ -305,4 +308,4 @@ def isSomfy() { device.getDataValue("manufacturer") == "SOMFY" } -private getGLYDEA_MOVE_THRESHOLD() { 3 } +private getGLYDEA_MOVE_THRESHOLD() { 3 } \ No newline at end of file From b358278d3d80f0fdf658162a10ebe5e347981a71 Mon Sep 17 00:00:00 2001 From: "jiangsy@3reality.com" <72915227+jiangshanyang0203@users.noreply.github.com> Date: Sun, 30 Jan 2022 19:34:46 +0800 Subject: [PATCH 116/184] Update Orvibo-Contact-Sensor.groovy add manufacturer == "THIRDREALITY" in order to pair v21 --- .../Orvibo-Contact-Sensor.groovy | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index a33260a3676..0df9da8f9a7 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -36,6 +36,7 @@ metadata { fingerprint manufacturer: "Aurora", model: "DoorSensor50AU", deviceJoinName: "Aurora Open/Closed Sensor" // Raw Description: 01 0104 0402 00 06 0000 0001 0003 0020 0500 0B05 01 0019 //Aurora Smart Door/Window Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "HEIMAN", model: "DoorSensor-N", deviceJoinName: "HEIMAN Open/Closed Sensor" //HEIMAN Door Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RDS17BZ", deviceJoinName: "ThirdReality Door Sensor" //ThirdReality Door Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0019", manufacturer: "THIRDREALITY", model: "3RDS17BZ", deviceJoinName: "ThirdReality Door Sensor" //ThirdReality Door Sensor } simulator { @@ -110,7 +111,7 @@ def installed() { log.debug "call installed()" def manufacturer = getDataValue("manufacturer") - if (manufacturer == "Third Reality, Inc") { + if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY" ) { //ThirdReality Door Sensor do not set checkInterval for power-saving. } else { sendEvent(name: "checkInterval", value:20 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) @@ -139,7 +140,7 @@ def refresh() { def configure() { def manufacturer = getDataValue("manufacturer") - if (manufacturer == "Third Reality, Inc") { + if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { //ThirdReality Door Sensor do not set checkInterval for power-saving. } else if (manufacturer == "eWeLink") { sendEvent(name: "checkInterval", value:2 * 60 * 60 + 5 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) @@ -154,7 +155,7 @@ def configure() { cmds = zigbee.enrollResponse() + zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 30, 60 * 5, null) + zigbee.batteryConfig() } else if (manufacturer == "eWeLink" || manufacturer == "HEIMAN") { cmds = zigbee.enrollResponse() + zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 30, 60 * 5, null) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 600, 1) - } else if (manufacturer == "Third Reality, Inc") { + } else if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { cmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } cmds += refresh() @@ -168,7 +169,7 @@ def getBatteryPercentageResult(rawValue) { if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if (manufacturer == "Third Reality, Inc") { + if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From c681d4877f3bc048f3cff51fb9e6a60688714ec1 Mon Sep 17 00:00:00 2001 From: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Date: Wed, 9 Feb 2022 09:15:06 +0100 Subject: [PATCH 117/184] Allow non-zero power meter values only when device is not idle (#77720) --- .../qubino-flush-thermostat.src/qubino-flush-thermostat.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy index e6a7a539959..372f1852c66 100644 --- a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy +++ b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy @@ -198,7 +198,8 @@ def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { if (cmd.scale == 0) { createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kWh") } else if (cmd.scale == 2) { - createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W") + def powerValue = device.currentValue("thermostatOperatingState") != "idle" ? Math.round(cmd.scaledMeterValue) : 0 + createEvent(name: "power", value: powerValue, unit: "W") } } } From 99c44dd91cc991e70e2ca215619dbc01ec8afdb3 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Wed, 9 Feb 2022 04:31:47 -0500 Subject: [PATCH 118/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZSE44 Temperature | Humidity XS Sensor (#77644) * DevWs for Zooz (The Smartest House) containing containing Zooz ZSE44 Temperature | Humidity XS Sensor * - made requested changes to ZSE44 DTH * Replaced temperatureAlarm custom capability with built-in capability. * made requested changes --- ...se44-temperature-humidity-xs-sensor.groovy | 421 ++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 devicetypes/zooz/zooz-zse44-temperature-humidity-xs-sensor.src/zooz-zse44-temperature-humidity-xs-sensor.groovy diff --git a/devicetypes/zooz/zooz-zse44-temperature-humidity-xs-sensor.src/zooz-zse44-temperature-humidity-xs-sensor.groovy b/devicetypes/zooz/zooz-zse44-temperature-humidity-xs-sensor.src/zooz-zse44-temperature-humidity-xs-sensor.groovy new file mode 100644 index 00000000000..4a7fc7530f4 --- /dev/null +++ b/devicetypes/zooz/zooz-zse44-temperature-humidity-xs-sensor.src/zooz-zse44-temperature-humidity-xs-sensor.groovy @@ -0,0 +1,421 @@ +/* + * Zooz ZSE44 Temperature | Humidity XS Sensor + * + * Changelog: + * + * 2022-02-01 + * - Requested changes + * + * 2022-01-27 + * - Replaced temperatureAlarm custom capability with built-in capability. + * + * 2022-01-26.2 + * - Requested Changes + * + * 2022-01-26 + * - Publication Release + * + * Copyright 2022 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x31: 5, // SensorMultilevel + 0x55: 1, // Transport Service v2 + 0x59: 1, // AssociationGrpInfo v3 + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo v2 + 0x6C: 1, // Supervision + 0x70: 2, // Configuration v4 + 0x71: 3, // Notification v4 + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd v5 + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association v3 + 0x86: 1, // Version v2 + 0x87: 1, // Indicator v3 + 0x8E: 2, // Multi Channel Association v4 + 0x9F: 1 // Security 2 +] + +@Field static Map configParams = [ + lowBatteryReports: [num:2, title:"Low Battery Reports", size:1, defaultVal:10, options:[10:"10% [DEFAULT]", 20:"20%", 30:"30%", 40:"40%", 50:"50%"]], + tempReportingThreshold: [num:3, title:"Temperature Reporting Threshold", size:1, defaultVal:10, range:"10..100", desc:"10..100 (10 = 1°)"], + tempReportingInterval: [num:16, title:"Temperature Reporting Interval", size:2, defaultVal:240, range:"0..480", desc:"0(disabled), 1..480(minutes)"], + tempUnit: [num:13, title:"Temperature Unit", size:1, defaultVal:1, options:[0:"Celsius", 1:"Fahrenheit [DEFAULT]"]], + tempOffset: [num:14, title:"Temperature Offset", size:1, defaultVal:100, range:"0..200", desc:"0..200 (0: -10°, 100: 0°, 200: +10°)"], + highTempThreshold: [num:5, title:"Heat Alert Temperature", size:1, defaultVal:120, range:"50..120", desc:"50..120(°)"], + lowTempThreshold: [num:7, title:"Freeze Alert Temperature", size:1, defaultVal:10, range:"10..100", desc:"10..100(°)"], + humidityReportingThreshold: [num:4, title:"Humidity Reporting Threshold", size:1, defaultVal:5, range:"1..50", desc:"1..50(%)"], + humidityReportingInterval: [num:17, title:"Humidity Reporting Interval", size:2, defaultVal:240, range:"0..480", desc:"0(disabled), 1..480(minutes)"], + humidityOffset: [num:15, title:"Humidity Offset", size:1, defaultVal:100, range:"0..200", desc:"0..200 (0: -10%, 100: 0%, 200: +10%)"], + highHumidityThreshold: [num:9, title:"High Humidity Alert Level", size:1, defaultVal:0, range:"0..100", desc:"0(disabled), 1..100(%)"], + lowHumidityThreshold: [num:11, title:"Low Humidity Alert Level", size:1, defaultVal:0, range:"0..100", desc:"0(disabled), 1..100(%)"] +] + +@Field static Map temperatureSensor = [sensorType:1, scale:1] +@Field static Map humiditySensor = [sensorType: 5, scale:0] +@Field static Map temperatureAlarm = [name:"temperatureAlarm", notificationType:4, eventValues:[0:"cleared", 2:"heat", 6:"freeze"]] +@Field static Map humidityAlarm = [name:"humidityAlarm", notificationType:16, eventValues:[0:"normal", 2:"high", 6:"low"]] +@Field static int wakeUpInterval = 43200 + +metadata { + definition ( + name: "Zooz ZSE44 Temperature | Humidity XS Sensor", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType:"oic.d.thermostat", + vid: "b68c78d7-bd01-3717-a2ac-d1d55ce5ef73", + mnmn: "SmartThingsCommunity" + ) { + capability "Sensor" + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + capability "Battery" + capability "Refresh" + capability "Health Check" + capability "Configuration" + capability "platemusic11009.temperatureHumiditySensor" + capability "temperatureAlarm" + capability "platemusic11009.humidityAlarm" + capability "platemusic11009.firmware" + capability "platemusic11009.syncStatus" + + // zw:Ss2a type:0701 mfr:027A prod:7000 model:E004 ver:1.10 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,85,8E,59,31,72,5A,87,73,80,71,70,84,7A + fingerprint mfr:"027A", prod:"7000", model:"E004", deviceJoinName: "Zooz Multipurpose Sensor" // Zooz ZSE44 Temperature | Humidity XS Sensor + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + description: "Default: ${param.options[param.defaultVal]}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input name, "number", + title: param.title, + description: "${param.desc} - Default: ${param.defaultVal}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + + input "debugLogging", "enum", + title: "Logging:", + description: "Default: Enabled", + required: false, + defaultValue: "1", + options: ["0":"Disabled", "1":"Enabled"] + } +} + +def installed() { + logDebug "installed()..." + state.pendingRefresh = true + initialize() +} + +def updated() { + logDebug "updated()..." + initialize() + + if (pendingChanges) { + logForceWakeupMessage("The setting changes will be sent to the device the next time it wakes up.") + } +} + +void initialize() { + state.debugLoggingEnabled = (safeToInt(settings?.debugLogging, 1) != 0) + + refreshSyncStatus() + + if (device.currentValue("temperatureHumidity") == null) { + state.displayHumidity = " " + state.displayTemperature = " " + sendEvent(name:"temperatureHumidity", value:" ") + } + + if (!device.currentValue("temperatureAlarm")) { + sendEvent(name:"temperatureAlarm", value:"cleared") + } + + if (!device.currentValue("humidityAlarm")) { + sendEvent(name:"humidityAlarm", value:"normal") + } + + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((wakeUpInterval * 2) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } +} + +def refresh() { + logDebug "refresh()..." + refreshSyncStatus() + state.pendingRefresh = true + logForceWakeupMessage("The device will be refreshed the next time it wakes up.") +} + +void logForceWakeupMessage(String msg) { + log.warn "${msg} To force the device to wake up immediately press the action button 4x quickly." +} + +def configure() { + logDebug "configure()..." + sendHubCommand(getRefreshCmds(), 250) +} + +List getRefreshCmds() { + List cmds = [] + + if (state.wakeUpInterval == null) { + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + if (state.pendingRefresh || !device.currentValue("battery")) { + cmds << secureCmd(zwave.batteryV1.batteryGet()) + } + + if (state.pendingRefresh || (device.currentValue("temperature") == null)) { + cmds << secureCmd(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: temperatureSensor.scale, sensorType: temperatureSensor.sensorType)) + } + + if (state.pendingRefresh || (device.currentValue("humidity") == null)) { + cmds << secureCmd(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: humiditySensor.scale, sensorType: humiditySensor.sensorType)) + } + + if (state.pendingRefresh || !device.currentValue("firmwareVersion")) { + cmds << secureCmd(zwave.versionV1.versionGet()) + } + + state.pendingRefresh = false + return cmds +} + +List getConfigureCmds() { + List cmds = [] + + int changes = pendingChanges + if (changes) { + log.warn "Syncing ${changes} Change(s)" + } + + if (state.wakeUpInterval != wakeUpInterval) { + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalSet(seconds: wakeUpInterval, nodeid:zwaveHubNodeId)) + cmds << secureCmd(zwave.wakeUpV2.wakeUpIntervalGet()) + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + logDebug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + return cmds +} + +def ping() { + logDebug "ping()" +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + logDebug "Device Woke Up..." + List cmds = [] + + cmds += getRefreshCmds() + cmds += getConfigureCmds() + + if (!cmds) { + cmds << secureCmd(zwave.batteryV1.batteryGet()) + } + + cmds << secureCmd(zwave.wakeUpV2.wakeUpNoMoreInformation()) + sendHubCommand(cmds, 250) +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { + logDebug "Wake Up Interval = ${cmd.seconds} seconds" + state.wakeUpInterval = cmd.seconds + refreshSyncStatus() +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + Integer val = (cmd.batteryLevel == 0xFF ? 1 : cmd.batteryLevel) + if (val > 100) { + val = 100 + } + logDebug "Battery is ${val}%" + sendEvent(name:"battery", value:val, unit:"%", isStateChange: true) +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + logDebug "${cmd}" + switch (cmd.notificationType) { + case temperatureAlarm.notificationType: + sendAlarmEvent(temperatureAlarm, cmd.event) + break + case humidityAlarm.notificationType: + sendAlarmEvent(humidityAlarm, cmd.event) + break + default: + logDebug "${cmd}" + } +} + +void sendAlarmEvent(Map alarm, int notificationEvent) { + String value = alarm.eventValues[notificationEvent] + if (value) { + logDebug "${alarm.name} is ${value}" + sendEvent(name: alarm.name, value: value) + } +} + +void zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + switch (cmd.sensorType) { + case temperatureSensor.sensorType: + def temperature = convertTemperatureIfNeeded(cmd.scaledSensorValue, (cmd.scale ? "F" : "C"), cmd.precision) + sendTemperatureEvent(temperature) + break + case humiditySensor.sensorType: + sendHumidityEvent(cmd.scaledSensorValue) + break + default: + logDebug "Unhandled: ${cmd}" + } +} + +void sendTemperatureEvent(value) { + state.displayTemperature = "${value}°${temperatureScale}" + logDebug "temperature is ${value}°${temperatureScale}" + sendEvent(name: "temperature", value: value, unit: temperatureScale) + sendTemperatureHumidityEvent() +} + +void sendHumidityEvent(value) { + state.displayHumidity = "${safeToInt(value)}%" + logDebug "humidity is ${value}%" + sendEvent(name: "humidity", value: value, unit: "%") + sendTemperatureHumidityEvent() +} + +void sendTemperatureHumidityEvent() { + sendEvent(name: "temperatureHumidity", value: "${state.displayTemperature} | ${state.displayHumidity}", displayed: false) +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + logDebug "${cmd}" + sendEvent(name: "firmwareVersion", value: (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + runIn(4, refreshSyncStatus) + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + + if ((val < 0) && ((name == "humidityOffset") || (name == "tempOffset"))) { + val = (val + 256) + } + + state[name] = val + logDebug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + logDebug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + logDebug "Unhandled zwaveEvent: ${cmd}" +} + +void refreshSyncStatus() { + int changes = pendingChanges + sendEvent(name: "syncStatus", value: (changes ? "${changes} Pending Changes" : "Synced"), displayed: false) +} + +Integer getPendingChanges() { + int configChanges = configParams.count { name, param -> + (getSettingVal(name) != getStoredVal(name)) + } + int pendingWakeUpInterval = (state.wakeUpInterval != wakeUpInterval ? 1 : 0) + return (configChanges + pendingWakeUpInterval) +} + +Integer getSettingVal(String name) { + Integer value = safeToInt(settings[name], null) + if ((value == null) && (getStoredVal(name) != null)) { + return configParams[name].defaultVal + } else { + return value + } +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +void logDebug(String msg) { + if (state.debugLoggingEnabled != false) { + log.debug "$msg" + } +} \ No newline at end of file From 3ce2797fde2cdec86809c229ed1a45ecfec803f9 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 15 Feb 2022 09:35:25 +0900 Subject: [PATCH 119/184] DevWs for SHINA SYSTEM containing containing SiHAS Zigbee Metering Plug (#77702) * DevWs for SHINA SYSTEM containing containing SiHAS Zigbee Metering Plug * Update sihas-zigbee-metering-plug.groovy Formatting: comma between clusterInt and attrInt --- .../sihas-zigbee-metering-plug.groovy | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy diff --git a/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy b/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy new file mode 100644 index 00000000000..c400f0255c0 --- /dev/null +++ b/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy @@ -0,0 +1,175 @@ +/** + * Copyright 2022 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: "SiHAS Zigbee Metering Plug", namespace: "shinasys", author: "SHINA SYSTEM", mnmn: "SmartThingsCommunity", ocfDeviceType: "oic.d.smartplug", vid: "12d61425-2258-376a-beee-7a69fbc0d9fe") { + capability "Energy Meter" + capability "Power Meter" + capability "Refresh" + capability "Health Check" + capability "Sensor" + capability "Configuration" + capability "Voltage Measurement" + capability "afterguide46998.currentMeasurement" + capability "afterguide46998.frequencyMeasurement" + capability "afterguide46998.powerfactorMeasurement" + capability "Temperature Measurement" + capability "Switch" + + fingerprint profileId: "0104", manufacturer: "ShinaSystem", model: "CCM-300Z2", deviceJoinName: "SiHAS Outlet" // SIHAS Zigbee Metering Plug 01 0104 0000 01 06 0000 0004 0003 0006 0B04 0702 02 0004 0019 + } +} + +def getATTRIBUTE_READING_INFO_SET() { 0x0000 } +def getATTRIBUTE_HISTORICAL_CONSUMPTION() { 0x0400 } +def getATTRIBUTE_ACTIVE_POWER() { 0x050B } +def getATTRIBUTE_FREQUENCY() { 0x0300 } +def getATTRIBUTE_VOLTAGE() { 0x0505 } +def getATTRIBUTE_CURRENT() { 0x0508 } +def getATTRIBUTE_POWERFACTOR() { 0x0510 } +def getTEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 } + +def convertHexToInt24Bit(value) { + int result = zigbee.convertHexToInt(value) + if (result & 0x800000) { + result |= 0xFF000000 + } + return result +} + +def parse(String description) { + log.debug "description is $description" + def event = zigbee.getEvent(description) + def descMap = zigbee.parseDescriptionAsMap(description) + + if (event) { + log.info "event enter:$event" + if (event.name == "switch") { + return sendEvent(event) + } else if (event.name == "temperature") { + return sendEvent(event) + } + } + + if (descMap) { + List result = [] + log.debug "Desc Map: $descMap" + + List attrData = [[clusterInt: descMap.clusterInt, attrInt: descMap.attrInt, value: descMap.value, isValidForDataType: descMap.isValidForDataType]] + descMap.additionalAttrs.each { + attrData << [clusterInt: descMap.clusterInt, attrInt: it.attrInt, value: it.value, isValidForDataType: it.isValidForDataType] + } + attrData.each { + def map = [:] + if (it.isValidForDataType && (it.value != null)) { + if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { + log.debug "meter" + map.name = "power" + map.value = convertHexToInt24Bit(it.value)/powerDivisor + map.unit = "W" + } else if (it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { + log.debug "energy" + map.name = "energy" + map.value = zigbee.convertHexToInt(it.value)/energyDivisor + map.unit = "kWh" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_FREQUENCY) { + log.debug "frequency" + map.name = "frequency" + map.value = zigbee.convertHexToInt(it.value)/frequencyDivisor + map.unit = "Hz" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_VOLTAGE) { + log.debug "voltage" + map.name = "voltage" + map.value = zigbee.convertHexToInt(it.value)/voltageDivisor + map.unit = "V" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_CURRENT) { + log.debug "current" + map.name = "current" + map.value = zigbee.convertHexToInt(it.value)/currentDivisor + map.unit = "A" + } else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_POWERFACTOR) { + log.debug "power factor" + map.name = "powerFactor" + map.value = (byte) zigbee.convertHexToInt(it.value)/powerFactorDivisor + map.unit = "%" + } else if (it.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && it.attrInt == TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE) { + log.debug "temperature" + map.name = "temperature" + map.unit = getTemperatureScale() + map.value = zigbee.parseHATemperatureValue("temperature: " + (zigbee.convertHexToInt(it.value)), "temperature: ", tempScale) + log.debug "${device.displayName}: Reported temperature is ${map.value}°$map.unit" + } + } + + if (map) { + result << createEvent(map) + } + log.debug "Parse returned $map" + } + return result + } +} + +def off() { + zigbee.off() +} + +def on() { + zigbee.on() +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return refresh() +} + +def refresh() { + log.debug "refresh " + zigbee.onOffRefresh() + + zigbee.simpleMeteringPowerRefresh() + + zigbee.readAttribute(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT) + + zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR) + + zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE) +} + +def configure() { + def configCmds = [] + // this device will send instantaneous demand and current summation delivered every 1 minute + sendEvent(name: "checkInterval", value: 2 * 60 + 10 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + + log.debug "Configuring Reporting" + configCmds = zigbee.onOffConfig() + + zigbee.simpleMeteringPowerConfig() + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 5, 600, 1) + + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY, DataType.UINT16, 10, 600, 3) + /* 3 unit : 0.3Hz */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE, DataType.UINT16, 5, 600, 3) + /* 3 unit : 0.3V */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT, DataType.UINT16, 5, 600, 1) + /* 1 unit : 0.01A */ + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR, DataType.INT8, 10, 600, 1) + /* 1 unit : 0.1% */ + zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 20, 300, 10 /* 1 uint : 0.1C */) + return configCmds + refresh() +} + +private getActivePowerDivisor() { 1 } +private getPowerDivisor() { 1 } +private getEnergyDivisor() { 1000 } +private getFrequencyDivisor() { 10 } +private getVoltageDivisor() { 10 } +private getCurrentDivisor() { 100 } +private getPowerFactorDivisor() { 1 } From cadf20d8b4e94a36ad85895f0db2110baf6454fe Mon Sep 17 00:00:00 2001 From: jahartogsveld <82935890+jahartogsveld@users.noreply.github.com> Date: Tue, 15 Feb 2022 15:11:54 +0100 Subject: [PATCH 120/184] Add Danalock Zigbee 3.0 (#77753) --- devicetypes/smartthings/zigbee-lock.src/README.md | 1 + devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy | 1 + 2 files changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-lock.src/README.md b/devicetypes/smartthings/zigbee-lock.src/README.md index 8dee77c9b7c..f54fc71a45c 100644 --- a/devicetypes/smartthings/zigbee-lock.src/README.md +++ b/devicetypes/smartthings/zigbee-lock.src/README.md @@ -13,6 +13,7 @@ Works with: * Yale Push Button Deadbolt Lock * Yale Touch Screen Deadbolt Lock * Yale Push Button Lever Lock +* Danalock Door Lock ## Table of contents diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index 299840f8888..86d164d91ae 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -49,6 +49,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "c700000202", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YDF40 fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "0700000001", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YMF40 fingerprint profileId: "0104", inClusters: "0000,0001,0003,0101", outClusters: "0000,0001,0003,0101", manufacturer: "Datek", model: "ID Lock 150", deviceJoinName: "ID Lock Door Lock" //ID Lock 150 Zigbee Module by Datek + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,0020,0101", outClusters: "0019", manufacturer: "Danalock", model: "V3-BTZBE", deviceJoinName: "Danalock Door Lock" } tiles(scale: 2) { From 0fec6f9b8a7af0586bf50e380656c9f0da8c020c Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Thu, 17 Feb 2022 04:14:43 +0900 Subject: [PATCH 121/184] WWST-7794, Add a DTH code for ABL CPX Lighting(Light with a motion sensor) (#77259) * Create led-cpx-light.groovy First commit * Create led-cpx-light.groovy First commit * Update led-cpx-light.groovy Line aligning * Delete led-cpx-light.groovy Move to other folder * Create README.md First commit * Create led-cpx-motion-sensor-child.groovy First commit * Update led-cpx-motion-sensor-child.groovy Line aligning * Update README.md Add definition of motion sensor capability * Edit codes Edit codes * Edit codes Edit codes * Edit codes Edit codes * Update led-cpx-light.groovy Delete configuration in the refresh function. Delete color temperature naming function. * Update led-cpx-light.groovy Edited conditional statement at line 73 in the parse function. * Update led-cpx-light.groovy Aligning codes. * Update led-cpx-light.groovy Edit try-catch in line 151 * Update led-cpx-light.groovy Edited and aligned codes. * Update led-cpx-motion-sensor-child.groovy Edited and aligned codes. * Update README.md Edited contents. * Update led-cpx-motion-sensor-child.groovy Removed unnecessary spaces. * Update led-cpx-light.groovy Added magic numbers and edited codes. * Update led-cpx-light.groovy Aligned codes. * Update led-cpx-light.groovy Cleaned up codes. * Update led-cpx-light.groovy Edited codes. * Update led-cpx-light.groovy Edited codes * Update zigbee-rgbw-bulb.groovy Changed the "deviceJoinName" in line @43 from "Juno Connect" to "RetroBasics RGBW" by the request of customer. * Update led-cpx-light.groovy Deleted after "runLoaclly". * Update led-cpx-light.groovy Edited codes * Update led-cpx-light.groovy Delete "runlocally:true" and add a rule to the event in parser. * Update led-cpx-light.groovy Aligned codes. * Update led-cpx-light.groovy Edited codes. * Update led-cpx-light.groovy Edited the magic number. * Update led-cpx-light.groovy Added a separate zigbeeMap for child event : zigbeeMap_child in line91. * Update led-cpx-light.groovy Aligned send child event block. --- .../zigbee-motion-sensor-light.src/README.md | 31 ++++ .../led-cpx-light.groovy | 171 ++++++++++++++++++ .../led-cpx-motion-sensor-child.groovy | 39 ++++ .../zigbee-rgbw-bulb.groovy | 2 +- 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 devicetypes/smartthings/zigbee-motion-sensor-light.src/README.md create mode 100644 devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy create mode 100644 devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-motion-sensor-child.groovy diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/README.md b/devicetypes/smartthings/zigbee-motion-sensor-light.src/README.md new file mode 100644 index 00000000000..9be7d475f69 --- /dev/null +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/README.md @@ -0,0 +1,31 @@ +# ZigBee CPX Smart Panel Light + +Cloud Execution + +Works with: + +* ABL Lithonia +* Samsung LED + +## Table of contents + +* [Capabilities](#capabilities) +* [Health](#device-health) + +## Capabilities + +* **Actuator** - represents that a Device has commands* +* **Color Temperaturer** - It represents color temperature capability measured in degree Kelvin. +* **Configuration** - _configure()_ command called when device is installed or device preferences updated. +* **Health Check** - indicates ability to get device health notifications +* **Refresh** - _refresh()_ command for status updates +* **Switch** - can detect state (possible values: on/off) +* **Switch Level** - represents current light level, usually 0-100 in percent +* **Motion Sensor** - can detect motion + +## Device Health + +Zigbee Bulb with reporting interval of 5 mins. +SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE` + +*__12min__ checkInterval diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy new file mode 100644 index 00000000000..074c8021d35 --- /dev/null +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy @@ -0,0 +1,171 @@ +/** + * Copyright 2022 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. + * + * LED CPX light + * + * Author: SAMSUNG LED + * Date: 2022-01-05 + */ + +metadata { + definition(name: "LED CPX light", namespace: "SAMSUNG LED", author: "SAMSUNG LED") { + + capability "Actuator" + capability "Color Temperature" + capability "Configuration" + capability "Health Check" + capability "Refresh" + capability "Switch" + capability "Switch Level" + + // ABL Lithonia + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Lithonia", model: "ABL-LIGHTSENSOR-Z-001", deviceJoinName: "CPX Smart Panel Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" + + // Samsung LED + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-004", deviceJoinName: "ITM CPX Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" + } + + // UI 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.light.on", backgroundColor: "#00A0DC", nextState: "turningOff" + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.light.on", backgroundColor: "#00A0DC", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action: "switch level.setLevel" + } + } + + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range: "(2700..6500)") { + state "colorTemperature", action: "color temperature.setColorTemperature" + } + + main(["switch"]) + details(["switch", "switchLevel", "colorTempSliderControl", "refresh"]) + } +} + +private getMOTION_CLUSTER() { 0x0406 } +private getMOTION_STATUS_ATTRIBUTE() { 0x0000 } +private getON_OFF_CLUSTER() { 0x0006 } +private getCONFIGURE_REPORTING_RESPONSE() { 0x07 } +private getON_DATA() { 0x01 } +private getOFF_DATA() { 0x00 } + +def parse(String description) { + def event = zigbee.getEvent(description) + def zigbeeMap = zigbee.parseDescriptionAsMap(description) + + if (event) { + if (zigbeeMap.clusterInt == ON_OFF_CLUSTER && (zigbeeMap.data[0] != ON_DATA || zigbeeMap.data[0] != OFF_DATA)) { + return + } + + if (!(event.name == "level" && event.value == 0)) { + sendEvent(event) + } + } else { + def cluster = zigbee.parse(description) + + if (cluster && cluster.clusterId == ON_OFF_CLUSTER && cluster.command == CONFIGURE_REPORTING_RESPONSE) { + if (cluster.data[0] == 0x00) { + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + } + } else { + if (zigbeeMap.clusterInt == MOTION_CLUSTER && zigbeeMap.attrInt == MOTION_STATUS_ATTRIBUTE) { + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}:1" + } + def event_child = zigbeeMap.value.endsWith("01") ? createEvent(name: "motion", value: "active") : createEvent(name: "motion", value: "inactive") + childDevice.sendEvent(event_child) + } + } + } +} + +def off() { + zigbee.off() +} + +def on() { + zigbee.on() +} + +def setLevel(value, rate=null) { + zigbee.setLevel(value) +} + +def configure() { + zigbee.configureReporting(MOTION_CLUSTER, MOTION_STATUS_ATTRIBUTE, 0x18, 30, 600, null) + + zigbee.onOffConfig() + + zigbee.levelConfig() + + refresh() +} + +def updated() { + if (!childDevices) { + addChildSensor() + } +} + +def ping() { + return zigbee.levelRefresh() +} + +def refresh() { + zigbee.readAttribute(MOTION_CLUSTER, MOTION_STATUS_ATTRIBUTE) + + zigbee.onOffRefresh() + + zigbee.levelRefresh() + + zigbee.colorTemperatureRefresh() +} + +def setColorTemperature(value) { + value = value as Integer + + zigbee.setColorTemperature(value) + + zigbee.on() + + zigbee.colorTemperatureRefresh() +} + +def installed() { + addChildSensor() +} + +def addChildSensor() { + def componentLabel + def childDevice + + if (device.displayName.endsWith(' Light') || device.displayName.endsWith(' light')) { + componentLabel = "${device.displayName[0..-6]} Motion sensor" + } else { + componentLabel = "$device.displayName Motion sensor" + } + + try { + String dni = "${device.deviceNetworkId}:1" + childDevice = addChildDevice("ITM CPX Motion sensor child", dni, device.hub.id, [completedSetup: true, label: "${componentLabel}", isComponent: false]) + if (childDevice != null) { + childDevice.sendEvent(name: "motion", value: "inactive") + } + } catch (e) { + log.warn "Failed to add ITM Fan Controller - $e" + } + + return childDevice +} diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-motion-sensor-child.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-motion-sensor-child.groovy new file mode 100644 index 00000000000..00afdb0827e --- /dev/null +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-motion-sensor-child.groovy @@ -0,0 +1,39 @@ +/** + * Copyright 2022 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. + * + * ITM CPX Motion sensor child + * + * Author: SAMSUNG LED + * Date: 2022-01-05 + */ + +metadata { + definition (name: "ITM CPX Motion sensor child", namespace: "SAMSUNG LED", author: "SAMSUNG LED", ocfDeviceType: "x.com.st.d.sensor.motion") { + capability "Motion Sensor" + capability "Refresh" + capability "Sensor" + } + + tiles(scale: 2) { + multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) { + tileAttribute("device.motion", key: "PRIMARY_CONTROL") { + attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC" + attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#cccccc" + } + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", action: "refresh.refresh", icon: "st.secondary.refresh" + } + main(["motion"]) + details(["motion", "refresh"]) + } +} diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 65dadbc811a..8177e505120 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -40,7 +40,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-002", deviceJoinName: "Samsung Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-002" //ITM RGBW // ABL - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-201", deviceJoinName: "Juno Connect", mnmn: "SmartThingsCommunity", vid: "0c0d8ed8-d536-324c-9b80-d4705a55e4df" //E-series + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-201", deviceJoinName: "RetroBasics RGBW", mnmn: "SmartThingsCommunity", vid: "0c0d8ed8-d536-324c-9b80-d4705a55e4df" //E-series // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010D", manufacturer: "AduroSmart Eria", model: "AD-RGBW3001", deviceJoinName: "Eria Light" //Eria ZigBee RGBW Bulb From 88d12fb86b0beb89fc44fa1a8e0fe6542dd62676 Mon Sep 17 00:00:00 2001 From: jeremelau <38304013+JeremeLau@users.noreply.github.com> Date: Thu, 17 Feb 2022 15:47:38 +0800 Subject: [PATCH 122/184] DevWs for YookSmart containing containing ZigBee Window Shade Battery (#76356) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for YookSmart containing containing ZigBee Window Shade Battery * commit battery report * add battery support for yooksmart * version commit * modify for the master * add raw description in the comment * remove useless tiles * restore ‘|| currentLevel == lastLevel’ in report event. But this will cause UI block when customers try to re-open the blinds when they are already open Co-authored-by: Bill Nie --- .../zigbee-window-shade-battery.groovy | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy index a67d14754f7..d2bd8427bca 100644 --- a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy +++ b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy @@ -34,9 +34,9 @@ metadata { fingerprint manufacturer: "IKEA of Sweden", model: "FYRTUR block-out roller blind", deviceJoinName: "IKEA Window Treatment" // raw description 01 0104 0202 01 09 0000 0001 0003 0004 0005 0020 0102 1000 FC7C 02 0019 1000 //IKEA FYRTUR Blinds // Yookee yooksmart - fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Yookee", model: "D10110", deviceJoinName: "Yookee Window Treatment" - fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "yooksmart", model: "D10110", deviceJoinName: "yooksmart Window Treatment" - + fingerprint manufacturer: "Yookee", model: "D10110", deviceJoinName: "Yookee Window Treatment" // raw description 01 0104 0202 01 07 0000 0001 0003 0004 0005 0020 0102 02 0003 0019 + fingerprint manufacturer: "yooksmart", model: "D10110", deviceJoinName: "yooksmart Window Treatment" // raw description 01 0104 0202 01 07 0000 0001 0003 0004 0005 0020 0102 02 0003 0019 + // SMARTWINGS fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Smartwings", model: "WM25/L-Z", deviceJoinName: "Smartwings Window Treatment" } @@ -178,7 +178,12 @@ def updateFinalState() { } def batteryPercentageEventHandler(batteryLevel) { + log.debug "batteryLevel: ${batteryLevel}" + if (batteryLevel != null) { + if (isYooksmartOrYookee()) { + batteryLevel = batteryLevel >> 1 + } batteryLevel = Math.min(100, Math.max(0, batteryLevel)) sendEvent([name: "battery", value: batteryLevel, unit: "%", descriptionText: "{{ device.displayName }} battery was {{ value }}%"]) } @@ -322,7 +327,7 @@ def shouldInvertLiftPercentage() { } def reportsBatteryPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() + return isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() } def isIkeaKadrilj() { From f5dd14065097d7fb288b86a04cda0d6215f9f774 Mon Sep 17 00:00:00 2001 From: greens Date: Thu, 24 Feb 2022 12:12:22 -0800 Subject: [PATCH 123/184] Add translation strings that were omitted. --- .../i18n/messages.properties | 580 ++++++++++++------ 1 file changed, 386 insertions(+), 194 deletions(-) diff --git a/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties b/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties index f4577247cf5..5d0b64f8a75 100644 --- a/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties @@ -349,54 +349,6 @@ '''Sound notifications status'''.tr=Sesli bildirimler '''Sound notifications status'''.uk=Звукові сповіщення '''Sound notifications status'''.vi=Thông báo âm thanh -'''24 hours'''.en=24 hours -'''24 hours'''.en-gb=24 hours -'''24 hours'''.en-us=24 hours -'''24 hours'''.en-ca=24 hours -'''24 hours'''.sq=24 orë -'''24 hours'''.ar=٢٤ ساعة -'''24 hours'''.be=24 гадзіны -'''24 hours'''.sr-ba=24 sata -'''24 hours'''.bg=24 часа -'''24 hours'''.ca=24 hores -'''24 hours'''.zh-cn=24 小时 -'''24 hours'''.zh-hk=24 小時 -'''24 hours'''.zh-tw=24 小時 -'''24 hours'''.hr=24 sata -'''24 hours'''.cs=24 hodin -'''24 hours'''.da=24 timer -'''24 hours'''.nl=24 uur -'''24 hours'''.et=24 tundi -'''24 hours'''.fi=24 tuntia -'''24 hours'''.fr=24 heures -'''24 hours'''.fr-ca=24 heures -'''24 hours'''.de=24 Stunden -'''24 hours'''.el=24 ώρες -'''24 hours'''.iw=24 שעות -'''24 hours'''.hi-in=24 घंटे -'''24 hours'''.hu=24 óra -'''24 hours'''.is=Sólarhringur -'''24 hours'''.in=24 jam -'''24 hours'''.it=24 ore -'''24 hours'''.ja=24時間 -'''24 hours'''.ko=24시간 -'''24 hours'''.lv=24 stundas -'''24 hours'''.lt=24 val. -'''24 hours'''.ms=24 jam -'''24 hours'''.no=24 timer -'''24 hours'''.pl=24 godziny -'''24 hours'''.pt=24 horas -'''24 hours'''.ro=24 de ore -'''24 hours'''.ru=24 часа -'''24 hours'''.sr=24 sata -'''24 hours'''.sk=24 hodín -'''24 hours'''.sl=24 ur -'''24 hours'''.es=24 horas -'''24 hours'''.sv=24 timmar -'''24 hours'''.th=24 ชั่วโมง -'''24 hours'''.tr=24 saat -'''24 hours'''.uk=24 години -'''24 hours'''.vi=24 giờ '''Overheat temperature threshold'''.en=Overheat temperature threshold '''Overheat temperature threshold'''.en-gb=Overheat temperature threshold '''Overheat temperature threshold'''.en-us=Overheat temperature threshold @@ -686,54 +638,6 @@ '''To check smoke detection state'''.tr=Duman algılama durumu kontrol ediliyor '''To check smoke detection state'''.uk=Перевірка стану датчика диму '''To check smoke detection state'''.vi=Kiểm tra trạng thái phát hiện khói -'''5 minutes'''.en=5 minutes -'''5 minutes'''.en-gb=5 minutes -'''5 minutes'''.en-us=5 minutes -'''5 minutes'''.en-ca=5 minutes -'''5 minutes'''.sq=5 minuta -'''5 minutes'''.ar=٥ دقائق -'''5 minutes'''.be=5 хвілін -'''5 minutes'''.sr-ba=5 minuta -'''5 minutes'''.bg=5 минути -'''5 minutes'''.ca=5 minuts -'''5 minutes'''.zh-cn=5 分钟 -'''5 minutes'''.zh-hk=5 分鐘 -'''5 minutes'''.zh-tw=5 分鐘 -'''5 minutes'''.hr=5 minuta -'''5 minutes'''.cs=5 minut -'''5 minutes'''.da=5 minutter -'''5 minutes'''.nl=5 minuten -'''5 minutes'''.et=5 minutit -'''5 minutes'''.fi=5 minuuttia -'''5 minutes'''.fr=5 minutes -'''5 minutes'''.fr-ca=5 minutes -'''5 minutes'''.de=5 Minuten -'''5 minutes'''.el=5 λεπτά -'''5 minutes'''.iw=5 דקות -'''5 minutes'''.hi-in=5 मिनट -'''5 minutes'''.hu=5 perc -'''5 minutes'''.is=5 mínútur -'''5 minutes'''.in=5 menit -'''5 minutes'''.it=5 minuti -'''5 minutes'''.ja=5分 -'''5 minutes'''.ko=5분 -'''5 minutes'''.lv=5 minūtes -'''5 minutes'''.lt=5 minutės -'''5 minutes'''.ms=5 minit -'''5 minutes'''.no=5 minutter -'''5 minutes'''.pl=5 minut -'''5 minutes'''.pt=5 minutos -'''5 minutes'''.ro=5 minute -'''5 minutes'''.ru=5 минут -'''5 minutes'''.sr=5 minuta -'''5 minutes'''.sk=5 minút -'''5 minutes'''.sl=5 minut -'''5 minutes'''.es=5 minutos -'''5 minutes'''.sv=5 minuter -'''5 minutes'''.th=5 นาที -'''5 minutes'''.tr=5 dakika -'''5 minutes'''.uk=5 хвилин -'''5 minutes'''.vi=5 phút '''Exceeding temperature threshold'''.en=Temperature threshold exceeded '''Exceeding temperature threshold'''.en-gb=Temperature threshold exceeded '''Exceeding temperature threshold'''.en-us=Temperature threshold exceeded @@ -782,55 +686,6 @@ '''Exceeding temperature threshold'''.tr=Sıcaklık eşiği aşıldı '''Exceeding temperature threshold'''.uk=Перевищено температурний поріг '''Exceeding temperature threshold'''.vi=Đã vượt ngưỡng nhiệt độ -'''30 minutes'''.en=30 minutes -'''30 minutes'''.en-gb=30 minutes -'''30 minutes'''.en-us=30 minutes -'''30 minutes'''.en-ca=30 minutes -'''30 minutes'''.en-ph=30 minutes -'''30 minutes'''.sq=30 minuta -'''30 minutes'''.ar=٣٠ دقيقة -'''30 minutes'''.be=30 хвілін -'''30 minutes'''.sr-ba=30 minuta -'''30 minutes'''.bg=30 минути -'''30 minutes'''.ca=30 minuts -'''30 minutes'''.zh-cn=30 分钟 -'''30 minutes'''.zh-hk=30 分鐘 -'''30 minutes'''.zh-tw=30 分鐘 -'''30 minutes'''.hr=30 minuta -'''30 minutes'''.cs=30 minut -'''30 minutes'''.da=30 minutter -'''30 minutes'''.nl=30 minuten -'''30 minutes'''.et=30 minutit -'''30 minutes'''.fi=30 minuuttia -'''30 minutes'''.fr=30 minutes -'''30 minutes'''.fr-ca=30 minutes -'''30 minutes'''.de=30 Minuten -'''30 minutes'''.el=30 λεπτά -'''30 minutes'''.iw=30 דקות -'''30 minutes'''.hi-in=30 मिनट -'''30 minutes'''.hu=30 perc -'''30 minutes'''.is=30 mínútur -'''30 minutes'''.in=30 menit -'''30 minutes'''.it=30 minuti -'''30 minutes'''.ja=30分 -'''30 minutes'''.ko=30분 -'''30 minutes'''.lv=30 minūtes -'''30 minutes'''.lt=30 minučių -'''30 minutes'''.ms=30 minit -'''30 minutes'''.no=30 minutter -'''30 minutes'''.pl=30 minut -'''30 minutes'''.pt=30 minutos -'''30 minutes'''.ro=30 de minute -'''30 minutes'''.ru=30 минут -'''30 minutes'''.sr=30 minuta -'''30 minutes'''.sk=30 minút -'''30 minutes'''.sl=30 min -'''30 minutes'''.es=30 minutos -'''30 minutes'''.sv=30 minuter -'''30 minutes'''.th=30 นาที -'''30 minutes'''.tr=30 dakika -'''30 minutes'''.uk=30 хвилин -'''30 minutes'''.vi=30 phút '''Instructions'''.en=Getting started '''Instructions'''.en-gb=Getting started '''Instructions'''.en-us=Getting started @@ -1314,55 +1169,6 @@ '''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.tr=Yükleme işleminden sonra, cihazın durumunu ve yapılandırmasını güncellemek için Fibaro Duman Sensörünüzde B tuşuna basın. '''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.uk=Після встановлення натисніть кнопку B на датчику диму Fibaro, щоб оновити стан і конфігурацію пристрою. '''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.vi=Sau khi cài đặt, nhấn phím B trên Cảm biến khói Fibaro của bạn để cập nhật trạng thái và cấu hình của thiết bị. -'''1 hour'''.en=1 hour -'''1 hour'''.en-gb=1 hour -'''1 hour'''.en-us=1 hour -'''1 hour'''.en-ca=1 hour -'''1 hour'''.en-ph=1 hour -'''1 hour'''.sq=1 orë -'''1 hour'''.ar=ساعة واحدة -'''1 hour'''.be=1 гадзіна -'''1 hour'''.sr-ba=Jedan sat -'''1 hour'''.bg=1 час -'''1 hour'''.ca=1 hora -'''1 hour'''.zh-cn=1 小时 -'''1 hour'''.zh-hk=1 小時 -'''1 hour'''.zh-tw=1 小時 -'''1 hour'''.hr=1 sat -'''1 hour'''.cs=1 hodina -'''1 hour'''.da=1 time -'''1 hour'''.nl=1 uur -'''1 hour'''.et=1 tund -'''1 hour'''.fi=1 tunti -'''1 hour'''.fr=1 heure -'''1 hour'''.fr-ca=1 heure -'''1 hour'''.de=1 Stunde -'''1 hour'''.el=1 ώρα -'''1 hour'''.iw=שעה אחת -'''1 hour'''.hi-in=1 घंटा -'''1 hour'''.hu=1 óra -'''1 hour'''.is=1 klukkustund -'''1 hour'''.in=1 jam -'''1 hour'''.it=1 ora -'''1 hour'''.ja=1時間 -'''1 hour'''.ko=1시간 -'''1 hour'''.lv=1 stunda -'''1 hour'''.lt=1 val. -'''1 hour'''.ms=1 jam -'''1 hour'''.no=1 time -'''1 hour'''.pl=1 godzina -'''1 hour'''.pt=1 hora -'''1 hour'''.ro=1 oră -'''1 hour'''.ru=1 час -'''1 hour'''.sr=Jedan sat -'''1 hour'''.sk=1 hodina -'''1 hour'''.sl=1 h -'''1 hour'''.es=1 hora -'''1 hour'''.sv=En timme -'''1 hour'''.th=1 ชั่วโมง -'''1 hour'''.tr=1 saat -'''1 hour'''.uk=1 година -'''1 hour'''.vi=1 giờ '''Visual indicator notifications status'''.en=Visual indicator notifications '''Visual indicator notifications status'''.en-gb=Visual indicator notifications '''Visual indicator notifications status'''.en-us=Visual indicator notifications @@ -1460,4 +1266,390 @@ '''All'''.tr=Tümü '''All'''.uk=Усі '''All'''.vi=Tất cả +'''5 minutes'''.en=5 minutes +'''5 minutes'''.en-gb=5 minutes +'''5 minutes'''.en-us=5 minutes +'''5 minutes'''.en-ca=5 minutes +'''5 minutes'''.sq=5 minuta +'''5 minutes'''.ar=٥ دقائق +'''5 minutes'''.be=5 хвілін +'''5 minutes'''.sr-ba=5 minuta +'''5 minutes'''.bg=5 минути +'''5 minutes'''.ca=5 minuts +'''5 minutes'''.zh-cn=5 分钟 +'''5 minutes'''.zh-hk=5 分鐘 +'''5 minutes'''.zh-tw=5 分鐘 +'''5 minutes'''.hr=5 minuta +'''5 minutes'''.cs=5 minut +'''5 minutes'''.da=5 minutter +'''5 minutes'''.nl=5 minuten +'''5 minutes'''.et=5 minutit +'''5 minutes'''.fi=5 minuuttia +'''5 minutes'''.fr=5 minutes +'''5 minutes'''.fr-ca=5 minutes +'''5 minutes'''.de=5 Minuten +'''5 minutes'''.el=5 λεπτά +'''5 minutes'''.iw=5 דקות +'''5 minutes'''.hi-in=5 मिनट +'''5 minutes'''.hu=5 perc +'''5 minutes'''.is=5 mínútur +'''5 minutes'''.in=5 menit +'''5 minutes'''.it=5 minuti +'''5 minutes'''.ja=5分 +'''5 minutes'''.ko=5분 +'''5 minutes'''.lv=5 minūtes +'''5 minutes'''.lt=5 minutės +'''5 minutes'''.ms=5 minit +'''5 minutes'''.no=5 minutter +'''5 minutes'''.pl=5 minut +'''5 minutes'''.pt=5 minutos +'''5 minutes'''.ro=5 minute +'''5 minutes'''.ru=5 минут +'''5 minutes'''.sr=5 minuta +'''5 minutes'''.sk=5 minút +'''5 minutes'''.sl=5 minut +'''5 minutes'''.es=5 minutos +'''5 minutes'''.sv=5 minuter +'''5 minutes'''.th=5 นาที +'''5 minutes'''.tr=5 dakika +'''5 minutes'''.uk=5 хвилин +'''5 minutes'''.vi=5 phút +'''15 minutes'''.en=15 minutes +'''15 minutes'''.en-gb=15 minutes +'''15 minutes'''.en-us=15 minutes +'''15 minutes'''.en-ca=15 minutes +'''15 minutes'''.sq=15 minuta +'''15 minutes'''.ar=١٥ دقيقة +'''15 minutes'''.be=15 хвілін +'''15 minutes'''.sr-ba=15 minuta +'''15 minutes'''.bg=15 минути +'''15 minutes'''.ca=15 minuts +'''15 minutes'''.zh-cn=15 分钟 +'''15 minutes'''.zh-hk=15 分鐘 +'''15 minutes'''.zh-tw=15 分鐘 +'''15 minutes'''.hr=15 minuta +'''15 minutes'''.cs=15 minut +'''15 minutes'''.da=15 minutter +'''15 minutes'''.nl=15 minuten +'''15 minutes'''.et=15 minutit +'''15 minutes'''.fi=15 minuuttia +'''15 minutes'''.fr=15 minutes +'''15 minutes'''.fr-ca=15 minutes +'''15 minutes'''.de=15 Minuten +'''15 minutes'''.el=15 λεπτά +'''15 minutes'''.iw=15 דקות +'''15 minutes'''.hi-in=15 मिनट +'''15 minutes'''.hu=15 perc +'''15 minutes'''.is=15 mínútur +'''15 minutes'''.in=15 menit +'''15 minutes'''.it=15 minuti +'''15 minutes'''.ja=15分 +'''15 minutes'''.ko=15분 +'''15 minutes'''.lv=15 minūtes +'''15 minutes'''.lt=15 min. +'''15 minutes'''.ms=15 minit +'''15 minutes'''.no=15 minutter +'''15 minutes'''.pl=15 minut +'''15 minutes'''.pt=15 minutos +'''15 minutes'''.ro=15 minute +'''15 minutes'''.ru=15 минут +'''15 minutes'''.sr=15 minuta +'''15 minutes'''.sk=15 minút +'''15 minutes'''.sl=15 minut +'''15 minutes'''.es=15 minutos +'''15 minutes'''.sv=15 minuter +'''15 minutes'''.th=15 นาที +'''15 minutes'''.tr=15 dakika +'''15 minutes'''.uk=15 хвилин +'''15 minutes'''.vi=15 phút +'''30 minutes'''.en=30 minutes +'''30 minutes'''.en-gb=30 minutes +'''30 minutes'''.en-us=30 minutes +'''30 minutes'''.en-ca=30 minutes +'''30 minutes'''.en-ph=30 minutes +'''30 minutes'''.sq=30 minuta +'''30 minutes'''.ar=٣٠ دقيقة +'''30 minutes'''.be=30 хвілін +'''30 minutes'''.sr-ba=30 minuta +'''30 minutes'''.bg=30 минути +'''30 minutes'''.ca=30 minuts +'''30 minutes'''.zh-cn=30 分钟 +'''30 minutes'''.zh-hk=30 分鐘 +'''30 minutes'''.zh-tw=30 分鐘 +'''30 minutes'''.hr=30 minuta +'''30 minutes'''.cs=30 minut +'''30 minutes'''.da=30 minutter +'''30 minutes'''.nl=30 minuten +'''30 minutes'''.et=30 minutit +'''30 minutes'''.fi=30 minuuttia +'''30 minutes'''.fr=30 minutes +'''30 minutes'''.fr-ca=30 minutes +'''30 minutes'''.de=30 Minuten +'''30 minutes'''.el=30 λεπτά +'''30 minutes'''.iw=30 דקות +'''30 minutes'''.hi-in=30 मिनट +'''30 minutes'''.hu=30 perc +'''30 minutes'''.is=30 mínútur +'''30 minutes'''.in=30 menit +'''30 minutes'''.it=30 minuti +'''30 minutes'''.ja=30分 +'''30 minutes'''.ko=30분 +'''30 minutes'''.lv=30 minūtes +'''30 minutes'''.lt=30 minučių +'''30 minutes'''.ms=30 minit +'''30 minutes'''.no=30 minutter +'''30 minutes'''.pl=30 minut +'''30 minutes'''.pt=30 minutos +'''30 minutes'''.ro=30 de minute +'''30 minutes'''.ru=30 минут +'''30 minutes'''.sr=30 minuta +'''30 minutes'''.sk=30 minút +'''30 minutes'''.sl=30 min +'''30 minutes'''.es=30 minutos +'''30 minutes'''.sv=30 minuter +'''30 minutes'''.th=30 นาที +'''30 minutes'''.tr=30 dakika +'''30 minutes'''.uk=30 хвилин +'''30 minutes'''.vi=30 phút +'''1 hour'''.en=1 hour +'''1 hour'''.en-gb=1 hour +'''1 hour'''.en-us=1 hour +'''1 hour'''.en-ca=1 hour +'''1 hour'''.en-ph=1 hour +'''1 hour'''.sq=1 orë +'''1 hour'''.ar=ساعة واحدة +'''1 hour'''.be=1 гадзіна +'''1 hour'''.sr-ba=Jedan sat +'''1 hour'''.bg=1 час +'''1 hour'''.ca=1 hora +'''1 hour'''.zh-cn=1 小时 +'''1 hour'''.zh-hk=1 小時 +'''1 hour'''.zh-tw=1 小時 +'''1 hour'''.hr=1 sat +'''1 hour'''.cs=1 hodina +'''1 hour'''.da=1 time +'''1 hour'''.nl=1 uur +'''1 hour'''.et=1 tund +'''1 hour'''.fi=1 tunti +'''1 hour'''.fr=1 heure +'''1 hour'''.fr-ca=1 heure +'''1 hour'''.de=1 Stunde +'''1 hour'''.el=1 ώρα +'''1 hour'''.iw=שעה אחת +'''1 hour'''.hi-in=1 घंटा +'''1 hour'''.hu=1 óra +'''1 hour'''.is=1 klukkustund +'''1 hour'''.in=1 jam +'''1 hour'''.it=1 ora +'''1 hour'''.ja=1時間 +'''1 hour'''.ko=1시간 +'''1 hour'''.lv=1 stunda +'''1 hour'''.lt=1 val. +'''1 hour'''.ms=1 jam +'''1 hour'''.no=1 time +'''1 hour'''.pl=1 godzina +'''1 hour'''.pt=1 hora +'''1 hour'''.ro=1 oră +'''1 hour'''.ru=1 час +'''1 hour'''.sr=Jedan sat +'''1 hour'''.sk=1 hodina +'''1 hour'''.sl=1 h +'''1 hour'''.es=1 hora +'''1 hour'''.sv=En timme +'''1 hour'''.th=1 ชั่วโมง +'''1 hour'''.tr=1 saat +'''1 hour'''.uk=1 година +'''1 hour'''.vi=1 giờ +'''6 hours'''.en=6 hours +'''6 hours'''.en-gb=6 hours +'''6 hours'''.en-us=6 hours +'''6 hours'''.en-ca=6 hours +'''6 hours'''.sq=6 orë +'''6 hours'''.ar=‏‫٦‬ ساعات +'''6 hours'''.be=6 гадзін +'''6 hours'''.sr-ba=6 sati +'''6 hours'''.bg=6 часа +'''6 hours'''.ca=6 hores +'''6 hours'''.zh-cn=6 小时 +'''6 hours'''.zh-hk=6 小時 +'''6 hours'''.zh-tw=6 小時 +'''6 hours'''.hr=6 sati +'''6 hours'''.cs=6 hodin +'''6 hours'''.da=6 timer +'''6 hours'''.nl=6 uur +'''6 hours'''.et=6 tundi +'''6 hours'''.fi=6 tuntia +'''6 hours'''.fr=6 heures +'''6 hours'''.fr-ca=6 heures +'''6 hours'''.de=6 Stunden +'''6 hours'''.el=6 ώρες +'''6 hours'''.iw=6 שעות +'''6 hours'''.hi-in=6 घंटे +'''6 hours'''.hu=6 óra +'''6 hours'''.is=6 klukkustundir +'''6 hours'''.in=6 jam +'''6 hours'''.it=6 ore +'''6 hours'''.ja=6時間 +'''6 hours'''.ko=6시간 +'''6 hours'''.lv=6 stundas +'''6 hours'''.lt=6 val. +'''6 hours'''.ms=6 jam +'''6 hours'''.no=6 timer +'''6 hours'''.pl=6 godzin +'''6 hours'''.pt=6 horas +'''6 hours'''.ro=6 ore +'''6 hours'''.ru=6 часов +'''6 hours'''.sr=6 sati +'''6 hours'''.sk=6 hodín +'''6 hours'''.sl=6 ur +'''6 hours'''.es=6 horas +'''6 hours'''.sv=6 timmar +'''6 hours'''.th=6 ชั่วโมง +'''6 hours'''.tr=6 saat +'''6 hours'''.uk=6 годин +'''6 hours'''.vi=6 giờ +'''12 hours'''.en=12 hours +'''12 hours'''.en-gb=12 hours +'''12 hours'''.en-us=12 hours +'''12 hours'''.en-ca=12 hours +'''12 hours'''.sq=12 orë +'''12 hours'''.ar=‏‫١٢‬ ساعة +'''12 hours'''.be=12 гадзін +'''12 hours'''.sr-ba=12 sati +'''12 hours'''.bg=12 часа +'''12 hours'''.ca=12 hores +'''12 hours'''.zh-cn=12 小时 +'''12 hours'''.zh-hk=12 小時 +'''12 hours'''.zh-tw=12 小時 +'''12 hours'''.hr=12 sati +'''12 hours'''.cs=12 hodin +'''12 hours'''.da=12 timer +'''12 hours'''.nl=12 uur +'''12 hours'''.et=12 tundi +'''12 hours'''.fi=12 tuntia +'''12 hours'''.fr=12 heures +'''12 hours'''.fr-ca=12 heures +'''12 hours'''.de=12 Stunden +'''12 hours'''.el=12 ώρες +'''12 hours'''.iw=12 שעות +'''12 hours'''.hi-in=12 घंटे +'''12 hours'''.hu=12 óra +'''12 hours'''.is=12 klukkustundir +'''12 hours'''.in=12 jam +'''12 hours'''.it=12 ore +'''12 hours'''.ja=12時間 +'''12 hours'''.ko=12시간 +'''12 hours'''.lv=12 stundas +'''12 hours'''.lt=12 val. +'''12 hours'''.ms=12 jam +'''12 hours'''.no=12 timer +'''12 hours'''.pl=12 godzin +'''12 hours'''.pt=12 horas +'''12 hours'''.ro=12 ore +'''12 hours'''.ru=12 часов +'''12 hours'''.sr=12 sati +'''12 hours'''.sk=12 hodín +'''12 hours'''.sl=12 ur +'''12 hours'''.es=12 horas +'''12 hours'''.sv=12 timmar +'''12 hours'''.th=12 ชั่วโมง +'''12 hours'''.tr=12 saat +'''12 hours'''.uk=12 годин +'''12 hours'''.vi=12 giờ +'''18 hours'''.en=18 hours +'''18 hours'''.en-gb=18 hours +'''18 hours'''.en-us=18 hours +'''18 hours'''.en-ca=18 hours +'''18 hours'''.sq=18 orë +'''18 hours'''.ar=١٨ ساعة +'''18 hours'''.be=18 гадзін +'''18 hours'''.sr-ba=18 sati +'''18 hours'''.bg=18 часа +'''18 hours'''.ca=18 hores +'''18 hours'''.zh-cn=18 小时 +'''18 hours'''.zh-hk=18 小時 +'''18 hours'''.zh-tw=18 小時 +'''18 hours'''.hr=18 sati +'''18 hours'''.cs=18 hodin +'''18 hours'''.da=18 timer +'''18 hours'''.nl=18 uur +'''18 hours'''.et=18 tundi +'''18 hours'''.fi=18 tuntia +'''18 hours'''.fr=18 heures +'''18 hours'''.fr-ca=18 heures +'''18 hours'''.de=18 Stunden +'''18 hours'''.el=18 ώρες +'''18 hours'''.iw=18 שעות +'''18 hours'''.hi-in=18 घंटे +'''18 hours'''.hu=18 óra +'''18 hours'''.is=18 klukkustundir +'''18 hours'''.in=18 jam +'''18 hours'''.it=18 ore +'''18 hours'''.ja=18時間 +'''18 hours'''.ko=18시간 +'''18 hours'''.lv=18 stundas +'''18 hours'''.lt=18 val. +'''18 hours'''.ms=18 jam +'''18 hours'''.no=18 timer +'''18 hours'''.pl=18 godzin +'''18 hours'''.pt=18 horas +'''18 hours'''.ro=18 ore +'''18 hours'''.ru=18 часов +'''18 hours'''.sr=18 sati +'''18 hours'''.sk=18 hodín +'''18 hours'''.sl=18 ur +'''18 hours'''.es=18 horas +'''18 hours'''.sv=18 timmar +'''18 hours'''.th=18 ชั่วโมง +'''18 hours'''.tr=18 saat +'''18 hours'''.uk=18 годин +'''18 hours'''.vi=18 giờ +'''24 hours'''.en=24 hours +'''24 hours'''.en-gb=24 hours +'''24 hours'''.en-us=24 hours +'''24 hours'''.en-ca=24 hours +'''24 hours'''.sq=24 orë +'''24 hours'''.ar=٢٤ ساعة +'''24 hours'''.be=24 гадзіны +'''24 hours'''.sr-ba=24 sata +'''24 hours'''.bg=24 часа +'''24 hours'''.ca=24 hores +'''24 hours'''.zh-cn=24 小时 +'''24 hours'''.zh-hk=24 小時 +'''24 hours'''.zh-tw=24 小時 +'''24 hours'''.hr=24 sata +'''24 hours'''.cs=24 hodin +'''24 hours'''.da=24 timer +'''24 hours'''.nl=24 uur +'''24 hours'''.et=24 tundi +'''24 hours'''.fi=24 tuntia +'''24 hours'''.fr=24 heures +'''24 hours'''.fr-ca=24 heures +'''24 hours'''.de=24 Stunden +'''24 hours'''.el=24 ώρες +'''24 hours'''.iw=24 שעות +'''24 hours'''.hi-in=24 घंटे +'''24 hours'''.hu=24 óra +'''24 hours'''.is=Sólarhringur +'''24 hours'''.in=24 jam +'''24 hours'''.it=24 ore +'''24 hours'''.ja=24時間 +'''24 hours'''.ko=24시간 +'''24 hours'''.lv=24 stundas +'''24 hours'''.lt=24 val. +'''24 hours'''.ms=24 jam +'''24 hours'''.no=24 timer +'''24 hours'''.pl=24 godziny +'''24 hours'''.pt=24 horas +'''24 hours'''.ro=24 de ore +'''24 hours'''.ru=24 часа +'''24 hours'''.sr=24 sata +'''24 hours'''.sk=24 hodín +'''24 hours'''.sl=24 ur +'''24 hours'''.es=24 horas +'''24 hours'''.sv=24 timmar +'''24 hours'''.th=24 ชั่วโมง +'''24 hours'''.tr=24 saat +'''24 hours'''.uk=24 години +'''24 hours'''.vi=24 giờ # End of Device Preferences From 3b2ec4eb80592e09c94916070695ecbb0054fbf5 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Fri, 25 Feb 2022 18:12:31 +0900 Subject: [PATCH 124/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#77867) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * Update sihas-multipurpose-sensor.groovy Motion uses a OCCUPANCY_SENSING_CLUSTER, OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE. So, delete unnecessary parts. --- .../sihas-multipurpose-sensor.groovy | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index d94e8d9a213..4c37dba3370 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -132,9 +132,7 @@ private Map translateZoneStatus(ZoneStatus zs) { // Some sensor models that use this DTH use alarm1 and some use alarm2 to signify motion if (isDSM300()) { return (zs.isAlarm1Set() || zs.isAlarm2Set()) ? getContactResult('open') : getContactResult('closed') - } else { - return (zs.isAlarm1Set() || zs.isAlarm2Set()) ? getMotionResult('active') : getMotionResult('inactive') - } + } } private Map getBatteryResult(rawValue) { @@ -286,19 +284,19 @@ def configure() { configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE, DataType.UINT8, 30, 21600, 0x01/*100mv*1*/) if (isUSM300() || isTSM300()) { - configCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 20, 300, 10/*10/100=0.1도*/) - configCmds += zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, RALATIVE_HUMIDITY_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, 20, 300, 40/*10/100=0.4%*/) + configCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 15, 300, 10/*10/100=0.1도*/) + configCmds += zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, RALATIVE_HUMIDITY_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, 15, 300, 40/*10/100=0.4%*/) } if (isUSM300()) { - configCmds += zigbee.configureReporting(ILLUMINANCE_MEASUREMENT_CLUSTER, ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, 20, 3600, 10/*10 lux*/) + configCmds += zigbee.configureReporting(ILLUMINANCE_MEASUREMENT_CLUSTER, ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.UINT16, 15, 3600, 1/*1 lux*/) } if (isUSM300() || isOSM300()) { configCmds += zigbee.configureReporting(OCCUPANCY_SENSING_CLUSTER, OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE, DataType.BITMAP8, 1, 600, 1) } - if (isDSM300()) { + if (isDSM300() || isUSM300() || isOSM300()) { configCmds += zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 0, 0xffff, null) } From a5c225a3dcd3b90756c0558ecf0cda224db82dea Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Mon, 28 Feb 2022 13:28:48 +0800 Subject: [PATCH 125/184] Update Orvibo-Contact-Sensor.groovy update thirdreality battery percent report --- .../Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index 0df9da8f9a7..9888fae4fb6 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -166,10 +166,11 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" def result = [:] def manufacturer = getDataValue("manufacturer") + def application = getDataValue("application") if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= "17") { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From f44d91715734384ea7a55674007031520405903e Mon Sep 17 00:00:00 2001 From: Konrad Date: Tue, 1 Mar 2022 16:56:02 +0100 Subject: [PATCH 126/184] CP-14539 - another fingerprint for Yale Lock YMF40 --- devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index 86d164d91ae..abeb1c082c6 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -48,6 +48,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "iZBModule01", deviceJoinName: "Yale Door Lock" //Yale Locks (YDF30/40, YMF30/40) with old firmware (v.9.0) fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "c700000202", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YDF40 fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "0700000001", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YMF40 + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "06ffff2027", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YMF40 fingerprint profileId: "0104", inClusters: "0000,0001,0003,0101", outClusters: "0000,0001,0003,0101", manufacturer: "Datek", model: "ID Lock 150", deviceJoinName: "ID Lock Door Lock" //ID Lock 150 Zigbee Module by Datek fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,0020,0101", outClusters: "0019", manufacturer: "Danalock", model: "V3-BTZBE", deviceJoinName: "Danalock Door Lock" } From 0d9c4ad3630739615ae86d21ecdc63414d6d833a Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Tue, 1 Mar 2022 23:17:01 +0400 Subject: [PATCH 127/184] DevWs for HELTUN containing containing HELTUN FT01 Fan Coil Thermostat (#77748) * DevWs for HELTUN containing containing HELTUN FT01 Fan Coil Thermostat * Removed logs * Fix typos * Removed unnecessary line * Indentation + formatting * Requested changes Co-authored-by: Artur Sargsyan --- .../heltun-ft01-fan-coil-thermostat.groovy | 565 ++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 devicetypes/heltun/heltun-ft01-fan-coil-thermostat.src/heltun-ft01-fan-coil-thermostat.groovy diff --git a/devicetypes/heltun/heltun-ft01-fan-coil-thermostat.src/heltun-ft01-fan-coil-thermostat.groovy b/devicetypes/heltun/heltun-ft01-fan-coil-thermostat.src/heltun-ft01-fan-coil-thermostat.groovy new file mode 100644 index 00000000000..cd1ffe78681 --- /dev/null +++ b/devicetypes/heltun/heltun-ft01-fan-coil-thermostat.src/heltun-ft01-fan-coil-thermostat.groovy @@ -0,0 +1,565 @@ +/** + * HELTUN FT01 Fan Coil Thermostat + * + * Copyright 2021 Sarkis Kabrailian + * + * 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: "HELTUN FT01 Fan Coil Thermostat", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, ocfDeviceType: "oic.d.thermostat") { + capability "Energy Meter" + capability "Fan Speed" + capability "Power Meter" + capability "Relative Humidity Measurement" + capability "Temperature Measurement" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Illuminance Measurement" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", model: "0002", deviceJoinName: "HELTUN Thermostat" //Raw Description zw:L type:0806 mfr:0344 prod:0004 model:0002 ver:2.05 zwv:7.11 lib:03 cc:5E,85,59,8E,55,86,72,5A,73,98,9F,6C,81,31,32,70,42,40,43,44,45,87,22,7A + } + preferences { + input ( + title: "HE-FT01 | HELTUN Fan Coil Thermostat", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + if (it.title != null) { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + } + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + +def parse(String description) { + def cmd = zwave.parse(description) + if (cmd) { + return zwaveEvent(cmd) + } +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if ( needConfig ) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if ( state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue){ + state."$parameter".state = "configured" + } else { + state."$parameter".state = "error" + } + configParam() +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { + def localScale = getTemperatureScale() //HubScale + def deviceMode = numToModeMap[cmd.mode.toInteger()] + sendEvent(name: "thermostatMode", data:[supportedThermostatModes: state.supportedModes], value: deviceMode) + if (cmd.mode == 0 || cmd.mode == 6) { + sendEvent(name: "heatingSetpoint", value: 0, unit: localScale) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + def roomTemperature = 1 + def humidity = 5 + def illuminance = 3 + def localScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + if (roomTemperature == cmd.sensorType) { + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == localScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = localScale + sendEvent(map) + } else if (humidity == cmd.sensorType) { + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + sendEvent(map) + } else if (illuminance == cmd.sensorType) { + map.name = "illuminance" + map.value = cmd.scaledSensorValue + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + } else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + } + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd) { + def state = cmd.operatingState.toInteger() + def currentState = opStateMap[state] + sendEvent(name: "thermostatOperatingState", value: currentState) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) { + def state = cmd.fanOperatingState.toInteger() + def currentState = fanStateMap[state] + sendEvent(name: "thermostatFanState", value: currentState) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) { + def speed = cmd.fanMode.toInteger() + def fanSpeed = fanModeToSpeedMap[speed] + if (cmd.off) { + fanSpeed = 0 + } + sendEvent(name: "fanSpeed", value: fanSpeed) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { + def localScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def deviceTemp = cmd.scaledValue + def setPoint = (deviceScale == localScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + def mode = modeToNumMap[device.currentValue("thermostatMode")] + if (mode == 0 || mode == 6) { + setPoint = 0 + } + sendEvent(name: "heatingSetpoint", value: setPoint, unit: localScale) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) { + def tSupportedModes = [] + if(cmd.heat) { tSupportedModes << "heat" } + if(cmd.cool) { tSupportedModes << "cool" } + if(cmd.auto) { tSupportedModes << "auto" } + if(cmd.fanOnly) { tSupportedModes << "fanonly" } + if(cmd.autoChangeover) { tSupportedModes << "autochangeover" } + if(cmd.energySaveHeat) { tSupportedModes << "energysaveheat" } + if(cmd.energySaveCool) { tSupportedModes << "energysavecool" } + if(cmd.off) { tSupportedModes << "off" } + state.supportedModes = tSupportedModes + sendEvent(name: "supportedThermostatModes", value: tSupportedModes, displayed: false) +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [0, zwaveHubNodeId, 0]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,0]).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = new Date().toCalendar() + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)) { + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def setHeatingSetpoint(tValue) { + def cmds = [] + def mode = device.currentValue("thermostatMode") + def currentMode = modeToNumMap[mode] + def temp = state.heatingSetpoint = tValue.toDouble() //temp got fromm the app + def tempInC = (getTemperatureScale() == "F" ? roundC(fahrenheitToCelsius(temp)) : temp) //If not C, Convert to C + cmds << zwave.thermostatSetpointV2.thermostatSetpointSet(setpointType: currentMode, scale: 0, precision: 1, scaledValue: tempInC).format() + // Sync temp, opState, setPoint, fanSpeed + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() + cmds << zwave.thermostatFanModeV3.thermostatFanModeGet() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: currentMode).format() + sendHubCommand(cmds) +} + +def setFanSpeed(speed) { + def cmds = [] + boolean fanState = false + if (speed == 0) { + fanState = true + cmds << zwave.thermostatFanModeV3.thermostatFanModeSet(off: fanState) + } else { + def fanSpeed = fanSpeedToModeMap[speed] + cmds << zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanSpeed, off: fanState) + } + cmds << zwave.thermostatFanModeV3.thermostatFanModeGet() + sendHubCommand(cmds) +} + +def setThermostatMode(String value) { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeSet(mode: modeToNumMap[value]).format() + cmds << zwave.thermostatModeV2.thermostatModeGet().format() + cmds << zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: modeToNumMap[value]).format() + sendHubCommand(cmds) +} + +def getNumToModeMap() { + [ + 0 : "off", + 1 : "heat", + 2: "cool", + 3 : "auto", + 6 : "fanonly", + 10 : "autochangeover", + 11 : "energysaveheat", + 12 : "energysavecool" + ] +} + +def getModeToNumMap() { + [ + "off": 0, + "heat": 1, + "cool": 2, + "auto": 3, + "fanonly": 6, + "autochangeover": 10, + "energysaveheat": 11, + "energysavecool": 12 + ] +} + +def getOpStateMap() { + [ + 0 : "idle", + 1 : "heating", + 2 : "cooling", + 3 : "fan only" + ] +} + +def getFanStateMap() { + [ + 0 : "idle", + 1 : "running", + 2 : "running high", + 3 : "running medium" + ] +} + +def getFanModeToSpeedMap() { + [ + 0 : 1, //Fan Auto Low > Speed Low + 1 : 1, //Fan Low > Speed Low + 2 : 4, //Fan Auto High > Speed High + 3 : 3, //Fan High > Speed Max + 4 : 2, //Fan Auto mendium > Speed Medium + 5 : 2 //Fan medium > Speed Medium + ] +} + +def getFanSpeedToModeMap() { + [ + 1 : 1, //Speed Low > Fan Low + 2 : 5, //Speed Medium > Fan Medium + 3 : 3, //Speed High > Fan Auto High + 4 : 2 //Speed Max > Fan High + ] +} + +def roundC (tempInC) { + return (Math.round(tempInC.toDouble() * 2))/2 +} + +def updated() { + initialize() +} + +def initialize() { + runIn(3, "checkParam") +} + +def ping() { + refresh() +} + +def refresh() { + def cmds = [] + cmds << zwave.thermostatModeV2.thermostatModeGet().format() //get thermostatmode + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1).format() //roomTemperature + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3).format() //Humidity + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5).format() //Illuminance + cmds << zwave.meterV3.meterGet(scale: 0).format() //get kWh + cmds << zwave.meterV3.meterGet(scale: 2).format() //get Watts + cmds << zwave.thermostatOperatingStateV2.thermostatOperatingStateGet().format() //get Thermostat Operating State + cmds << zwave.clockV1.clockGet().format() //get Clock + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() //get channel association + cmds << zwave.thermostatModeV2.thermostatModeSupportedGet().format() //get supported modes + cmds << zwave.thermostatFanModeV3.thermostatFanModeGet() //get fanMode + sendHubCommand(cmds, 1200) + runIn(15, "checkParam") +} + +def configure() { + ping() +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +def off() { + setThermostatMode("off") +} + +def heat() { + setThermostatMode("heat") +} + +def cool() { + setThermostatMode("cool") +} + +def auto() { + setThermostatMode("auto") +} + +private parameterMap() {[ +[title: "Display Brightness Control", description: "The HE-FT01 can adjust its display brightness automatically depending on the illumination of the ambient environment and also allows to control it manually.", + name: "Selected Brightness Level", options: [ + 0: "Auto", + 1: "Level 1 (Lowest)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (Highest)" + ], paramNum: 5, size: 1, default: "0", type: "enum"], + +[title: "Touch Sensor Sensitivity Threshold", description: "This Parameter allows to adjust the Touch Buttons Sensitivity. Note: Setting the sensitivity too high can lead to false touch detection. We recommend not changing this Parameter unless there is a special need to do so.", + name: "Selected Touch Sensitivity", options: [ + 1: "Level 1 (Low sensitivity)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (High sensitivity)" + ], paramNum: 6, size: 1, default: "6", type: "enum"], + +[title: "Fan Relay Output Mode", description: "This Parameter determines the type of load connected to the device fan relay relay outputs (OUT-1, OUT-2, OUT-3). The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum"], + +[title: "Heater Relay Output Mode", description: "This Parameter determines the type of load connected to the device heater relay output (OUT-4). The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 8, size: 1, default: "0", type: "enum"], + +[title: "Cooler Relay Output Mode", description: "This Parameter determines the type of load connected to the device cooler relay output (OUT-5). The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 9, size: 1, default: "0", type: "enum"], + +[title: "Heating State Fan Control", description: "This parameter determines if fan should be enabled or disabled in heating mode. If fan is enabled (normal operation), one of the outputs OUT-1, OUT-2, OUT-3 will be ON depending on the selected fan speed. If fan is disabled, in heating state, only OUT-4 will be ON and OUT-1, OUT-2, OUT-3 will always remain OFF", + name: "Selected Mode", options: [ + 0: "Fan Disabled", + 1: "Fan Enabled" + ], paramNum: 10, size: 1, default: "1", type: "enum"], + +[title: "Cooling State Fan Control", description: "This parameter determines if fan should be enabled or disabled in cooling mode. If fan is enabled (normal operation), one of the outputs OUT-1, OUT-2, OUT-3 will be ON depending on the selected fan speed. If fan is disabled, in cooling state, only OUT-4 will be ON and OUT-1, OUT-2, OUT-3 will always remain OFF", + name: "Selected Mode", options: [ + 0: "Fan Disabled", + 1: "Fan Enabled" + ], paramNum: 11, size: 1, default: "1", type: "enum"], + +[title: "Relays Load Power", description: "These parameters are used to specify the loads power that are connected to the device outputs (Relays). Using your connected device’s power consumption specification (see associated owner’s manual), set the load in Watts for the outputs bellow:", + name: "Selected Fan Low Speed Load Power in Watts", paramNum: 12, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + +[name: "Selected Fan Medium Speed Load Power in Watts", paramNum: 13, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + +[name: "Selected Fan High Speed Load Power in Watts", paramNum: 14, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + +[name: "Selected Heating Load Power in Watts", paramNum: 15, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + +[name: "Selected Cooling Load Power in Watts", paramNum: 16, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + +[title: "Air Temperature Calibration", description: "This Parameter defines the offset value for room air temperature. This value will be added or subtracted from the air temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 17, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + +[title: "Temperature Hysteresis", description: "This Parameter defines the hysteresis value for temperature control. The HE-FT01 will stabilize the temperature with selected hysteresis. For example, if the SET POINT is set for 25°C and HYSTERESIS is set for 0.5°C the HE-FT01 will change the state to IDLE if the temperature reaches 25.0°C. It will change the state to HEATING if the temperature becomes lower than 24.5°C, and will change the state to COOLING if the temperature rises beyond 25.5°C.The value of this Parameter should be x10 e.g. for 0.5°C set the value 5.", + name: "Selected Hysteresis in °Cx10", paramNum: 18, size: 1, default: 5, type: "number", min: 2, max: 100, unit: " °Cx10"], + +[title: "TIME mode operation", description: "This Parameter determines the Climate Mode (Heating or Cooling) in which HE-FT01 will operates when the TIME mode is selected", + name: "Selected Mode", options: [ + 1: "Heating & Cooling", + 2: "Heating", + 3: "Cooling" + ], paramNum: 23, size: 1, default: "1", type: "enum"], + +[title: "Schedule Time", description: "Use these Parameters to set the Morning, Day, Evening and Night start times manually for the Temperature Schedule. The value of these Parameters has format HHMM, e.g. for 08:00 use value 0800 (time without a colon). From 00:00 to 23:59 can be selected.", + name: "Selected Morning Start Time", paramNum: 41, size: 2, default: 600, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Day Start Time", paramNum: 42, size: 2, default: 900, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Evening Start Time", paramNum: 43, size: 2, default: 1800, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[name: "Selected Night Start Time", paramNum: 44, size: 2, default: 2300, type: "number", min: 0, max: 2359, unit: " HHMM"], + +[title: "Schedule Temperature", description: "Use these Parameters to set the temperature for each day Schedule manually. The value of this Parameter should be x10, e.g., for 22.5°C set value 225. From 1°C (value 10) to 110°C (value 1100) can be selected.", + name: "Monday Morning Temperature in °Cx10", paramNum: 45, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Day Temperature in °Cx10", paramNum: 46, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Evening Temperature in °Cx10", paramNum: 47, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Monday Night Temperature in °Cx10", paramNum: 48, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Morning Temperature in °Cx10", paramNum: 49, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Day Temperature in °Cx10", paramNum: 50, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Evening Temperature in °Cx10", paramNum: 51, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Tuesday Night Temperature in °Cx10", paramNum: 52, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Morning Temperature in °Cx10", paramNum: 53, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Day Temperature in °Cx10", paramNum: 54, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Evening Temperature in °Cx10", paramNum: 55, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Wednesday Night Temperature in °Cx10", paramNum: 56, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Morning Temperature in °Cx10", paramNum: 57, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Day Temperature in °Cx10", paramNum: 58, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Evening Temperature in °Cx10", paramNum: 59, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Thursday Night Temperature in °Cx10", paramNum: 60, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Morning Temperature in °Cx10", paramNum: 61, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Day Temperature in °Cx10", paramNum: 62, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Evening Temperature in °Cx10", paramNum: 63, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Friday Night Temperature in °Cx10", paramNum: 64, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Morning Temperature in °Cx10", paramNum: 65, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Day Temperature in °Cx10", paramNum: 66, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Evening Temperature in °Cx10", paramNum: 67, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Saturday Night Temperature in °Cx10", paramNum: 68, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Morning Temperature in °Cx10", paramNum: 69, size: 2, default: 240, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Day Temperature in °Cx10", paramNum: 70, size: 2, default: 200, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Evening Temperature in °Cx10", paramNum: 71, size: 2, default: 230, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[name: "Sunday Night Temperature in °Cx10", paramNum: 72, size: 2, default: 180, type: "number", min: 10, max: 370, unit: " °Cx10"], + +[title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Control Energy Meter Report", description: "This Parameter determines if the change in the energy meter will result in a report being sent to the gateway. Note: When the device is turning ON, the consumption data will be sent to the gateway once, even if the report is disabled.", + name: "Sending Energy Meter Reports", options: [ + 0: "Disabled", + 1: "Enabled" + ], paramNum: 142, size: 1, default: "1", type: "enum"], + +[title: "Sensors Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends to the gateway reports from its external NTC temperature sensor even if there are not changes in the values. This Parameter defines the interval between consecutive reports", + name: "Selected Energy Report Interval in minutes", paramNum: 143, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + +[title: "Air & Floor Temperature Sensors Report Threshold", description: "This Parameter determines the change in temperature level (in °C) resulting in temperature sensors report being sent to the gateway. The value of this Parameter should be x10 for °C, e.g. for 0.4°C use value 4. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Temperature Threshold in °Cx10", paramNum: 144, size: 1, default: 2, type: "number", min: 0 , max: 100, unit: " °Cx10"], + +[title: "Humidity Sensor Report Threshold", description: "This Parameter determines the change in humidity level in % resulting in humidity sensors report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Humidity Threshold in %", paramNum: 145, size: 1, default: 2, type: "number", min: 0 , max: 25, unit: "%"], + +[title: "Light Sensor Report Threshold", description: "This Parameter determines the change in the ambient environment illuminance level resulting in a light sensors report being sent to the gateway. From 10% to 99% can be selected. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Light Sensor Threshold in %", paramNum: 146, size: 1, default: 50, type: "number", min: 0 , max: 99, unit: "%"] + +]} \ No newline at end of file From 6c071836a322df969cbdf7512240b8d22e8cb33b Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:42:25 -0500 Subject: [PATCH 128/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZEN52 Double Relay (#77899) * DevWs for Zooz (The Smartest House) containing containing Zooz ZEN52 Double Relay * Zooz Child Switch Button for Zooz ZEN52 Double Relay * Zooz ZEN52 Double Relay changes --- .../zooz-child-switch-button.groovy | 61 +++ .../zooz-zen52-double-relay.groovy | 437 ++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 devicetypes/zooz/zooz-child-switch-button.src/zooz-child-switch-button.groovy create mode 100644 devicetypes/zooz/zooz-zen52-double-relay.src/zooz-zen52-double-relay.groovy diff --git a/devicetypes/zooz/zooz-child-switch-button.src/zooz-child-switch-button.groovy b/devicetypes/zooz/zooz-child-switch-button.src/zooz-child-switch-button.groovy new file mode 100644 index 00000000000..496a5bdbb2e --- /dev/null +++ b/devicetypes/zooz/zooz-child-switch-button.src/zooz-child-switch-button.groovy @@ -0,0 +1,61 @@ +/* + * Zooz Child Switch Button + * + * Changelog: + * + * 2022-03-02 + * - Publication Release + * + * Copyright 2022 Zooz + * + * 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: "Zooz Child Switch Button", + namespace: "Zooz", + author: "Kevin LaFramboise (krlaframboise)", + ocfDeviceType: "oic.d.light", + mnmn: "SmartThingsCommunity", + vid: "29d51c12-bb47-3d95-ad2e-831656ed20a8" + ) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Button" + capability "Refresh" + } + + preferences() {} +} + +def parse(String description) { + return [] +} + +def on() { + log.debug "on()..." + parent.childOn(device.deviceNetworkId) +} + +def off() { + log.debug "off()..." + parent.childOff(device.deviceNetworkId) +} + +def refresh() { + log.debug "refresh()..." + parent.childRefresh(device.deviceNetworkId) +} \ No newline at end of file diff --git a/devicetypes/zooz/zooz-zen52-double-relay.src/zooz-zen52-double-relay.groovy b/devicetypes/zooz/zooz-zen52-double-relay.src/zooz-zen52-double-relay.groovy new file mode 100644 index 00000000000..ef3eb55c4b7 --- /dev/null +++ b/devicetypes/zooz/zooz-zen52-double-relay.src/zooz-zen52-double-relay.groovy @@ -0,0 +1,437 @@ +/* + * Zooz ZEN52 Double Relay + * + * Changelog: + * + * 2022-03-02.2 + * - Removed central scene setting + * 2022-03-02 + * - Publication Release + * + * Copyright 2022 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x22: 1, // ApplicationStatus + 0x25: 1, // SwitchBinary + 0x55: 1, // TransportService + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5B: 1, // CentralScene + 0x5E: 2, // ZwaveplusInfo + 0x60: 3, // MultiChannel + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x85: 2, // Association + 0x86: 1, // Version + 0x87: 2, // Indicator (3) + 0x8E: 2, // MultiChannelAssociation + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 +] + +@Field static int supervisionCC = 108 +@Field static int btnPushed = 0 +@Field static int btnReleased = 1 +@Field static int btnHeld = 2 +@Field static int mainEndpoint = 0 +@Field static List relayEndpoints = [1, 2] +@Field static List supportedButtonValues = ["pushed","held","pushed_2x","pushed_3x","pushed_4x","pushed_5x"] + +@Field static Map configParams = [ + ledIndicator: [num:2, title:"Led indicator", size:1, defaultVal:1, options:[0:"Disabled", 1:"Enabled"]], + relay1AutoOff: [num:3, title:"Relay 1 Auto Off Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + relay1AutoOn: [num:4, title:"Relay 1 Auto On Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + relay1TimerUnit: [num:7, title:"Relay 1 Timer Unit", size:1, defaultVal:1, options:[1:"Minutes", 2:"Seconds"]], + relay1StatusAfterPowerFailure: [num:14, title:"Relay 1 Status After Power Failure", size:1, defaultVal:2, options:[0:"Forced off", 1:"Forced on", 2:"Restore previous state"]], + relay1LoadControl: [num:17, title:"Relay 1 Load Control", size:1, defaultVal:1, options:[0:"Disable Switch/ Enable Z-Wave", 1:"Enable Switch and Z-Wave", 2:"Disable Switch and Z-Wave"]], + relay1SwitchType: [num:20, title:"Relay 1 Switch Type", size:1, defaultVal:2, options:[0:"Toggle Switch", 1:"Momentary Light Switch", 2:"Toggle Up On/Down Off", 3:"3-way Impulse Control", 4:"Garage Door Mode"]], + relay1ImpulseDuration: [num:22, title:"Relay 1 Impulse Duration for 3-way", size:1, defaultVal:10, range:"2..200", desc:"2..200"], + relay2AutoOff: [num:5, title:"Relay 2 Auto Off Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + relay2AutoOn: [num:6, title:"Relay 2 Auto On Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + relay2TimerUnit: [num:8, title:"Relay 2 Timer Unit", size:1, defaultVal:1, options:[1:"Minutes", 2:"Seconds"]], + relay2StatusAfterPowerFailure: [num:15, title:"Relay 2 Status After Power Failure", size:1, defaultVal:2, options:[0:"Forced off", 1:"Forced on", 2:"Restore previous state"]], + relay2LoadControl: [num:18, title:"Relay 2 Load Control", size:1, defaultVal:1, options:[0:"Disable Switch/ Enable Z-Wave", 1:"Enable Switch and Z-Wave", 2:"Disable Switch and Z-Wave"]], + relay2SwitchType: [num:21, title:"Relay 2 Switch Type", size:1, defaultVal:2, options:[0:"Toggle Switch", 1:"Momentary Light Switch", 2:"Toggle Up On/Down Off", 3:"3-way Impulse Control", 4:"Garage Door Mode"]], + relay2ImpulseDuration: [num:23, title:"Relay 2 Impulse Duration for 3-way", size:1, defaultVal:10, range:"2..200", desc:"2..200"] +] + +metadata { + definition ( + name: "Zooz ZEN52 Double Relay", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "oic.d.light", + mnmn: "SmartThings", + vid: "generic-switch" + ) { + capability "Actuator" + capability "Switch" + capability "Refresh" + capability "Health Check" + + // zw:Ls2a type:1000 mfr:027A prod:0104 model:0202 ver:1.11 zwv:7.15 lib:03 cc:5E,55,9F,6C,22 sec:25,70,85,59,8E,86,72,5A,73,7A,60,5B,87 epc:2 + fingerprint mfr: "027A", prod: "0104", model: "0202", deviceJoinName: "Zooz Switch" // Zooz ZEN52 Double Relay + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + description: "Default: ${param.options[param.defaultVal]}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input name, "number", + title: param.title, + description: "${param.desc} - Default: ${param.defaultVal}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + } +} + +def installed() { + log.debug "installed()..." + initialize() + state.firstConfig = true +} + +def updated() { + log.debug "updated()..." + initialize() + + if (!state.firstConfig) { + configure() + } else { + state.firstConfig = false + } +} + +void initialize() { + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((60 * 60 * 3) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + relayEndpoints.each { endpoint -> + if (!findChildByEndpoint(endpoint)) { + String dni = buildChildDNI(endpoint) + def child + try { + child = createChildDevice(endpoint, dni, "Zooz", "Zooz Child Switch Button") + child.sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed: false) + child.sendEvent(name:"numberOfButtons", value:1, displayed:false) + sendButtonEvent(child, "pushed") + } catch(e) { + log.warn "${e}" + } + + if (child) { + childRefresh(child.deviceNetworkId) + } + } + } +} + +def createChildDevice(int endpoint, String dni, String dthNamespace, String dthName) { + return addChildDevice( + dthNamespace, + dthName, + dni, + device.getHub().getId(), + [ + completedSetup: true, + label: "Zooz Switch ${endpoint}", + isComponent: false + ] + ) +} + +def configure() { + log.debug "configure()..." + List cmds = [] + + if (device.currentValue("switch") == null) { + cmds << switchBinaryGetCmd(mainEndpoint) + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + log.debug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + if (cmds) { + sendHubCommand(cmds, 500) + } +} + +def on() { + log.debug "on()..." + executeOnOffCmds(0xFF, mainEndpoint) +} + +def off() { + log.debug "off()..." + executeOnOffCmds(0x00, mainEndpoint) +} + +void childOn(String dni) { + executeOnOffCmds(0xFF, getEndpointFromDNI(dni)) +} + +void childOff(String dni) { + executeOnOffCmds(0x00, getEndpointFromDNI(dni)) +} + +void executeOnOffCmds(int value, endpoint) { + List cmds = [ + multiChannelCmdEncapCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: value), endpoint) + ] + + // Workaround for unreliable automatic reports. + if (endpoint == mainEndpoint) { + cmds += getRefreshRelaysCmds() + } else { + cmds << switchBinaryGetCmd(endpoint) + } + + sendHubCommand(cmds) +} + +List getRefreshRelaysCmds() { + List cmds = [] + relayEndpoints.each { endpoint -> + cmds << switchBinaryGetCmd(endpoint) + } + return cmds +} + +def ping() { + log.debug "ping()..." + return [ switchBinaryGetCmd(mainEndpoint) ] +} + +def refresh() { + log.debug "refresh()..." + sendHubCommand(getRefreshRelaysCmds(), 500) +} + +void childRefresh(String dni) { + sendHubCommand([ + switchBinaryGetCmd(getEndpointFromDNI(dni)) + ]) +} + +String switchBinaryGetCmd(int endpoint) { + return multiChannelCmdEncapCmd(zwave.switchBinaryV1.switchBinaryGet(), endpoint) +} + +String multiChannelCmdEncapCmd(cmd, int endpoint=0) { + if (endpoint) { + return secureCmd(zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd)) + } else { + return secureCmd(cmd) + } +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + // Workaround that was added to all SmartThings Multichannel DTHs. + if ((cmd.commandClass == supervisionCC) && (cmd.parameter.size >= 4)) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint) + } else { + log.debug "Unable to get encapsulated command: $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + + if (val < 0) { + // device uses signed values + val = (val + Math.pow(256, cmd.size)) + } + + state[name] = val + log.debug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + log.debug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint=0) { + log.debug "${cmd} (${endpoint})" + sendSwitchEvent(cmd.value, endpoint) +} + +void zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint=0) { + log.debug "${cmd} (${endpoint})" + sendSwitchEvent(cmd.value, endpoint) +} + +void sendSwitchEvent(int rawValue, int endpoint) { + String value = (rawValue ? "on" : "off") + if (endpoint == mainEndpoint) { + log.debug("Switch is ${value}") + sendEvent(name: "switch", value: value) + } else { + def child = findChildByEndpoint(endpoint) + if (child) { + log.debug("${child.displayName} switch is ${value}") + child.sendEvent(name: "switch", value: value) + } else { + log.warn "Child device for endpoint ${endpoint} does not exist" + } + + // Workaround for device not sending reports for main endpoint for physical or z-wave control. + if (device.currentValue("switch") != value) { + sendHubCommand([switchBinaryGetCmd(mainEndpoint)]) + } + } +} + +void zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + + int endpoint = cmd.sceneNumber + String value + + switch (cmd.keyAttributes){ + case btnPushed: + value = "pushed" + break + case btnReleased: + log.debug "Button Value 'released' is not supported by SmartThings" + break + case btnHeld: + value = "held" + break + default: + value = "pushed_${cmd.keyAttributes - 1}x" + } + + if (value) { + sendButtonEvent(findChildByEndpoint(endpoint), value) + } + } +} + +void sendButtonEvent(child, String value) { + if (child) { + log.debug "${child.displayName} button ${value}" + child.sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Unhandled zwaveEvent: $cmd" +} + +Integer getSettingVal(String name) { + Integer value = safeToInt(settings[name], null) + if ((value == null) && (getStoredVal(name) != null)) { + return configParams[name].defaultVal + } else { + return value + } +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +def findChildByEndpoint(int endpoint) { + String dni = buildChildDNI(endpoint) + return childDevices?.find { it.deviceNetworkId == dni } +} + +String buildChildDNI(int endpoint) { + return "${device.deviceNetworkId}:${endpoint}" +} + +int getEndpointFromDNI(String dni) { + if (dni?.contains(":")) { + String lastChar = dni.reverse().take(1) + return safeToInt(lastChar, mainEndpoint) + } else { + return mainEndpoint + } +} \ No newline at end of file From 9a2fc20fc28fea843c2e0f7834b46f867e08e658 Mon Sep 17 00:00:00 2001 From: AltyorFig <95210115+AltyorFig@users.noreply.github.com> Date: Mon, 7 Mar 2022 15:53:11 +0100 Subject: [PATCH 129/184] DevWs for NodOn containing containing NodOn lighting Switch and 2 more (#77876) * DevWs for NodOn containing containing NodOn lighting Switch and 2 more * add space outcluster --- .../zigbee-multi-switch.src/zigbee-multi-switch.groovy | 3 ++- .../smartthings/zigbee-switch.src/zigbee-switch.groovy | 7 +++++-- .../zigbee-window-shade.src/zigbee-window-shade.groovy | 5 +++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index 4be9b697ea0..47d8af4f804 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -92,7 +92,8 @@ metadata { fingerprint manufacturer: "LELLKI", model: "JZ-ZB-006", deviceJoinName: "LELLKI Switch 1" //LELLKI 6 Gang Switch 1 // NodOn - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 0008, FC57", outClusters: "0021", manufacturer: "NodOn", model: "SIN-4-2-20", deviceJoinName: "NodOn Light 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 0008, 1000, FC57", outClusters: "0003, 0006, 0019", manufacturer: "NodOn", model: "SIN-4-2-20", deviceJoinName: "NodOn Light 1" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 0008, 1000, FC57", outClusters: "0003, 0006, 0019", manufacturer: "NodOn", model: "SIN-4-2-20_PRO", deviceJoinName: "NodOn Light 1" // SiHAS Switch (2~6 Gang) fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z2", deviceJoinName: "SiHAS Switch 1" diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index d64ae59efc6..b0293c12ea5 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -78,7 +78,8 @@ metadata { fingerprint manufacturer: "Leviton", model: "DG15A", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Zigbee Plug-In Switch DG15A, Raw Description: 01 0104 010A 00 06 0000 0003 0004 0005 0006 0B05 01 0019 // NodOn - fingerprint profileId: "0104", deviceId: "0002", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-1-20", deviceJoinName: "NodOn Switch" + fingerprint profileId: "0104", deviceId: "0002", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 1000, FC57", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-1-20", deviceJoinName: "NodOn Switch" + fingerprint profileId: "0104", deviceId: "0002", inClusters: "0000, 0003, 0004, 0005, 0006, 0007, 1000, FC57", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-1-20_PRO", deviceJoinName: "NodOn Switch" // Orvibo fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "095db3379e414477ba6c2f7e0c6aa026", deviceJoinName: "Orvibo Switch" //Orvibo Smart Switch @@ -198,4 +199,6 @@ def configure() { sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) log.debug "Configuring Reporting and Bindings." zigbee.onOffRefresh() + zigbee.onOffConfig() -} \ 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 0bc16af7238..e580330b3fc 100644 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -29,8 +29,9 @@ metadata { command "pause" // NodOn - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0021", manufacturer: "NodOn", model: "SIN-4-RS-20", deviceJoinName: "NodOn Window Treatment" - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-RS-20", deviceJoinName: "NodOn Window Treatment" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-RS-20_PRO", deviceJoinName: "NodOn Window Treatment" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "eZEX Window Treatment" // SY-IoT201-BD //SOMFY Blind Controller/eZEX fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.6", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.8", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) From ebd2a4a9e4d75052bd7aae10a9c88486a1402b0f Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Tue, 8 Mar 2022 08:55:13 +0900 Subject: [PATCH 130/184] Update led-cpx-light.groovy Added an ocf device type. Added initial dimming level. --- .../zigbee-motion-sensor-light.src/led-cpx-light.groovy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy index 074c8021d35..5af6d858682 100644 --- a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy @@ -17,7 +17,7 @@ */ metadata { - definition(name: "LED CPX light", namespace: "SAMSUNG LED", author: "SAMSUNG LED") { + definition(name: "LED CPX light", namespace: "SAMSUNG LED", author: "SAMSUNG LED", ocfDeviceType: "oic.d.light") { capability "Actuator" capability "Color Temperature" @@ -144,7 +144,10 @@ def setColorTemperature(value) { } def installed() { - addChildSensor() + if ((device.currentState("level")?.value == null) || (device.currentState("level")?.value == 0)) { + sendEvent(name: "level", value: 100) + } + addChildSensor() } def addChildSensor() { From f4c921a6c048126b2e56569db4e337aab6156ffe Mon Sep 17 00:00:00 2001 From: dsobierajsk Date: Wed, 9 Mar 2022 14:21:13 +0100 Subject: [PATCH 131/184] ICP-13805 Added YMF40 to bad models which reports battery incorrectly --- devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index abeb1c082c6..2121d9d531a 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -1135,7 +1135,7 @@ def isYaleLock() { } def isYaleFingerprintLock() { - return "ASSA ABLOY iRevo" == device.getDataValue("manufacturer") && ("iZBModule01" || "c700000202" || "0700000001" == device.getDataValue("model")) + return "ASSA ABLOY iRevo" == device.getDataValue("manufacturer") && ("iZBModule01" || "c700000202" || "0700000001" || "06ffff2027" == device.getDataValue("model")) } /** @@ -1150,7 +1150,8 @@ def reportsBatteryIncorrectly() { "YRD210 PB DB", "YRD220/240 TSDB", "YRL210 PB LL", - "c700000202" //YDF40 + "c700000202", //YDF40 + "06ffff2027" //YMF40 ] return device.getDataValue("model") in badModels } From 5bcf02236755e2881c37a1a0dd2a4d52e5d6e527 Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Thu, 10 Mar 2022 17:04:44 -0500 Subject: [PATCH 132/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZEN51 Dry Contact Relay (#77898) * DevWs for Zooz (The Smartest House) containing containing Zooz ZEN51 Dry Contact Relay * Zooz ZEN51 Dry Contact Relay changes * Zooz ZEN51 Dry Contact Relay changes --- .../zooz-zen51-dry-contact-relay.groovy | 300 ++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 devicetypes/zooz/zooz-zen51-dry-contact-relay.src/zooz-zen51-dry-contact-relay.groovy diff --git a/devicetypes/zooz/zooz-zen51-dry-contact-relay.src/zooz-zen51-dry-contact-relay.groovy b/devicetypes/zooz/zooz-zen51-dry-contact-relay.src/zooz-zen51-dry-contact-relay.groovy new file mode 100644 index 00000000000..faa8fe2c45f --- /dev/null +++ b/devicetypes/zooz/zooz-zen51-dry-contact-relay.src/zooz-zen51-dry-contact-relay.groovy @@ -0,0 +1,300 @@ +/* + * Zooz ZEN51 Dry Contact Relay + * + * Changelog: + * + * 2022-03-09 + * - requested change. + * 2022-03-02 + * - Removed central scene setting + * 2022-03-01 + * - Publication Release + * + * Copyright 2022 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x22: 1, // ApplicationStatus + 0x25: 1, // SwitchBinary + 0x55: 1, // TransportService + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5B: 1, // CentralScene + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x85: 2, // Association + 0x86: 1, // Version + 0x87: 2, // Indicator (3) + 0x8E: 2, // MultiChannelAssociation + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 +] + +@Field static int btnPushed = 0 +@Field static int btnReleased = 1 +@Field static int btnHeld = 2 +@Field static List supportedButtonValues = ["pushed","held","pushed_2x","pushed_3x","pushed_4x","pushed_5x"] + +@Field static Map configParams = [ + ledIndicator: [num:1, title:"Led indicator", size:1, defaultVal:1, options:[0:"Disabled", 1:"Enabled"]], + autoOff: [num:2, title:"Auto Off Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + autoOn: [num:3, title:"Auto On Timer", size:2, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(timer unit)"], + timerUnit: [num:10, title:"Timer Unit", size:1, defaultVal:1, options:[1:"Minutes", 2:"Seconds"]], + statusAfterPowerFailure: [num:4, title:"On/Off Status After Power Failure", size:1, defaultVal:2, options:[0:"Forced off", 1:"Forced on", 2:"Restore previous state"]], + loadControl: [num:6, title:"Load Control", size:1, defaultVal:1, options:[0:"Disable Switch/ Enable Z-Wave", 1:"Enable Switch and Z-Wave", 2:"Disable Switch and Z-Wave"]], + switchType: [num:7, title:"Switch Type", size:1, defaultVal:2, options:[0:"Toggle Switch", 1:"Momentary Light Switch", 2:"Toggle Up On/Down Off", 3:"3-way Impulse Control", 4:"Garage Door Mode"]], + relayBehavior: [num:9, title:"Relay Type Behavior", size:1, defaultVal:0, options:[0:"Normally Open (NO)", 1:"Normally Closed (NC)"]], + impulseDuration: [num:11, title:"Impulse Duration for 3-way", size:1, defaultVal:10, range:"2..200", desc:"2..200 (seconds)"] +] + +metadata { + definition ( + name: "Zooz ZEN51 Dry Contact Relay", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "oic.d.light", + mnmn: "SmartThingsCommunity", + vid: "d4bdecb2-4374-3c96-aceb-24223399fe5f" + ) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Button" + capability "Refresh" + capability "Health Check" + + // zw:Ls2a type:1000 mfr:027A prod:0104 model:0201 ver:1.24 zwv:7.15 lib:03 cc:5E,55,9F,6C,22 sec:25,70,85,59,8E,86,72,5A,73,7A,5B,87 + fingerprint mfr: "027A", prod: "0104", model: "0201", deviceJoinName: "Zooz Switch" // Zooz ZEN51 Dry Contact Relay + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + description: "Default: ${param.options[param.defaultVal]}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input name, "number", + title: param.title, + description: "${param.desc} - Default: ${param.defaultVal}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + } +} + +def installed() { + log.debug "installed()..." + initialize() + state.firstConfig = true +} + +def updated() { + log.debug "updated()..." + initialize() + + if (!state.firstConfig) { + configure() + } else { + state.firstConfig = false + } +} + +void initialize() { + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((60 * 60 * 3) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + if (!device.currentValue("numberOfButtons")) { + sendEvent(name:"numberOfButtons", value:1, displayed:false) + sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed: false) + sendButtonEvent("pushed") + } +} + +def configure() { + log.debug "configure()..." + List cmds = [] + + if (device.currentValue("switch") == null) { + cmds << secureCmd(zwave.switchBinaryV1.switchBinaryGet()) + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if (storedVal != settingVal) { + log.debug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: settingVal)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + if (cmds) { + sendHubCommand(cmds, 500) + } +} + +def on() { + log.debug "on()..." + return [ secureCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF)) ] +} + +def off() { + log.debug "off()..." + return [ secureCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00)) ] +} + +def ping() { + log.debug "ping()..." + return [ secureCmd(zwave.switchBinaryV1.switchBinaryGet()) ] +} + +def refresh() { + log.debug "refresh()..." + sendHubCommand([ secureCmd(zwave.switchBinaryV1.switchBinaryGet()) ]) +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + int val = cmd.scaledConfigurationValue + + if (val < 0) { + // device uses signed values + val = (val + Math.pow(256, cmd.size)) + } + + state[name] = val + log.debug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${val}" + } else { + log.debug "Parameter #${cmd.parameterNumber} = ${cmd.scaledConfigurationValue}" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + log.debug "${cmd}" + sendSwitchEvent(cmd.value) +} + +void zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + log.debug "${cmd}" + sendSwitchEvent(cmd.value) +} + +void sendSwitchEvent(int rawValue) { + String value = (rawValue ? "on" : "off") + log.debug("Switch is ${value}") + sendEvent(name: "switch", value: value) +} + +void zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + + String value + switch (cmd.keyAttributes){ + case btnPushed: + value = "pushed" + break + case btnReleased: + // value = released" + log.debug "Button Value 'released' is not supported by SmartThings" + break + case btnHeld: + value = "held" + break + default: + value = "pushed_${cmd.keyAttributes - 1}x" + } + + if (value) { + sendButtonEvent(value) + } + } +} + +void sendButtonEvent(String value) { + log.debug "button ${value}" + sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Unhandled zwaveEvent: $cmd" +} + +Integer getSettingVal(String name) { + Integer value = safeToInt(settings[name], null) + if ((value == null) && (getStoredVal(name) != null)) { + return configParams[name].defaultVal + } else { + return value + } +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} \ No newline at end of file From 810faf5771956d8d48b2d1da37c3fdfb3f2ac17a Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Thu, 10 Mar 2022 17:05:07 -0500 Subject: [PATCH 133/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZSE11 Q Sensor (#77897) * DevWs for Zooz (The Smartest House) containing containing Zooz ZSE11 Q Sensor * Zooz ZSE11 Q Sensor changes * Zooz ZSE11 Q Sensor changes --- .../zooz-zse11-q-sensor.groovy | 429 ++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100644 devicetypes/zooz/zooz-zse11-q-sensor.src/zooz-zse11-q-sensor.groovy diff --git a/devicetypes/zooz/zooz-zse11-q-sensor.src/zooz-zse11-q-sensor.groovy b/devicetypes/zooz/zooz-zse11-q-sensor.src/zooz-zse11-q-sensor.groovy new file mode 100644 index 00000000000..ea4f04ea16e --- /dev/null +++ b/devicetypes/zooz/zooz-zse11-q-sensor.src/zooz-zse11-q-sensor.groovy @@ -0,0 +1,429 @@ +/* + * Zooz ZSE11 Q Sensor + * + * Changelog: + * + * 2022-03-09 + * - Requested changes + * 2022-03-02 + * - Requested changes + * 2022-03-01 + * - Publication Release + * + * Copyright 2022 Zooz + * + * 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x30: 2, // SensorBinary + 0x31: 5, // SensorMultilevel + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x71: 3, // Notification + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x7A: 2, // FirmwareUpdateMd + 0x80: 1, // Battery + 0x84: 2, // WakeUp + 0x85: 2, // Association + 0x86: 1, // Version + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 +] + +@Field static String batteryCC = "80" +@Field static int homeSecurity = 7 +@Field static int homeSecurityTamper = 3 +@Field static int tempSensorType = 1 +@Field static int lightSensorType = 3 +@Field static int humiditySensorType = 5 +@Field static int motionSensorType = 12 + +metadata { + definition ( + name: "Zooz ZSE11 Q Sensor", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "x.com.st.d.sensor.motion", + mnmn: "SmartThingsCommunity", + vid: "42067896-6424-3a34-b753-b87d8c92262f" + ) { + capability "Sensor" + capability "Motion Sensor" + capability "Tamper Alert" + capability "Temperature Measurement" + capability "Illuminance Measurement" + capability "Relative Humidity Measurement" + capability "Battery" + capability "Refresh" + capability "Health Check" + capability "Power Source" + + // zw:Ss2 type:0701 mfr:027A prod:0200 model:0006 ver:1.09 zwv:6.04 lib:03 cc:5E,6C,55,98,9F sec:86,72,71,59,85,80,84,73,30,31,70,5A,7A + fingerprint mfr:"027A", prod:"0200", model:"0006", deviceJoinName: "Zooz Multipurpose Sensor" // Zooz ZSE11 Q Sensor (EU) + // zw:Ss2 type:0701 mfr:027A prod:0201 model:0006 ver:1.09 zwv:6.04 lib:03 cc:5E,6C,55,98,9F sec:86,72,71,59,85,80,84,73,30,31,70,5A,7A + fingerprint mfr:"027A", prod:"0201", model:"0006", deviceJoinName: "Zooz Multipurpose Sensor" // Zooz ZSE11 Q Sensor (US) + // zw:Ss2 type:0701 mfr:027A prod:0202 model:0006 ver:1.09 zwv:6.04 lib:03 cc:5E,6C,55,98,9F sec:86,72,71,59,85,80,84,73,30,31,70,5A,7A + fingerprint mfr:"027A", prod:"0202", model:"0006", deviceJoinName: "Zooz Multipurpose Sensor" // Zooz ZSE11 Q Sensor (AU) + } + + preferences { + configParams.each { param -> + if (param.options) { + input "configParam${param.num}", "enum", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input "configParam${param.num}", "number", + title: "${param.name}:", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + + input "tempOffset", "decimal", + title: "Temperature Offset:", + required: false, + defaultValue: 0, + range: "-50..50" + + input "humidityOffset", "number", + title: "Humidity Offset:", + required: false, + defaultValue: 0, + range: "-50..50" + + input "lightOffset", "number", + title: "Light Offset:", + required: false, + defaultValue: 0, + range: "-20000..20000" + } +} + +def installed() { + log.debug "installed()..." + state.firstConfig = true + initialize() +} + +def updated() { + log.debug "updated()..." + + initialize() + + if (!state.firstConfig) { + if (device.currentValue("powerSource") == "battery") { + logForceWakeupMessage("Configuration changes will be sent to the device the next time it wakes up.") + } else { + sendHubCommand(getConfigCmds()) + } + } else { + sendHubCommand(getRefreshCmds()) + state.firstConfig = false + } +} + +void initialize() { + if (!device.currentValue("checkInterval")) { + sendEvent(name: "checkInterval", value: ((60 * 60 * 24) + (60 * 5)), displayed: false, data:[protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } + + if (!device.currentValue("tamper")) { + sendEvent(name: "tamper", value: "clear") + } + + if (device.currentValue("powerSource") == null) { + boolean hasBatteryCC = ((zwaveInfo?.cc?.find { it.toString() == batteryCC }) || (zwaveInfo?.sec?.find { it.toString() == batteryCC })) + + String powerSource = (hasBatteryCC ? "battery" : "dc") + sendEvent(name: "powerSource", value: powerSource) + + if (powerSource == "dc") { + sendEvent(name: "battery", value: 100, unit: "%") + } + } + + sendTempEvent(state.reportedTemp) + sendLightEvent(state.reportedLight) + sendHumidityEvent(state.reportedHumidity) +} + +def configure() { + log.debug "configure()..." + sendHubCommand(getConfigCmds(), 200) +} + +List getConfigCmds() { + List cmds = [] + + configParams.each { param -> + def storedVal = safeToInt(state["configVal${param.num}"] , null) + if ("${storedVal}" != "${param.value}") { + log.debug "Changing ${param.name}(#${param.num}) from ${storedVal} to ${param.value}" + cmds << secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: param.size, scaledConfigurationValue: param.value)) + cmds << secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) + } + } + return cmds +} + +def refresh() { + log.debug "refresh()..." + + if (device.currentValue("tamper") != "clear") { + sendEvent(name:"tamper", value:"clear") + } + + if (device.currentValue("powerSource") == "battery") { + state.pendingRefresh = true + logForceWakeupMessage("The sensor values will be requested the next time the device wakes up.") + } else { + sendHubCommand(getRefreshCmds()) + } +} + +void logForceWakeupMessage(msg) { + log.debug "${msg} You can force the device to wake up immediately by holding the z-button for 3 seconds." +} + +List getRefreshCmds() { + return [ + secureCmd(zwave.sensorBinaryV2.sensorBinaryGet(sensorType: motionSensorType)), + sensorMultilevelGetCmd(tempSensorType), + sensorMultilevelGetCmd(lightSensorType), + sensorMultilevelGetCmd(humiditySensorType), + batteryGetCmd() + ] +} + +String sensorMultilevelGetCmd(sensorType) { + def scale = (sensorType == tempSensorType ? 0 : 1) + return secureCmd(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: scale, sensorType: sensorType)) +} + +String batteryGetCmd() { + return secureCmd(zwave.batteryV1.batteryGet()) +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + log.debug "Device Woke Up" + List cmds = [] + + if (state.pendingRefresh) { + state.pendingRefresh = false + cmds += getRefreshCmds() + } + + cmds += getConfigCmds() + + if (!cmds) { + cmds << batteryGetCmd() + } + + cmds << secureCmd(zwave.wakeUpV1.wakeUpNoMoreInformation()) + sendHubCommand(cmds) +} + +void zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + int val = (cmd.batteryLevel == 0xFF ? 1 : cmd.batteryLevel) + val = Math.min(Math.max(1, val), 100) + + if (device.currentValue("powerSource") != "battery") { + log.debug "powerSource is battery" + sendEvent(name:"powerSource", value:"battery") + } + + log.debug "battery is ${val}%" + sendEvent(name:"battery", value:val, unit:"%", isStateChange:true) +} + +void zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + switch (cmd.sensorType) { + case tempSensorType: + def temp = convertTemperatureIfNeeded(cmd.scaledSensorValue, (cmd.scale ? "F" : "C"), cmd.precision) + sendTempEvent(temp) + break + case lightSensorType: + sendLightEvent(cmd.scaledSensorValue) + break + case humiditySensorType: + sendHumidityEvent(cmd.scaledSensorValue) + break + default: + log.debug "Unhandled: ${cmd}" + } +} + +void sendTempEvent(reportedVal) { + reportedVal = safeToDec(reportedVal) + state.reportedTemp = reportedVal + + def adjVal = (safeToDec(settings?.tempOffset) + reportedVal) + log.debug "temperature is ${adjVal}°${temperatureScale}" + sendEvent(name:"temperature", value:adjVal, unit:temperatureScale) +} + +void sendLightEvent(reportedVal) { + reportedVal = safeToInt(reportedVal) + if (reportedVal < 0) { + // workaround for bug in original firmware + reportedVal = (reportedVal + 65536) + } + state.reportedLight = reportedVal + + def adjVal = (safeToInt(settings?.lightOffset) + reportedVal) + if (adjVal < 0) adjVal = 0 + log.debug "illuminance is ${adjVal}lux" + sendEvent(name:"illuminance", value:adjVal, unit:"lux") +} + +void sendHumidityEvent(reportedVal) { + reportedVal = safeToInt(reportedVal) + state.reportedHumidity = reportedVal + + def adjVal = (safeToInt(settings?.humidityOffset) + reportedVal) + adjVal = Math.min(Math.max(0, adjVal), 100) + log.debug "humidity is ${adjVal}%" + sendEvent(name:"humidity", value:adjVal, unit:"%") +} + +void zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationType == homeSecurity) { + if ((cmd.event == homeSecurityTamper) || (cmd.eventParameter[0] == homeSecurityTamper)) { + String value = (cmd.event ? "detected" : "clear") + log.debug "tamper is ${value}" + sendEvent(name:"tamper", value:value) + } + } +} + +void zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { + if (cmd.sensorType == motionSensorType) { + String value = (cmd.sensorValue ? "active" : "inactive") + log.debug "motion is ${value}" + sendEvent(name:"motion", value:value) + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + def param = configParams.find { it.num == cmd.parameterNumber } + if (param) { + def val = cmd.scaledConfigurationValue + log.debug "${param.name}(#${param.num}) = ${val}" + state["configVal${param.num}"] = val + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Ignored Command: $cmd" +} + +List getConfigParams() { + [ + motionSensitivityParam, + motionResetParam, + motionLedParam, + reportingFrequencyParam, + temperatureThresholdParam, + humidityThresholdParam, + lightThresholdParam + ] +} + +Map getMotionSensitivityParam() { + return getParam(12, "Motion Sensitivity", 1, 6, [0:"Motion Disabled", 1:"1 - Least Sensitive", 2:"2", 3:"3", 4:"4", 5:"5", 6:"6 [DEFAULT]", 7:"7", 8:"8 - Most Sensitive"]) +} + +Map getMotionResetParam() { + return getParam(13, "Motion Clear Time (10-3600 Seconds)", 2, 30, null, "10..3600") +} + +Map getMotionLedParam() { + return getParam(19, "Motion LED", 1, 1, [0:"Disabled", 1:"Enabled [DEFAULT]"]) +} + +Map getReportingFrequencyParam() { + return getParam(172, "Minimum Reporting Frequency (1-774 Hours)", 2, 4, null, "1..744") +} + +Map getTemperatureThresholdParam() { + return getParam(183, "Temperature Reporting Threshold (1-144°F)", 2, 1, null, "1..144") +} + +Map getHumidityThresholdParam() { + return getParam(184, "Humidity Reporting Threshold (0:No Reports, 1-80%)", 1, 5, null, "0..80") +} + +Map getLightThresholdParam() { + return getParam(185, "Light Reporting Threshold (0:No Reports, 1-30000 lux)", 2, 50, null, "0..30000") +} + +Map getParam(Integer num, String name, Integer size, Integer defaultVal, Map options, range=null) { + Integer val = safeToInt((settings ? settings["configParam${num}"] : null), defaultVal) + + return [num: num, name: name, size: size, defaultVal: defaultVal, value: val, options: options, range: range] +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} + +BigDecimal safeToDec(val, BigDecimal defaultVal=0) { + return "${val}"?.isBigDecimal() ? "${val}".toBigDecimal() : defaultVal +} \ No newline at end of file From 688e0253cc3d895166ad33cc9482132cc9895538 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 15 Mar 2022 00:03:49 +0800 Subject: [PATCH 134/184] DevWs for NIE-TECH CO., LTD. containing containing ZigBee Switch (#77938) * DevWs for NIE-TECH CO., LTD. containing containing ZigBee Switch * Except the modifications, others remain the same as the master. * Except the modifications, others remain the same as the master. Co-authored-by: Winnie Wen --- devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index b0293c12ea5..6814c50d000 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -32,6 +32,9 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "eWeLink", model: "SA-003-Zigbee", deviceJoinName: "eWeLink Outlet", ocfDeviceType: "oic.d.smartplug" //eWeLink SmartPlug (SA-003) fingerprint profileId: "0104", inClusters: "0000,0003,0004,00005,0006", outClusters: "0000", manufacturer: "eWeLink", model: "ZB-SW01", deviceJoinName: "eWeLink Switch" + // Minoston + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "Minoston", model: "ZB36S", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Minoston SmartPlug + // LELLKI fingerprint profileId: "0104", inClusters: "0000,0003,0004,00005,0006", outClusters: "0000", manufacturer: "LELLKI", model: "JZ-ZB-001", deviceJoinName: "LELLKI Switch" From be1aeca6d181369e542dac671e7e57acee25fa65 Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 14 Mar 2022 10:43:58 -0700 Subject: [PATCH 135/184] Revert "Update Orvibo-Contact-Sensor.groovy" This reverts commit a5c225a3dcd3b90756c0558ecf0cda224db82dea. --- .../Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index 9888fae4fb6..0df9da8f9a7 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -166,11 +166,10 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" def result = [:] def manufacturer = getDataValue("manufacturer") - def application = getDataValue("application") if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= "17") { + if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From 45cdecd145623ec2a5ddfe6fc496893eaeb492c3 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 15 Mar 2022 17:31:09 +0900 Subject: [PATCH 136/184] DevWs for SHINA SYSTEM containing containing Zigbee Power Meter (#77947) --- .../sihas-zigbee-power-meter.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy b/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy index fd7d4091644..b64146158b3 100644 --- a/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy +++ b/devicetypes/shinasys/sihas-zigbee-power-meter.src/sihas-zigbee-power-meter.groovy @@ -143,7 +143,7 @@ def configure() { sendEvent(name: "checkInterval", value: 2 * 60 + 10 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) log.debug "Configuring Reporting" - configCmds = zigbee.simpleMeteringPowerConfig() + + configCmds = zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_HISTORICAL_CONSUMPTION, DataType.INT24, 5, 600, 1) + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 5, 600, 1) + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY, DataType.UINT16, 10, 600, 3) + /* 3 unit : 0.3Hz */ zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE, DataType.UINT16, 5, 600, 3) + /* 3 unit : 0.3V */ @@ -159,4 +159,4 @@ private getEnergyDivisor() { 1000 } private getFrequencyDivisor() { 10 } private getVoltageDivisor() { 10 } private getCurrentDivisor() { 100 } -private getPowerFactorDivisor() { 1 } +private getPowerFactorDivisor() { 1 } \ No newline at end of file From eb59c8c6bc1a64b1861c420a3d7d3ba8cc733f25 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:08:31 +0900 Subject: [PATCH 137/184] DevWs for SHINA SYSTEM containing containing SiHAS Zigbee Metering Plug (#77948) --- .../sihas-zigbee-metering-plug.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy b/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy index c400f0255c0..6d291988590 100644 --- a/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy +++ b/devicetypes/shinasys/sihas-zigbee-metering-plug.src/sihas-zigbee-metering-plug.groovy @@ -156,7 +156,7 @@ def configure() { log.debug "Configuring Reporting" configCmds = zigbee.onOffConfig() + - zigbee.simpleMeteringPowerConfig() + + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_HISTORICAL_CONSUMPTION, DataType.INT24, 5, 600, 1) + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 5, 600, 1) + zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY, DataType.UINT16, 10, 600, 3) + /* 3 unit : 0.3Hz */ zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE, DataType.UINT16, 5, 600, 3) + /* 3 unit : 0.3V */ @@ -172,4 +172,4 @@ private getEnergyDivisor() { 1000 } private getFrequencyDivisor() { 10 } private getVoltageDivisor() { 10 } private getCurrentDivisor() { 100 } -private getPowerFactorDivisor() { 1 } +private getPowerFactorDivisor() { 1 } \ No newline at end of file From ac64e68a990c93ee1dc10d9edf953e6f20663ba8 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:58:17 +0900 Subject: [PATCH 138/184] DevWs for SHINA SYSTEM containing containing Zigbee Multi Button (#77951) --- .../zigbee-multi-button.src/zigbee-multi-button.groovy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy index 628bd4486ca..c829563ca9b 100644 --- a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy +++ b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy @@ -37,11 +37,11 @@ metadata { fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", outClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", manufacturer: "ADUROLIGHT", model: "ADUROLIGHT_CSC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria scene button switch V2.0 fingerprint inClusters: "0000, 0003, 0008, FCCC, 1000", outClusters: "0003, 0004, 0006, 0008, FCCC, 1000", manufacturer: "AduroSmart Eria", model: "Adurolight_NCC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria dimming button switch V2.1 fingerprint inClusters: "0000, 0003, 0008, FCCC, 1000", outClusters: "0003, 0004, 0006, 0008, FCCC, 1000", manufacturer: "ADUROLIGHT", model: "Adurolight_NCC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria dimming button switch V2.0 - fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "MSM-300Z", deviceJoinName: "SiHAS Remote Control", mnmn: "0Ar2", vid: "ST_9639674b-8026-4f61-9579-585cd0fe1fad" - fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "BSM-300Z", deviceJoinName: "SiHAS Remote Control", mnmn: "0Ar2", vid: "ST_9639674b-8026-4f61-9579-585cd0fe1fad" - fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB1", deviceJoinName: "SiHAS Remote Control", mnmn: "0Ar2", vid: "ST_9639674b-8026-4f61-9579-585cd0fe1fad" - fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB2", deviceJoinName: "SiHAS Remote Control", mnmn: "0Ar2", vid: "ST_9639674b-8026-4f61-9579-585cd0fe1fad" - fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB3", deviceJoinName: "SiHAS Remote Control", mnmn: "0Ar2", vid: "ST_9639674b-8026-4f61-9579-585cd0fe1fad" + fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "MSM-300Z", deviceJoinName: "SiHAS Remote Control", mnmn: "SmartThingsCommunity", vid: "b18d7e4e-3775-3606-85a6-14b63cd8a0e3" + fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "BSM-300Z", deviceJoinName: "SiHAS Remote Control", mnmn: "SmartThingsCommunity", vid: "0b6ace5f-e2d8-3e34-9b2a-5662bc9e20e1" + fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB1", deviceJoinName: "SiHAS Remote Control", mnmn: "SmartThingsCommunity", vid: "0b6ace5f-e2d8-3e34-9b2a-5662bc9e20e1" + fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB2", deviceJoinName: "SiHAS Remote Control", mnmn: "SmartThingsCommunity", vid: "57bb4dc5-40ef-335f-8e60-cc63190cc73b" + fingerprint inClusters: "0000,0001,0003,0020", outClusters: "0003,0004,0006,0019", manufacturer: "ShinaSystem", model: "SBM300ZB3", deviceJoinName: "SiHAS Remote Control", mnmn: "SmartThingsCommunity", vid: "f3f3ab0e-82f5-36dd-839f-a048e1a3f8f9" } tiles { From 53a1598159573de9a608e8b142e42a7c6065898b Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Tue, 15 Mar 2022 22:42:13 +0800 Subject: [PATCH 139/184] Update orvibo-Moisture-sensor.groovy (#77886) * Update orvibo-Moisture-sensor.groovy update thirdreality battery percent report Update * update orvibo-Moisture-sensor.groovy update orvibo-Moisture-sensor.groovy * update orvibo-moisture-sensor.groovy update orvibo-moisture-sensor.groovy --- .../orvibo-Moisture-Sensor.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy index f7addb7e9f6..c2efdb53720 100644 --- a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy +++ b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy @@ -35,6 +35,7 @@ metadata { fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001, 0009", outClusters: "0019", manufacturer: "HEIMAN", model: "da2edf1ded0d44e1815d06f45ce02029", deviceJoinName: "Orvibo Water Leak Sensor" fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001", manufacturer: "HEIMAN", model: "WaterSensor-N", deviceJoinName: "HEIMAN Water Leak Sensor" //HEIMAN Water Leakage Sensor (HS3WL-E) fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0006,0019", manufacturer:"Third Reality, Inc", model:"3RWS18BZ", deviceJoinName: "ThirdReality Water Leak Sensor" //ThirdReality WaterLeak Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0006,0019", manufacturer:"THIRDREALITY", model:"3RWS18BZ", deviceJoinName: "ThirdReality Water Leak Sensor" //ThirdReality WaterLeak Sensor } simulator { @@ -156,11 +157,12 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage" def result = [:] def manufacturer = getDataValue("manufacturer") + def application = getDataValue("application").toInteger() if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if (manufacturer == "Third Reality, Inc") { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= 17) { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) @@ -170,4 +172,4 @@ def getBatteryPercentageResult(rawValue) { log.debug "${device.displayName} battery was ${result.value}%" result -} \ No newline at end of file +} From 478d5b378c2204bc520047c8c1235ab7b408fc2c Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Tue, 15 Mar 2022 22:42:58 +0800 Subject: [PATCH 140/184] Update zigbee-motion-detector.groovy (#77885) * Update zigbee-motion-detector.groovy update thirdreality battery percent report * update zigbee-motion-detector.groovy update zigbee-motion-detector.groovy * update zigbee-motion-detector.groovy update zigbee-motion-detector.groovy --- .../zigbee-motion-detector.src/zigbee-motion-detector.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy index 14003b028af..2cc8d98d1ce 100644 --- a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy +++ b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy @@ -32,6 +32,7 @@ metadata { fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "Megaman", model: "PS601/z1", deviceJoinName: "INGENIUM Motion Sensor" //INGENIUM ZB PIR Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001", outClusters: "0019", manufacturer: "HEIMAN", model: "PIRSensor-N", deviceJoinName: "HEIMAN Motion Sensor" //HEIMAN Motion Sensor fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RMS16BZ", deviceJoinName: "ThirdReality Motion Sensor" //ThirdReality Motion Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0001, 0500", outClusters: "0019", manufacturer: "THIRDREALITY", model: "3RMS16BZ", deviceJoinName: "ThirdReality Motion Sensor" //ThirdReality Motion Sensor } simulator { status "active": "zone status 0x0001 -- extended status 0x00" @@ -128,11 +129,12 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" def result = [:] def manufacturer = getDataValue("manufacturer") + def application = getDataValue("application").toInteger() if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if (manufacturer == "Third Reality, Inc") { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= 17) { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From 5edcea2ff97ab7f885fb5714c7a323cb8a0cb0e5 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Tue, 15 Mar 2022 22:43:52 +0800 Subject: [PATCH 141/184] Update smartsense-button.groovy (#77934) * Update smartsense-button.groovy Update smartsense-button.groovy * update smartsense-button.groovy update smartsense-button.groovy * update smartsense-button.groovy update smartsense-button.groovy --- .../smartsense-button.src/smartsense-button.groovy | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy index 209c08ad376..c301d5c7a6f 100755 --- a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy +++ b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy @@ -28,6 +28,7 @@ metadata { capability "Sensor" fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "button", deviceJoinName: "Button" + fingerprint inClusters: "0000,0001,0012", outClusters: "0006,0008,0019", manufacturer: "Third Reality, Inc", model: "3RSB22BZ", deviceJoinName: "ThirdReality Smart Button" } simulator { @@ -136,6 +137,8 @@ def parse(String description) { } } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) { map = translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value))) + } else if ( descMap.clusterInt == 0x0012 ) { + map = translateMultiStatus(descMap.value) } } } else if (map.name == "temperature") { @@ -174,6 +177,16 @@ private Map translateZoneStatus(ZoneStatus zs) { } else { } } +private Map translateMultiStatus(String value) { + if (value == "0002" ) { + return getButtonResult('double') + } else if (value == "0001" ) { + return getButtonResult('pushed') + } else if (value == "0000"){ + return getButtonResult('held') + } else {} +} + private Map getBatteryResult(rawValue) { log.debug "Battery rawValue = ${rawValue}" def linkText = getLinkText(device) From 3d3d88c9748b8b4826433023acb170811e6bf5af Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Wed, 16 Mar 2022 09:45:31 +0800 Subject: [PATCH 142/184] update zigbee-motion-detector.groovy update zigbee-motion-detector.groovy --- .../zigbee-motion-detector.src/zigbee-motion-detector.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy index 2cc8d98d1ce..846e3722bdf 100644 --- a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy +++ b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy @@ -129,12 +129,12 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" def result = [:] def manufacturer = getDataValue("manufacturer") - def application = getDataValue("application").toInteger() + def application = getDataValue("application") if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= 17) { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application.toInteger() <= 17) { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From 316637bd334a9f10f85d86d437b7e447fb61f5ac Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Wed, 16 Mar 2022 09:48:35 +0800 Subject: [PATCH 143/184] update orvibo-moisture-sensor.groovy update orvibo-moisture-sensor.groovy --- .../orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy index c2efdb53720..fe909265b8f 100644 --- a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy +++ b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy @@ -157,12 +157,12 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage" def result = [:] def manufacturer = getDataValue("manufacturer") - def application = getDataValue("application").toInteger() + def application = getDataValue("application") if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application <= 17) { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application.toInteger() <= 17) { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From 72b6baa41a2ee91494770a6bc98448f63cf20a63 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Wed, 16 Mar 2022 09:52:54 +0800 Subject: [PATCH 144/184] update orvibo-contact-sensor.groovy update orvibo-contact-sensor.groovy --- .../Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy index 0df9da8f9a7..04d568956e8 100755 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -166,10 +166,12 @@ def getBatteryPercentageResult(rawValue) { log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" def result = [:] def manufacturer = getDataValue("manufacturer") + def application = getDataValue("application") + if (0 <= rawValue && rawValue <= 200) { result.name = 'battery' result.translatable = true - if (manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") { + if ((manufacturer == "Third Reality, Inc" || manufacturer == "THIRDREALITY") && application.toInteger() <= 17) { result.value = Math.round(rawValue) } else { result.value = Math.round(rawValue / 2) From 979628a4770c3f47700cf3019f1e8dbc923b8ebf Mon Sep 17 00:00:00 2001 From: Sarkis008 <92102906+Sarkis008@users.noreply.github.com> Date: Wed, 16 Mar 2022 17:23:58 +0400 Subject: [PATCH 145/184] DevWs for HELTUN containing HELTUN TPS05 Switch (#77846) * Create heltun-tps05-switch.groovy * Fix typos Change child device names * initial * initial * Indentation * Delete heltun-child-backlight.groovy * Requested changes * Requested changes * Requested changes 2 * Requested changes 3 * Indentation * Requested changed 4 * Identation 2 * identation fix Co-authored-by: Artur Sargsyan --- .../heltun-tps05-switch.groovy | 724 ++++++++++++++++++ 1 file changed, 724 insertions(+) create mode 100644 devicetypes/heltun/heltun-tps05-switch.src/heltun-tps05-switch.groovy diff --git a/devicetypes/heltun/heltun-tps05-switch.src/heltun-tps05-switch.groovy b/devicetypes/heltun/heltun-tps05-switch.src/heltun-tps05-switch.groovy new file mode 100644 index 00000000000..c86d131d699 --- /dev/null +++ b/devicetypes/heltun/heltun-tps05-switch.src/heltun-tps05-switch.groovy @@ -0,0 +1,724 @@ +/** + * HELTUN TPS05 Switch + * + * Copyright 2022 Sarkis Kabrailian + * + * 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 groovy.transform.Field + +@Field static int roomTemperature = 1 +@Field static int humidity = 5 +@Field static int illuminance = 3 + +metadata { + definition (name: "HELTUN TPS05 Switch", namespace: "HELTUN", author: "Sarkis Kabrailian", cstHandler: true, mcdSync: true ) { + capability "Temperature Measurement" + capability "Illuminance Measurement" + capability "Relative Humidity Measurement" + capability "Energy Meter" + capability "Power Meter" + capability "Configuration" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0344", prod: "0004", model: "0003", deviceJoinName: "HELTUN Panel" + } + preferences { + input ( + title: "HE-TPS05 | HELTUN Touch Panel Switch", + description: "The user manual document with all technical information is available in support.heltun.com page. In case of technical questions please contact HELTUN Support Team at support@heltun.com", + type: "paragraph", + element: "paragraph" + ) + parameterMap().each { + if (it.title != null) { + input ( + title: "${it.title}", + description: it.description, + type: "paragraph", + element: "paragraph" + ) + } + def unit = it.unit ? it.unit : "" + def defV = it.default as Integer + def defVDescr = it.options ? it.options.get(defV) : "${defV}${unit} - Default Value" + input ( + name: it.name, + title: null, + description: "$defVDescr", + type: it.type, + options: it.options, + range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, + defaultValue: it.default, + required: false + ) + } + } +} + +def checkParam() { + boolean needConfig = false + parameterMap().each { + if (state."$it.name" == null || state."$it.name".state == "defNotConfigured") { + state."$it.name" = [value: it.default as Integer, state: "defNotConfigured"] + needConfig = true + } + if (settings."$it.name" != null && (state."$it.name".value != settings."$it.name" as Integer || state."$it.name".state == "notConfigured")) { + state."$it.name".value = settings."$it.name" as Integer + state."$it.name".state = "notConfigured" + needConfig = true + } + } + if (needConfig) { + configParam() + } +} + +private configParam() { + def cmds = [] + for (parameter in parameterMap()) { + if (state."$parameter.name"?.value != null && state."$parameter.name"?.state in ["notConfigured", "defNotConfigured"] ) { + cmds << zwave.configurationV2.configurationSet(scaledConfigurationValue: state."$parameter.name".value, parameterNumber: parameter.paramNum, size: parameter.size).format() + cmds << zwave.configurationV2.configurationGet(parameterNumber: parameter.paramNum).format() + break + } + } + if (cmds) { + runIn(5, "checkParam") + sendHubCommand(cmds,500) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + def localScale = getTemperatureScale() //HubScale + def deviceScale = (cmd.scale == 1) ? "F" : "C" //DeviceScale + def child = childDevices?.find {channelNumber(it.deviceNetworkId) == 1 } + if (roomTemperature == cmd.sensorType) { + def deviceTemp = cmd.scaledSensorValue + def scaledTemp = (deviceScale == localScale) ? deviceTemp : (deviceScale == "F" ? roundC(fahrenheitToCelsius(deviceTemp)) : celsiusToFahrenheit(deviceTemp).toDouble().round(0).toInteger()) + map.name = "temperature" + map.value = scaledTemp + map.unit = localScale + sendEvent(map) + } else if (humidity == cmd.sensorType) { + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + sendEvent(map) + } else if (illuminance == cmd.sensorType) { + map.name = "illuminance" + map.value = cmd.scaledSensorValue + sendEvent(map) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + def parameter = parameterMap().find( {it.paramNum == cmd.parameterNumber } ).name + if (state."$parameter".value == cmd.scaledConfigurationValue){ + state."$parameter".state = "configured" + } else { + state."$parameter".state = "error" + } + configParam() +} + +def updated() { + if (childDevices && device.label != state.oldLabel) { + childDevices.each { + def newLabel = getChildName(channelNumber(it.deviceNetworkId)) + it.setLabel(newLabel) + } + state.oldLabel = device.label + } + initialize() +} + +def initialize() { + runIn(3, "checkParam") +} + +def installed() { + def numberOfButtons = 5 + state.numberOfButtons = numberOfButtons + def existingChildren = getChildDevices() + for (i in 1..numberOfButtons) { + def buttonNetworkId = "${device.deviceNetworkId}:${i+2*numberOfButtons}" + def relayNetworkId = "${device.deviceNetworkId}:${i+numberOfButtons}" + def backlightNetworkId = "${device.deviceNetworkId}:${i}" + def childRelayExists = (existingChildren.find {child -> child.getDeviceNetworkId() == relayNetworkId} != NULL) + def childButtonExists = (existingChildren.find {child -> child.getDeviceNetworkId() == buttonNetworkId} != NULL) + def childBacklightExists = (existingChildren.find {child -> child.getDeviceNetworkId() == backlightNetworkId} != NULL) + if (!childBacklightExists ) { + addChildDevice("smartthings","Child Switch", backlightNetworkId, device.hubId, [completedSetup: true, label: getChildName(i), isComponent: false]) + } + if (!childRelayExists) { + addChildDevice("HELTUN", "Heltun Child Relay", relayNetworkId, device.hubId,[completedSetup: true, label: getChildName(i+numberOfButtons), isComponent: false]) + } + if (!childButtonExists ) { + addChildDevice("smartthings", "Child Button", buttonNetworkId, device.hubId, [completedSetup: true, label: getChildName(i+2*numberOfButtons), isComponent: true, componentName: "button$i", componentLabel: "Button ${i}"]) + } + } + initialize() +} + +private getChildName(channelNumber) { + def prefix = device.displayName + if (prefix == "HELTUN Panel") { + prefix = "HELTUN" + } + def numberOfButtons = state.numberOfButtons + if (channelNumber in 1..numberOfButtons) { + return "${prefix} " + "${"Backlight"} " + "${channelNumber}" + } + else if (channelNumber in (numberOfButtons+1)..(2*numberOfButtons)){ + return "${prefix} " + "${"Switch"} " + "${channelNumber-numberOfButtons}" + } + else if (channelNumber in (2*numberOfButtons+1)..(3*numberOfButtons)){ + return "${prefix} " + "${"Button"} " + "${channelNumber-numberOfButtons*2}" + } +} + +private channelNumber(String deviceNetworkId) { + deviceNetworkId.split(":")[-1] as Integer +} + +def parse(String description) { + def cmd = zwave.parse(description) + if (cmd) { + return zwaveEvent(cmd) + } +} + +private void setState(value, endpoint = null) { + def cmds = [ + encap(zwave.basicV1.basicSet(value: value), endpoint), + encap(zwave.switchBinaryV1.switchBinaryGet(), endpoint), + ] + sendHubCommand(cmds, 500) +} + +private encap(cmd, endpoint) { + if (endpoint) { + zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd).format() + } else { + cmd.format() + } +} + +def childOn(childId) { + setState(0xFF, channelNumber(childId)) +} + +def childOff(childId) { + setState(0x00, channelNumber(childId)) +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + map.name = "energy" + map.value = cmd.scaledMeterValue + map.unit = "kWh" + sendEvent(map) + } else if (cmd.scale == 2) { + map.name = "power" + map.value = Math.round(cmd.scaledMeterValue) + map.unit = "W" + sendEvent(map) + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + log.info cmd + def numberOfButtons = state.numberOfButtons + def state + def buttonN = cmd.sceneNumber + switch (cmd.keyAttributes as Integer) { + case 0: + state = "pushed" + break + case 1: + state = "up" + break + case 2: + state = "held" + break + } + if (buttonN) { + def buttonId = buttonN + numberOfButtons * 2 + def child = childDevices?.find {channelNumber(it.deviceNetworkId) == buttonId } + child?.sendEvent([name: "button", value: state, data: [buttonNumber: 1], isStateChange: true]) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) { + def numberOfButtons = state.numberOfButtons + def value = cmd.value + def childDevice = childDevices?.find {channelNumber(it.deviceNetworkId) == ep } + def corrRelCons = 0 + def corRelParam = 11 + ep - numberOfButtons + if (ep in numberOfButtons..(2*numberOfButtons)) { + def param = parameterMap().find( {it.paramNum == corRelParam } ).name + def paramState = state."$param" + if (paramState) { + corrRelCons = paramState.value + } + } + if (childDevice) { + childDevice.sendEvent(name: "switch", value: value ? "on" : "off") + if (value) { + sendEvent(name: "switch", value: "on") + childDevice.sendEvent(name: "power", value: corrRelCons, unit: "W") + } else { + childDevice.sendEvent(name: "power", value: 0, unit: "W") + if (!childDevices.any { it.currentValue("switch") == "on" }) { + sendEvent(name: "switch", value: "off") + } + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.clockv1.ClockReport cmd) { + def currDate = Calendar.getInstance(location.timeZone) + def time = [hour: currDate.get(Calendar.HOUR_OF_DAY), minute: currDate.get(Calendar.MINUTE), weekday: currDate.get(Calendar.DAY_OF_WEEK)] + if ((time.hour != cmd.hour) || (time.minute != cmd.minute) || (time.weekday != cmd.weekday)) { + sendHubCommand(zwave.clockV1.clockSet(time).format()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationReport cmd) { + def cmds = [] + if (cmd.groupingIdentifier == 1) { + if (cmd.nodeId != [0, zwaveHubNodeId, 0]) { + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1).format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,0]).format() + } + } + if (cmds) { + sendHubCommand(cmds, 1200) + } +} + +def configure() { + refresh() +} + +def getRefreshCommands() { + def numberOfButtons = state.numberOfButtons + def cmds = [] + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:roomTemperature).format() + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:humidity).format() + cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:illuminance).format() + for (i in 1..(2 * numberOfButtons)) { + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), i) + } + return cmds +} + +def refresh() { + def cmds = getRefreshCommands() + cmds << zwave.clockV1.clockGet().format() + cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1).format() + sendHubCommand(cmds, 1200) + runIn(15, "checkParam") +} + +def ping() { + def cmds = getRefreshCommands() + sendHubCommand(cmds, 1200) +} + +def resetEnergyMeter() { + sendHubCommand(zwave.meterV3.meterReset().format()) +} + +private parameterMap() {[ + [title: "Relays Output Mode", description: "These Parameters determine the type of loads connected to the device relay outputs. " + + "The output type can be NO – normal open (no contact/voltage switch the load OFF) or NC - normal close (output is contacted / there is a voltage to switch the load OFF)", + name: "Selected Relay 1 Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 7, size: 1, default: "0", type: "enum"], + + [name: "Selected Relay 2 Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 8, size: 1, default: "0", type: "enum"], + + [name: "Selected Relay 3 Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 9, size: 1, default: "0", type: "enum"], + + [name: "Selected Relay 4 Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 10, size: 1, default: "0", type: "enum"], + + [name: "Selected Relay 5 Mode", options: [ + 0: "NO - Normal Open", + 1: "NC - Normal Close" + ], paramNum: 11, size: 1, default: "0", type: "enum"], + + [title: "Relays Load Power", description: "These parameters are used to specify the loads power that are connected to the device outputs (Relays). " + + "Using your connected device’s power consumption specification (see associated owner’s manual), set the load in Watts for the outputs bellow:", + name: "Selected Relay 1 Load Power in Watts", paramNum: 12, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + + [name: "Selected Relay 2 Load Power in Watts", paramNum: 13, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + + [name: "Selected Relay 3 Load Power in Watts", paramNum: 14, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + + [name: "Selected Relay 4 Load Power in Watts", paramNum: 15, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + + [name: "Selected Relay 5 Load Power in Watts", paramNum: 16, size: 2, default: 0, type: "number", min: 0, max: 1100, unit: "W"], + + [title: "Air Temperature Calibration", description: "This Parameter defines the offset value for room air temperature. " + + "This value will be added or subtracted from the air temperature sensor reading.Through the Z-Wave network the value of this Parameter should be x10, e.g. for 1.5°C set the value 15.", + name: "Selected Temperature Offset in °Cx10", paramNum: 17, size: 1, default: 0, type: "number", min: -100, max: 100, unit: " °Cx10"], + + [title: "Touch Sensor Sensitivity Threshold", description: "This Parameter allows to adjust the Touch Buttons Sensitivity. " + + "Note: Setting the sensitivity too high can lead to false touch detection. We recommend not changing this Parameter unless there is a special need to do so.", + name: "Selected Touch Sensitivity", options: [ + 1: "Level 1 (Low sensitivity)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (High sensitivity)" + ], paramNum: 6, size: 1, default: "6", type: "enum"], + + [title: "Brightness Control", description: "The HE-TPS05 can adjust its display brightness automatically depending on the illumination of the ambient environment and also allows to control it manually.", + name: "Selected Brightness Level", options: [ + 0: "Auto", + 1: "Level 1 (Lowest)", + 2: "Level 2", + 3: "Level 3", + 4: "Level 4", + 5: "Level 5", + 6: "Level 6", + 7: "Level 7", + 8: "Level 8", + 9: "Level 9", + 10: "Level 10 (Highest)" + ], paramNum: 5, size: 1, default: "0", type: "enum"], + + [title: "Buttons Backlight Color", description: "This parameter defines backlights active state color", + name: "Selected Active State Color", options: [ + 0: "Red", + 1: "Blue" + ], paramNum: 30, size: 1, default: "1", type: "enum"], + + [title: "Buttons Backlight Control Source", description: "This parameter defines the buttons backlight control source", + name: "Backlight 1", options: [ + 0: "Disabled", + 1: "Controlled by Touch Button", + 2: "Controlled by Gateway" + ], paramNum: 31, size: 1, default: "1", type: "enum"], + + [name: "Backlight 2", options: [ + 0: "Disabled", + 1: "Controlled by Touch Button", + 2: "Controlled by Gateway" + ], paramNum: 32, size: 1, default: "1", type: "enum"], + + [name: "Backlight 3", options: [ + 0: "Disabled", + 1: "Controlled by Touch Button", + 2: "Controlled by Gateway" + ], paramNum: 33, size: 1, default: "1", type: "enum"], + + [name: "Backlight 4", options: [ + 0: "Disabled", + 1: "Controlled by Touch Button", + 2: "Controlled by Gateway" + ], paramNum: 34, size: 1, default: "1", type: "enum"], + + [name: "Backlight 5", options: [ + 0: "Disabled", + 1: "Controlled by Touch Button", + 2: "Controlled by Gateway" + ], paramNum: 35, size: 1, default: "1", type: "enum"], + + [title: "Buttons Hold Control Mode", description: "This Parameter defines how the relay should react while holding the corresponding button. The options are: " + + "Hold is disabled, Operate like click, " + + "Momentary Switch: When the button is held, the relay output state is ON, as soon as the button is released the relay output state changes to OFF, " + + "Reversed Momentary: When the button is held, the relay output state is OFF, as soon as the button is released the relay output state changes to ON, " + + "Toggle: When the button is held or released the relay output state will toggle its state (ON to OFF or OFF to ON).", + name: "Selected Hold Control Mode for Button 1", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 41, size: 1, default: "2", type: "enum"], + + [name: "Selected Hold Control Mode for Button 2", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 42, size: 1, default: "2", type: "enum"], + + [name: "Selected Hold Control Mode for Button 3", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 43, size: 1, default: "2", type: "enum"], + + [name: "Selected Hold Control Mode for Button 4", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 44, size: 1, default: "2", type: "enum"], + + [name: "Selected Hold Control Mode for Button 5", options: [ + 0: "Hold is disabled", + 1: "Operate like click", + 2: "Momentary Switch", + 3: "Reversed Momentary", + 4: "Toggle" + ], paramNum: 45, size: 1, default: "2", type: "enum"], + + [title: "Buttons Click Control Mode", description: "These Parameters defines how the relay should react when clicking the corresponding button. The options are: " + + "Click is disabled, Toggle Switch (Relay): relay inverts state (ON to OFF, OFF to ON) according to the relay state, " + + "Toggle Switch (Backlight): relay inverts state (ON to OFF, OFF to ON) according to the button backlight state, " + + "Only On: Relay switches to ON state only, " + + "Only Off: Relay switches to OFF state only, " + + "Timer: On > Off: Relay output switches to ON state (contacts are closed) then after a specified time switches back to OFF state (contacts are open). The time is specified in 'Relay Timer Mode Duration' below, " + + "Timer: Off > On: Relay output switches to OFF state (contacts are open) then after a specified time switches back to On state (contacts are closed). The time is specified in 'Relay Timer Mode Duration' below ", + name: "Selected Click Control Mode for Button 1", options: [ + 0: "Click is disabled", + 1: "Toggle Switch (Relay)", + 2: "Toggle Switch (Backlight)", + 3: "Only On", + 4: "Only Off", + 5: "Timer: On > Off", + 6: "Timer: Off > On" + ], paramNum: 51, size: 1, default: "1", type: "enum"], + + [name: "Selected Click Control Mode for Button 2", options: [ + 0: "Click is disabled", + 1: "Toggle Switch (Relay)", + 2: "Toggle Switch (Backlight)", + 3: "Only On", + 4: "Only Off", + 5: "Timer: On > Off", + 6: "Timer: Off > On" + ], paramNum: 52, size: 1, default: "1", type: "enum"], + + [name: "Selected Click Control Mode for Button 3", options: [ + 0: "Click is disabled", + 1: "Toggle Switch (Relay)", + 2: "Toggle Switch (Backlight)", + 3: "Only On", + 4: "Only Off", + 5: "Timer: On > Off", + 6: "Timer: Off > On" + ], paramNum: 53, size: 1, default: "1", type: "enum"], + + [name: "Selected Click Control Mode for Button 4", options: [ + 0: "Click is disabled", + 1: "Toggle Switch (Relay)", + 2: "Toggle Switch (Backlight)", + 3: "Only On", + 4: "Only Off", + 5: "Timer: On > Off", + 6: "Timer: Off > On" + ], paramNum: 54, size: 1, default: "1", type: "enum"], + + [name: "Selected Click Control Mode for Button 5", options: [ + 0: "Click is disabled", + 1: "Toggle Switch (Relay)", + 2: "Toggle Switch (Backlight)", + 3: "Only On", + 4: "Only Off", + 5: "Timer: On > Off", + 6: "Timer: Off > On" + ], paramNum: 55, size: 1, default: "1", type: "enum"], + + [title: "Button Number for Relays Output Control", description: "This parameter defines the relays control source", + name: "Selected Relay 1 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 61, size: 1, default: "1", type: "enum"], + + [name: "Selected Relay 1 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 61, size: 1, default: "1", type: "enum"], + + [name: "Selected Relay 2 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 62, size: 1, default: "2", type: "enum"], + + [name: "Selected Relay 3 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 63, size: 1, default: "3", type: "enum"], + + [name: "Selected Relay 4 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 64, size: 1, default: "4", type: "enum"], + + [name: "Selected Relay 5 Control Source", options: [ + 0: "Controlled by Gateway", + 1: "Touch Button 1 (Top Left)", + 2: "Touch Button 2 (Top Right)", + 3: "Touch Button 3 (Bottom Left)", + 4: "Touch Button 4 (Bottom Right)", + 5: "Touch Button 5 (Center)" + ], paramNum: 65, size: 1, default: "5", type: "enum"], + + [title: "Relays Timer Mode Duration", description: "These parameters specify the duration in seconds for the Timer modes for Click Control Mode above. " + + "Press the button and the relay output goes to ON/OFF for the specified time then changes back to OFF/ON. " + + "If the value is set to “0” the relay output will operate as a short contact (duration is about 0.5 sec)", + name: "Selected Relay 1 Timer Mode Duration in seconds", paramNum: 71, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + + [name: "Selected Relay 2 Timer Mode Duration in seconds", paramNum: 72, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + + [name: "Selected Relay 3 Timer Mode Duration in seconds", paramNum: 73, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + + [name: "Selected Relay 4 Timer Mode Duration in seconds", paramNum: 74, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + + [name: "Selected Relay 5 Timer Mode Duration in seconds", paramNum: 75, size: 2, default: 0, type: "number", min: 0 , max: 43200, unit: "s"], + + [title: "Retore Relays State", description: "This parameter determines if the last relay state should be restored after power failure or not. " + + "These parameters are available on firmware V2.4 or higher", + name: "Selected Mode for Relay 1", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 66, size: 1, default: "0", type: "enum"], + + [name: "Selected Mode for Relay 2", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 67, size: 1, default: "0", type: "enum"], + + [name: "Selected Mode for Relay 3", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 68, size: 1, default: "0", type: "enum"], + + [name: "Selected Mode for Relay 4", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 69, size: 1, default: "0", type: "enum"], + + [name: "Selected Mode for Relay 5", options: [ + 0: "Relay Off After Power Failure", + 1: "Restore Last State" + ], paramNum: 70, size: 1, default: "0", type: "enum"], + + [title: "Relay Inverse Mode", description: "The values in this Parameter specify the relays that will operate in inverse mode. Relays can operate in an inverse mode in two different ways: " + + "1. When the first and the second relays are connected to two different external switches. In this case, after pressing a button, the corresponding relay connected to that button will toggle its state (ON to OFF or OFF to ON), and the other relay will be switched OFF. " + + "2. When two relays are connected to the same external switch. In this case, the relays will operate in roller shutter mode and their behavior will follow these four cycles: " + + "a - 1st press of button: the first relay will be switched ON, the second relay will be switched OFF, " + + "b - 2nd press of button: both relays will be switched OFF, " + + "c - 3rd press of button: the second relay will be switched ON, the first relay will be switched OFF, " + + "d - 4th press of button: both relays will be switched OFF. " + + "≡ Note: In this mode, both relays cannot be switched ON at the same time (i.e. simultaneously). " + + "≡ Note: Switching OFF one relay will always operate before switching ON another relay to prevent both relays from being ON at the same time.", + name: "Group 1", options: [ + 0: "Disabled", + 12: "1st & 2nd Relay", + 13: "1st & 3rd Relay", + 14: "1st & 4th Relay", + 15: "1st & 5th Relay", + 23: "2nd & 3rd Relay", + 24: "2nd & 4th Relay", + 25: "2nd & 5th Relay", + 34: "3rd & 4th Relay", + 35: "3rd & 5th Relay", + 45: "4th & 5th Relay" + ], paramNum: 101, size: 1, default: "0", type: "enum"], + + [name: "Group 2", options: [ + 0: "Disabled", + 12: "1st & 2nd Relay", + 13: "1st & 3rd Relay", + 14: "1st & 4th Relay", + 15: "1st & 5th Relay", + 23: "2nd & 3rd Relay", + 24: "2nd & 4th Relay", + 25: "2nd & 5th Relay", + 34: "3rd & 4th Relay", + 35: "3rd & 5th Relay", + 45: "4th & 5th Relay" + ], paramNum: 102, size: 1, default: "0", type: "enum"], + + [title: "Energy Consumption Meter Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends reports from its energy consumption sensor even if there is no change in the value. " + + "This parameter defines the interval between consecutive reports of real time and cumulative energy consumption data to the gateway", + name: "Selected Energy Report Interval in minutes", paramNum: 141, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + + [title: "Control Energy Meter Report", description: "This Parameter determines if the change in the energy meter will result in a report being sent to the gateway. " + + "Note: When the device is turning ON, the consumption data will be sent to the gateway once, even if the report is disabled.", + name: "Sending Energy Meter Reports", options: [ + 0: "Disabled", + 1: "Enabled" + ], paramNum: 142, size: 1, default: "1", type: "enum"], + + [title: "Sensors Consecutive Report Interval", description: "When the device is connected to the gateway, it periodically sends to the gateway reports from its external " + + "NTC temperature sensor even if there are not changes in the values. This Parameter defines the interval between consecutive reports", + name: "Selected Energy Report Interval in minutes", paramNum: 143, size: 1, default: 10, type: "number", min: 1 , max: 120, unit: "min"], + + [title: "Air & Floor Temperature Sensors Report Threshold", description: "This Parameter determines the change in temperature level (in °C) resulting in temperature sensors " + + "report being sent to the gateway. The value of this Parameter should be x10 for °C, e.g. for 0.4°C use value 4. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Temperature Threshold in °Cx10", paramNum: 144, size: 1, default: 2, type: "number", min: 0 , max: 100, unit: " °Cx10"], + + [title: "Humidity Sensor Report Threshold", description: "This Parameter determines the change in humidity level in % resulting in humidity sensors " + + "report being sent to the gateway. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Humidity Threshold in %", paramNum: 145, size: 1, default: 2, type: "number", min: 0 , max: 25, unit: "%"], + + [title: "Light Sensor Report Threshold", description: "This Parameter determines the change in the ambient environment illuminance level resulting in a light sensors report " + + "being sent to the gateway. From 10% to 99% can be selected. Use the value 0 if there is a need to stop sending the reports.", + name: "Selected Light Sensor Threshold in %", paramNum: 146, size: 1, default: 50, type: "number", min: 0 , max: 99, unit: "%"] + +]} From 9301f9395ed972efcd1b9c47edb59f36448a35aa Mon Sep 17 00:00:00 2001 From: aguilbault-Sinope <54598043+aguilbault-Sinope@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:04:16 -0400 Subject: [PATCH 146/184] integrate dm2500zb and dm2550zb in the same file (#77964) --- .../dm2500zb-dm2550zb-sinope-dimmer.groovy} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename devicetypes/sinope-technologies/{dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy => dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy} (97%) diff --git a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy b/devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy similarity index 97% rename from devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy rename to devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy index 028431906cb..cf7093a9a7e 100644 --- a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy +++ b/devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy @@ -18,7 +18,7 @@ preferences { } metadata { - definition (name: "DM2500ZB Sinope Dimmer", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch") + definition (name: "DM2500ZB-DM2550ZB Sinope Dimmer", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch") { capability "Actuator" capability "Configuration" @@ -30,6 +30,7 @@ metadata { attribute "swBuild","string"// earliers versions of the DM2500ZB does not support the minimal intensity. theses dimmers can be identified by their swBuild under the value 106 fingerprint manufacturer: "Sinope Technologies", model: "DM2500ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2500ZB + fingerprint manufacturer: "Sinope Technologies", model: "DM2550ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2550ZB } tiles(scale: 2) From 03238c199aecd8b7689a171893ee475e3e880bb6 Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Thu, 17 Mar 2022 09:28:37 +0900 Subject: [PATCH 147/184] Update led-cpx-light.groovy Edited vids. --- .../zigbee-motion-sensor-light.src/led-cpx-light.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy index 5af6d858682..451e1ece4bb 100644 --- a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy @@ -28,10 +28,10 @@ metadata { capability "Switch Level" // ABL Lithonia - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Lithonia", model: "ABL-LIGHTSENSOR-Z-001", deviceJoinName: "CPX Smart Panel Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Lithonia", model: "ABL-LIGHTSENSOR-Z-001", deviceJoinName: "CPX Smart Panel Light", mnmn: "Samsung Electronics", vid: "ABL-LIGHTSENSOR-Z-001" // Samsung LED - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-004", deviceJoinName: "ITM CPX Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-001" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Samsung Electronics", model: "SAMSUNG-ITM-Z-004", deviceJoinName: "ITM CPX Light", mnmn: "Samsung Electronics", vid: "SAMSUNG-ITM-Z-004" } // UI tile definitions From 4a2cd6ad143180dd6d7b884be0d1d7807faadaca Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:49:10 +0800 Subject: [PATCH 148/184] DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch (#77930) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch * Update zigbee-switch.groovy Co-authored-by: 啦啦 王 --- devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 6814c50d000..1b354241f1b 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -105,6 +105,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "1000", manufacturer: "SONOFF", model: "01MINIZB", deviceJoinName: "SONOFF 01MINIZB" //01MINIZB fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, FC57", outClusters: "0019", manufacturer: "SONOFF", model: "S26R2ZB", deviceJoinName: "SONOFF Plug", ocfDeviceType: "oic.d.smartplug" //SONOFF S26R2 Plug fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, FC57", outClusters: "0019", manufacturer: "SONOFF", model: "S40LITE", deviceJoinName: "SONOFF Plug", ocfDeviceType: "oic.d.smartplug" //SONOFF S40Lite Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0020, FC57", outClusters: "0019", manufacturer: "SONOFF", model: "ZBMINI-L", deviceJoinName: "SONOFF Switch" //SONOFF ZBMINI-L // Terncy fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0019", manufacturer: "", model: "TERNCY-LS01", deviceJoinName: "Terncy Switch" //Terncy Smart Light Socket @@ -203,5 +204,3 @@ def configure() { log.debug "Configuring Reporting and Bindings." zigbee.onOffRefresh() + zigbee.onOffConfig() } - - From 80e9a24563017b198ae0f60430452e2475a4423c Mon Sep 17 00:00:00 2001 From: KevinTSH <89558926+KevinTSH@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:34:55 -0400 Subject: [PATCH 149/184] DevWs for Zooz (The Smartest House) containing containing Zooz ZEN32 Scene Controller (#77946) * DevWs for Zooz (The Smartest House) containing containing Zooz ZEN32 Scene Controller * Zooz ZEN32 Scene Controller * Zooz ZEN32 Scene Controller --- .../zooz-zen32-scene-controller-button.groovy | 91 ++++ .../zooz-zen32-scene-controller.groovy | 457 ++++++++++++++++++ 2 files changed, 548 insertions(+) create mode 100644 devicetypes/zooz/zooz-zen32-scene-controller-button.src/zooz-zen32-scene-controller-button.groovy create mode 100644 devicetypes/zooz/zooz-zen32-scene-controller.src/zooz-zen32-scene-controller.groovy diff --git a/devicetypes/zooz/zooz-zen32-scene-controller-button.src/zooz-zen32-scene-controller-button.groovy b/devicetypes/zooz/zooz-zen32-scene-controller-button.src/zooz-zen32-scene-controller-button.groovy new file mode 100644 index 00000000000..660cb0d2e61 --- /dev/null +++ b/devicetypes/zooz/zooz-zen32-scene-controller-button.src/zooz-zen32-scene-controller-button.groovy @@ -0,0 +1,91 @@ +/* +* Zooz ZEN32 Scene Controller Button +* +* Changelog: +* +* 2022-03-17 +* - Requested changes +* 2022-02-27 +* - Publication Release +* +* Copyright 2022 Zooz +* +* 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: "Zooz ZEN32 Scene Controller Button", + namespace: "Zooz", + author: "Kevin LaFramboise (krlaframboise)", + ocfDeviceType: "x.com.st.d.remotecontroller", + mnmn: "SmartThingsCommunity", + vid: "63601248-c681-3458-b5d6-ab1f482b2d71" + ) { + capability "Sensor" + capability "Button" + capability "Refresh" + capability "platemusic11009.zoozLedColor" + capability "platemusic11009.zoozLedBrightness" + capability "platemusic11009.zoozLedMode" + } + + preferences() {} +} + +def parse(String description) { + log.debug "parse(${description})..." + return [] +} + +def installed() { + log.debug "installed()..." + initialize() +} + +def updated() { + log.debug "updated().." + initialize() +} + +void initialize() { + if (!device.currentValue("numberOfButtons")) { + sendEvent(name: "numberOfButtons", value: 1) + sendEvent(name: "supportedButtonValues", value: ["pushed", "held", "pushed_2x", "pushed_3x", "pushed_4x", "pushed_5x"].encodeAsJSON()) + sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1]) + sendEvent(name: "ledMode", value: "onWhenOff") + sendEvent(name: "ledBrightness", value: "medium") + sendEvent(name: "ledColor", value: "white") + } +} + +def refresh() { + log.debug "refresh()..." + parent.childRefresh(device.deviceNetworkId) +} + +def setLedMode(mode) { + log.debug "setLedMode(${mode})..." + parent.childSetLedMode(device.deviceNetworkId, mode) +} + +def setLedColor(color) { + log.debug "setLedColor(${color})..." + parent.childSetLedColor(device.deviceNetworkId, color) +} + +def setLedBrightness(brightness) { + log.debug "setLedBrightness(${brightness})..." + parent.childSetLedBrightness(device.deviceNetworkId, brightness) +} \ No newline at end of file diff --git a/devicetypes/zooz/zooz-zen32-scene-controller.src/zooz-zen32-scene-controller.groovy b/devicetypes/zooz/zooz-zen32-scene-controller.src/zooz-zen32-scene-controller.groovy new file mode 100644 index 00000000000..3317d20a50e --- /dev/null +++ b/devicetypes/zooz/zooz-zen32-scene-controller.src/zooz-zen32-scene-controller.groovy @@ -0,0 +1,457 @@ +/* +* Zooz ZEN32 Scene Controller +* +* Changelog: +* +* 2022-03-17 +* - Requested changes +* 2022-02-27 +* - Publication Release +* +* Copyright 2022 Zooz +* +* 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 groovy.transform.Field + +@Field static Map commandClassVersions = [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x55: 1, // Transport Service + 0x59: 1, // AssociationGrpInfo + 0x5A: 1, // DeviceResetLocally + 0x5B: 1, // CentralScene (3) + 0x5E: 2, // ZwaveplusInfo + 0x6C: 1, // Supervision + 0x70: 1, // Configuration + 0x7A: 2, // FirmwareUpdateMd + 0x72: 2, // ManufacturerSpecific + 0x73: 1, // Powerlevel + 0x85: 2, // Association + 0x86: 1, // Version (2) + 0x87: 1, // Indicator + 0x8E: 2, // Multi Channel Association + 0x98: 1, // Security S0 + 0x9F: 1 // Security S2 +] + +@Field static Map configParams = [ + autoOffTimer: [num:16, title:"Auto Turn-Off Timer (Minutes)", size:4, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(minutes)"], + autoOnTimer: [num:17, title:"Auto Turn-On Timer (Minutes)", size:4, defaultVal:0, range:"0..65535", desc:"0(disabled), 1..65535(minutes)"], + statusAfterPowerFailure: [num:18, title:"On Off Status After Power Failure", defaultVal:0, options:[0:"Restore previous state", 1:"Forced off", 2:"Forced on"]], + relayLoadControl: [num:19, title:"Relay Load Control", defaultVal:1, options:[1:"Enable Switch and Z-Wave", 0:"Disable Switch/ Enable Z-Wave", 2:"Disable Switch and Z-Wave"]], + disabledRelayBehavior: [num:20, title:"Disabled Relay Load Control Behavior", defaultVal:0, options:[0:"Reports Status / Changes LED", 1:"Doesn't Report Status / Change LED"]], + threeWaySwitchType: [num:21, title:"3-Way Switch Type", defaultVal:0, options:[0:"Toggle On/Off Switch", 1:"Momentary Switch (ZAC99)"]] +] + +@Field static List buttons = [ + [btnNum: 1, params:[ledMode:[num:2], ledColor:[num:7], ledBrightness:[num:12]]], + [btnNum: 2, params:[ledMode:[num:3], ledColor:[num:8], ledBrightness:[num:13]]], + [btnNum: 3, params:[ledMode:[num:4], ledColor:[num:9], ledBrightness:[num:14]]], + [btnNum: 4, params:[ledMode:[num:5], ledColor:[num:10], ledBrightness:[num:15]]], + [btnNum: 5, params:[ledMode:[num:1], ledColor:[num:6], ledBrightness:[num:11]]] +] + +@Field static Map ledParamOptions = [ + ledMode:[0:"onWhenOff", 1:"onWhenOn", 2:"alwaysOff", 3:"alwaysOn"], + ledColor:[0:"white", 1:"blue", 2:"green", 3:"red"], + ledBrightness:[0:"bright", 1:"medium", 2:"low"] +] + +@Field static int btnPushed = 0 +@Field static int btnReleased = 1 +@Field static int btnHeld = 2 + +metadata { + definition ( + name: "Zooz ZEN32 Scene Controller", + namespace: "Zooz", + author: "Kevin LaFramboise (@krlaframboise)", + ocfDeviceType: "oic.d.switch", + mnmn: "SmartThingsCommunity", + vid: "a0e5a3b8-4dc2-3616-87d1-58a520a2dc52" + ) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Light" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "Button" + capability "platemusic11009.firmware" + + // zw:Ls2a type:1000 mfr:027A prod:7000 model:A008 ver:1.01 zwv:7.13 lib:03 cc:5E,55,9F,6C sec:86,25,70,20,5B,85,8E,59,72,5A,73,87,7A + fingerprint mfr:"027A", prod:"7000", model: "A008", deviceJoinName:"Zooz Switch" // Zooz ZEN32 Scene Controller + } + + preferences { + configParams.each { name, param -> + if (param.options) { + input name, "enum", + title: param.title, + description: "Default: ${param.options[param.defaultVal]}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + options: param.options + } else if (param.range) { + input name, "number", + title: param.title, + description: "${param.desc} - Default: ${param.defaultVal}", + required: false, + displayDuringSetup: false, + defaultValue: param.defaultVal, + range: param.range + } + } + } +} + +def installed() { + log.debug "installed()..." + initialize() + state.firstRun = true +} + +def updated() { + log.debug "updated()..." + initialize() + + if (!state.firstRun) { + executeConfigure() + } else { + state.firstRun = false + } +} + +void initialize() { + if (!device.currentValue("checkInterval")) { + sendEvent([name: "checkInterval", value: ((60 * 60 * 3) + (5 * 60)), displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]]) + } + + buttons.each { btn -> + if (!findChildByButton(btn)) { + addChildButton(btn) + } + } +} + +void addChildButton(Map btn) { + log.debug "Creating Button ${btn.btnNum}" + try { + addChildDevice( + "Zooz", + "Zooz ZEN32 Scene Controller Button", + "${device.deviceNetworkId}:${btn.btnNum}", + device.getHub().getId(), + [ + completedSetup: true, + label: "Zooz Button ${btn.btnNum}", + isComponent: false + ] + ) + } catch(Exception e) { + log.warn "${e}" + } +} + +void executeConfigure() { + List cmds = [] + + if (!device.currentValue("switch")) { + cmds << switchBinaryGetCmd() + } + + if (!device.currentValue("firmwareVersion")) { + cmds << versionGetCmd() + } + + configParams.each { name, param -> + Integer storedVal = getStoredVal(name) + Integer settingVal = getSettingVal(name) + if ((storedVal == null) || (storedVal != settingVal)) { + if (settingVal != null) { + log.debug "Changing ${param.title}(#${param.num}) from ${storedVal} to ${settingVal}" + cmds << configSetCmd(param, settingVal) + } + cmds << configGetCmd(param) + } + } + + if (cmds) { + sendHubCommand(cmds, 100) + } +} + +Integer getSettingVal(String name) { + Integer value = safeToInt(settings[name], null) + if ((value == null) && (getStoredVal(name) != null)) { + return configParams[name].defaultVal + } else { + return value + } +} + +Integer getStoredVal(String name) { + return safeToInt(state[name], null) +} + +def ping() { + log.debug "ping()..." + return [ switchBinaryGetCmd() ] +} + +def on() { + log.debug "on()..." + return [ switchBinarySetCmd(0xFF) ] +} + +def off() { + log.debug "off()..." + return [ switchBinarySetCmd(0x00) ] +} + +def refresh() { + log.debug "refresh()..." + List cmds = [ + switchBinaryGetCmd(), + versionGetCmd() + ] + + buttons.each { btn -> + btn.params.each { name, param -> + cmds << configGetCmd(param) + } + } + sendHubCommand(cmds) +} + +void childRefresh(String dni) { + log.debug "childRefresh(${dni})..." + Map btn = findButtonByDNI(dni) + if (btn) { + List cmds = [] + btn.params.each { name, param -> + cmds << configGetCmd(param) + } + sendHubCommand(cmds) + } +} + +void childSetLedMode(String dni, String mode) { + log.debug "childSetLedMode(${dni}, ${mode})..." + Map btn = findButtonByDNI(dni) + if (btn) { + mode = mode?.toLowerCase()?.trim() + Integer value = ledParamOptions.ledMode.find { it.value.toLowerCase() == mode }?.key + + if (value != null) { + sendConfigCmds(btn.params.ledMode, value) + } else { + log.warn "${mode} is not a valid LED Mode" + } + } +} + +void childSetLedColor(String dni, String color) { + log.debug "childSetLedColor(${dni}, ${color})..." + Map btn = findButtonByDNI(dni) + if (btn) { + color = color?.toLowerCase()?.trim() + Integer value = ledParamOptions.ledColor.find { it.value.toLowerCase() == color }?.key + + if (value != null) { + sendConfigCmds(btn.params.ledColor, value) + } else { + log.warn "${color} is not a valid LED Color" + } + } +} + +void childSetLedBrightness(String dni, String brightness) { + log.debug "childSetLedBrightness(${dni}, ${brightness})..." + Map btn = findButtonByDNI(dni) + if (btn) { + brightness = brightness?.toLowerCase()?.trim() + Integer value = ledParamOptions.ledBrightness.find { it.value == brightness }?.key + + if (value != null) { + sendConfigCmds(btn.params.ledBrightness, value) + } else { + log.warn "${brightness} is not a valid LED Brightness" + } + } +} + +void sendConfigCmds(Map param, int value) { + sendHubCommand([ + configSetCmd(param, value), + configGetCmd(param) + ]) +} + +String versionGetCmd() { + return secureCmd(zwave.versionV1.versionGet()) +} + +String switchBinaryGetCmd() { + return secureCmd(zwave.switchBinaryV1.switchBinaryGet()) +} + +String switchBinarySetCmd(val) { + return secureCmd(zwave.switchBinaryV1.switchBinarySet(switchValue: val)) +} + +String configSetCmd(Map param, int value) { + int size = (param.size ?: 1) + return secureCmd(zwave.configurationV1.configurationSet(parameterNumber: param.num, size: size, scaledConfigurationValue: value)) +} + +String configGetCmd(Map param) { + return secureCmd(zwave.configurationV1.configurationGet(parameterNumber: param.num)) +} + +String secureCmd(cmd) { + if (zwaveInfo?.zw?.contains("s")) { + return zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + return cmd.format() + } +} + +def parse(String description) { + def cmd = zwave.parse(description, commandClassVersions) + if (cmd) { + zwaveEvent(cmd) + } else { + log.warn "Unable to parse: $description" + } + return [] +} + +void zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCmd) { + zwaveEvent(encapsulatedCmd) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + } +} + +void zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + int value = cmd.scaledConfigurationValue + String name = configParams.find { name, param -> param.num == cmd.parameterNumber }?.key + if (name) { + state[name] = value + log.debug "${configParams[name]?.title}(#${configParams[name]?.num}) = ${value}" + } else { + handleLedEvent(cmd.parameterNumber, value) + } +} + +void handleLedEvent(int paramNum, int configVal) { + buttons.each { btn -> + String name = btn.params.find { it.value.num == paramNum}?.key + if (name) { + String value = ledParamOptions[name].get(configVal) + if (value) { + log.debug "Button ${btn.btnNum} ${name} is ${value}" + findChildByButton(btn)?.sendEvent(name: name, value: value) + } + } + } +} + +void zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { + log.debug "${cmd}" + sendEvent(name: "firmwareVersion", value: (cmd.applicationVersion + (cmd.applicationSubVersion / 100))) +} + +void zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + sendSwitchEvent(cmd.value) +} + +void zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { + sendSwitchEvent(cmd.value) +} + +void sendSwitchEvent(rawVal) { + String value = (rawVal ? "on" : "off") + log.debug "switch is ${value}" + sendEvent(name: "switch", value: value) +} + +void zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd){ + if (state.lastSequenceNumber != cmd.sequenceNumber) { + state.lastSequenceNumber = cmd.sequenceNumber + + Map btn = findButtonByNum(cmd.sceneNumber) + if (btn) { + String value + switch (cmd.keyAttributes){ + case btnPushed: + value = "pushed" + break + case btnReleased: + log.debug "Button Value 'released' is not supported by SmartThings" + break + case btnHeld: + value = "held" + break + default: + value = "pushed_${cmd.keyAttributes - 1}x" + } + + if (value) { + log.debug "button ${btn.btnNum} ${value}" + findChildByButton(btn)?.sendEvent(name: "button", value: value, data:[buttonNumber: 1], isStateChange: true) + } + } else { + log.debug "Scene ${cmd.sceneNumber} is not a valid Button Number" + } + } +} + +void zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Unhandled zwaveEvent: $cmd" +} + +def findChildByButton(Map btn) { + return childDevices?.find { btn == findButtonByDNI(it.deviceNetworkId) } +} + +Map findButtonByDNI(String dni) { + Integer btnNum = safeToInt("${dni}".reverse().take(1), null) + if (btnNum) { + return findButtonByNum(btnNum) + } else { + log.warn "${dni} is not a valid Button DNI" + } +} + +Map findButtonByNum(Integer btnNum) { + return buttons.find { it.btnNum == btnNum } +} + +Integer safeToInt(val, Integer defaultVal=0) { + if ("${val}"?.isInteger()) { + return "${val}".toInteger() + } else if ("${val}".isDouble()) { + return "${val}".toDouble()?.round() + } else { + return defaultVal + } +} \ No newline at end of file From c69e449a51b41f53144a389c49ddd2c768f2dfc5 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Mon, 21 Mar 2022 16:31:46 +0800 Subject: [PATCH 150/184] DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Switch Generic (#77973) * DevWs for NIE-TECH CO., LTD. containing containing Z-Wave Switch Generic * Add a new product for Minoston Mini Outdoor Smart Plug * The deleted code is repeated with line 57:the fingerprint was added long long ago but the product is not managed by developer workspace. Co-authored-by: Winnie Wen --- .../zwave-switch-generic.src/zwave-switch-generic.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c9727f3a775..e109fb88f56 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -59,7 +59,7 @@ metadata { fingerprint mfr: "0312", prod: "FF00", model: "FF01", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Minoston on/off Toggle Switch fingerprint mfr: "0312", prod: "C000", model: "C003", deviceJoinName: "Evalogik Outlet", ocfDeviceType: "oic.d.smartplug" //Evalogik Outdoor Smart Plug fingerprint mfr: "0312", prod: "FF00", model: "FF03", deviceJoinName: "Minoston Switch" //Minoston Smart On/Off Switch - fingerprint mfr: "0312", prod: "C000", model: "CO05", deviceJoinName: "Evalogik Outlet", ocfDeviceType: "oic.d.smartplug" //Evalogik Mini Outdoor Smart Plug + fingerprint mfr: "0312", prod: "C000", model: "C005", deviceJoinName: "Evalogik Outlet", ocfDeviceType: "oic.d.smartplug" //Evalogik Mini Outdoor Smart Plug fingerprint mfr: "031E", prod: "0004", model: "0001", deviceJoinName: "Inovelli Switch" //Inovelli Switch fingerprint mfr: "001D", prod: "0037", model: "0002", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Tamper Resistant Outlet ZW15R fingerprint mfr: "0371", prod: "0103", model: "0026", deviceJoinName: "Aeotec Wall Switch" //Aeotec illumino Wall Switch From 3b46e8cde5ab7ca4d52b2498c33fab734124b016 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Wed, 23 Mar 2022 01:25:42 +0800 Subject: [PATCH 151/184] Update zigbee-window-shade.groovy (#77868) * Update zigbee-window-shade.groovy add third reality smart blind * update zigbee-window-shade.groovy update zigbee-window-shade.groovy --- .../zigbee-window-shade.groovy | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) 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 e580330b3fc..4fc994cb38e 100644 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -40,6 +40,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "SOMFY", model: "Glydea Ultra Curtain", deviceJoinName: "Somfy Window Treatment" //Somfy Glydea Ultra fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0020, 0102", outClusters: "0003", manufacturer: "SOMFY", model: "Sonesse 30 WF Roller", deviceJoinName: "Somfy Window Treatment" // Somfy Sonesse 30 Zigbee LI-ION Pack fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0020, 0102", outClusters: "0003", manufacturer: "SOMFY", model: "Sonesse 40 Roller", deviceJoinName: "Somfy Window Treatment" // Somfy Sonesse 40 + fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSB015BZ", deviceJoinName: "ThirdReality smart Blind" // ThirdReality } preferences { @@ -148,7 +149,11 @@ def levelEventHandler(currentLevel) { sendEvent(name: "level", value: currentLevel, unit: "%", displayed: false) if (currentLevel == 0 || currentLevel == 100) { - sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") + if (device.getDataValue("manufacturer") == "Third Reality, Inc"){ + sendEvent(name: "windowShade", value: currentLevel == 0 ? "open" : "closed") + } else { + sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") + } } else { if (priorLevel < currentLevel) { sendEvent([name:"windowShade", value: "opening"]) @@ -217,10 +222,14 @@ def pause() { log.info "pause()" def currentShadeStatus = device.currentValue("windowShade") - if (currentShadeStatus == "open" || currentShadeStatus == "closed") { - sendEvent(name: "windowShade", value: currentShadeStatus) + if (device.getDataValue("manufacturer") == "Third Reality, Inc") { + zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) } else { - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) + if (currentShadeStatus == "open" || currentShadeStatus == "closed") { + sendEvent(name: "windowShade", value: currentShadeStatus) + } else { + zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) + } } } @@ -309,4 +318,4 @@ def isSomfy() { device.getDataValue("manufacturer") == "SOMFY" } -private getGLYDEA_MOVE_THRESHOLD() { 3 } \ No newline at end of file +private getGLYDEA_MOVE_THRESHOLD() { 3 } From 1ecb021216bd3372f5bb5420210b8efe3b88ba6a Mon Sep 17 00:00:00 2001 From: Aeotec-ccheng <63321041+Aeotec-ccheng@users.noreply.github.com> Date: Thu, 24 Mar 2022 02:27:06 -0700 Subject: [PATCH 152/184] DevWs for Aeotec Group GmbH containing containing Z-Wave Switch Generic (#77999) * DevWs for Aeotec Group GmbH containing containing Z-Wave Switch Generic * Fixed line 62 Co-authored-by: Christopher Cheng --- .../zwave-switch-generic.src/zwave-switch-generic.groovy | 3 +++ 1 file changed, 3 insertions(+) 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 e109fb88f56..4226bac8b81 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -63,6 +63,9 @@ metadata { fingerprint mfr: "031E", prod: "0004", model: "0001", deviceJoinName: "Inovelli Switch" //Inovelli Switch fingerprint mfr: "001D", prod: "0037", model: "0002", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Tamper Resistant Outlet ZW15R fingerprint mfr: "0371", prod: "0103", model: "0026", deviceJoinName: "Aeotec Wall Switch" //Aeotec illumino Wall Switch + fingerprint mfr: "0371", prod: "0003", model: "002A", deviceJoinName: "Aeotec Switch" //Aeotec Outdoor Smart Plug EU + fingerprint mfr: "0371", prod: "0103", model: "002A", deviceJoinName: "Aeotec Switch" //Aeotec Outdoor Smart Plug US + fingerprint mfr: "0371", prod: "0203", model: "002A", deviceJoinName: "Aeotec Switch" //Aeotec Outdoor Smart Plug AU } // simulator metadata From f75fe15e90fd945793d66b79322bf4c7c62da5c4 Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Mon, 28 Mar 2022 17:00:25 +0900 Subject: [PATCH 153/184] Update led-cpx-light.groovy Added a light type capability in the code. --- .../zigbee-motion-sensor-light.src/led-cpx-light.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy index 451e1ece4bb..cda93258309 100644 --- a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy @@ -26,6 +26,7 @@ metadata { capability "Refresh" capability "Switch" capability "Switch Level" + capability "Light" // ABL Lithonia fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0406", outClusters: "0019", manufacturer: "Lithonia", model: "ABL-LIGHTSENSOR-Z-001", deviceJoinName: "CPX Smart Panel Light", mnmn: "Samsung Electronics", vid: "ABL-LIGHTSENSOR-Z-001" From d340b1ba7be82e71566dfde1cc170551e689f624 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Tue, 29 Mar 2022 05:25:31 +0800 Subject: [PATCH 154/184] update smartsense-temp-humodity-sensor.groovy (#78003) * update smartsense-temp-humodity-sensor.groovy update smartsense-temp-humodity-sensor.groovy * update smartsense-temp-humidity-sensor.groovy update smartsense-temp-humidity-sensor.groovy * update update --- .../smartsense-temp-humidity-sensor.groovy | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index 543d629fc53..af41fd23c1a 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -38,6 +38,9 @@ metadata { //eWeLink fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0402, 0405", outClusters: "0003", manufacturer: "eWeLink", model: "TH01", deviceJoinName: "eWeLink Multipurpose Sensor" fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0020, 0402, 0405, FC57", outClusters: "0003, 0019", manufacturer: "eWeLink", model: "SNZB-02P", deviceJoinName: "eWeLink Multipurpose Sensor" + + //Third Reality + fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0402,0405", outClusters: "0019", manufacturer:"Third Reality, Inc", model:"3RTS20BZ", deviceJoinName: "ThirdReality Thermal & Humidity Sensor" } simulator { @@ -174,7 +177,7 @@ def refresh() { return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, [destEndpoint: 0x01])+ zigbee.readAttribute(0x0402, 0x0000, [destEndpoint: 0x01])+ zigbee.readAttribute(0x0405, 0x0000, [destEndpoint: 0x02]) - } else if (isFrientSensor()) { + } else if (isFrientSensor() || isThirdReality()) { return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)+ zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000)+ zigbee.readAttribute(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000) @@ -205,7 +208,7 @@ def configure() { zigbee.temperatureConfig(30, 300) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10) + zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 30, 3600, 100, [destEndpoint: 0x02]) - } else if (isFrientSensor()) { + } else if (isFrientSensor() || isThirdReality()) { return refresh() + zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000, DataType.UINT16, 60, 600, 1*100) + zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 60, 600, 0xA) + @@ -231,3 +234,7 @@ private Boolean isFrientSensor() { private Boolean isEWeLink() { device.getDataValue("manufacturer") == "eWeLink" } + +private Boolean isThirdReality() { + device.getDataValue("manufacturer") == "Third Reality, Inc" +} From ad257ff39bb835e4699e666317de567fe62521a2 Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 29 Mar 2022 11:19:39 -0700 Subject: [PATCH 155/184] Revert "integrate dm2500zb and dm2550zb in the same file (#77964)" This reverts commit 9301f9395ed972efcd1b9c47edb59f36448a35aa. --- .../dm2500zb-sinope-dimmer.groovy} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename devicetypes/sinope-technologies/{dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy => dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy} (97%) diff --git a/devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy similarity index 97% rename from devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy rename to devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy index cf7093a9a7e..028431906cb 100644 --- a/devicetypes/sinope-technologies/dm2500zb-dm2550zb-sinope-dimmer.src/dm2500zb-dm2550zb-sinope-dimmer.groovy +++ b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy @@ -18,7 +18,7 @@ preferences { } metadata { - definition (name: "DM2500ZB-DM2550ZB Sinope Dimmer", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch") + definition (name: "DM2500ZB Sinope Dimmer", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch") { capability "Actuator" capability "Configuration" @@ -30,7 +30,6 @@ metadata { attribute "swBuild","string"// earliers versions of the DM2500ZB does not support the minimal intensity. theses dimmers can be identified by their swBuild under the value 106 fingerprint manufacturer: "Sinope Technologies", model: "DM2500ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2500ZB - fingerprint manufacturer: "Sinope Technologies", model: "DM2550ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2550ZB } tiles(scale: 2) From 06c6546f0aac4856b5cf00e377a541ed98829ca5 Mon Sep 17 00:00:00 2001 From: greens Date: Tue, 29 Mar 2022 11:20:55 -0700 Subject: [PATCH 156/184] Add DM2550ZB fingerprint --- .../dm2500zb-sinope-dimmer.groovy | 225 +++++++++--------- 1 file changed, 113 insertions(+), 112 deletions(-) diff --git a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy index 028431906cb..a412eeec34e 100644 --- a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy +++ b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy @@ -3,18 +3,18 @@ Copyright Sinopé Technologies 1.3.0 SVN-571 * 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. + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. **/ preferences { - input("MinimalIntensityParam", "number", title:"Light bulb minimal intensity (1..10) (default: blank)", range:"1..10", description:"optional") + input("MinimalIntensityParam", "number", title:"Light bulb minimal intensity (1..10) (default: blank)", range:"1..10", description:"optional") // when the is at a low value, some bulbs may flicker for some technical reasons. to prevent that behaviour. writting this parameter will increase the minimal value // of the dimmer's become a little bit higher so the load doesn't start flickering when the level is low. input("LedIntensityParam", "number", title:"Indicator light intensity (1..100) (default: blank)", range:"1..100", description:"optional") - input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - // input("logFilter", "number", title: "Trace level", range: "1..5", - // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } metadata { @@ -26,13 +26,14 @@ metadata { capability "Switch" capability "Switch Level" capability "Health Check" - + attribute "swBuild","string"// earliers versions of the DM2500ZB does not support the minimal intensity. theses dimmers can be identified by their swBuild under the value 106 - + fingerprint manufacturer: "Sinope Technologies", model: "DM2500ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2500ZB + fingerprint manufacturer: "Sinope Technologies", model: "DM2550ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2550ZB } - tiles(scale: 2) + tiles(scale: 2) { multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { @@ -43,13 +44,13 @@ metadata { attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" } - tileAttribute ("device.level", key: "SLIDER_CONTROL") + tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" } } - standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" } @@ -63,26 +64,26 @@ def parse(String description) traceEvent(settings.logFilter, "description is $description", settings.trace, get_LOG_DEBUG()) def event = zigbee.getEvent(description) traceEvent(settings.logFilter, "Event = $event", settings.trace, get_LOG_DEBUG()) - + if(event) { if (event.name=="level" && event.value==0) {} - else { + else { traceEvent(settings.logFilter, "send event : $event", settings.trace, get_LOG_DEBUG()) - sendEvent(event) + sendEvent(event) sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - } + } } else { traceEvent(settings.logFilter, "DID NOT PARSE MESSAGE for description", settings.trace, get_LOG_WARN()) - if (description?.startsWith("read attr -")) + if (description?.startsWith("read attr -")) { def descMap = zigbee.parseDescriptionAsMap(description) def result = [] result += createCustomMap(descMap) - // In the possibility of multiple attributes being reported in the same message, all the attributes will be in the same description. the first attribute will be in the fields regularly used, + // In the possibility of multiple attributes being reported in the same message, all the attributes will be in the same description. the first attribute will be in the fields regularly used, // but the otter attributes will be in the "additionalAttrs". they should all be treated in the following part. if(descMap.additionalAttrs) { @@ -104,18 +105,18 @@ def parse(String description) private def parseDescriptionAsMap(description) { traceEvent(settings.logFilter, "parsing MAP ...", settings.trace, get_LOG_DEBUG()) - (description - "read attr - ").split(",").inject([:]) + (description - "read attr - ").split(",").inject([:]) { - map, param -> - def nameAndValue = param.split(":") - map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] - } + map, param -> + def nameAndValue = param.split(":") + map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] + } } private def createCustomMap(descMap) { def result = null - def map = [:] + def map = [:] if(descMap.cluster == "0000" && descMap.attrId == "0001") { @@ -128,11 +129,11 @@ private def createCustomMap(descMap) } def updated() { - - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 2000) + + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 2000) { - state.updatedLastRanAt = now() - + state.updatedLastRanAt = now() + def cmds = [] if(checkSoftVersion() == true) { @@ -140,7 +141,7 @@ def updated() { def Time = getTiming(MinLight) traceEvent(settings.logFilter, "Set timing to: $Time", settings.trace, get_LOG_DEBUG()) cmds += zigbee.writeAttribute(0xff01, 0x0055, 0x21, Time) - + } else { @@ -157,11 +158,11 @@ def updated() { } sendZigbeeCommands(cmds) - } - else { + } + else { traceEvent(settings.logFilter, "updated(): Ran within last 2 seconds so aborting", settings.trace, get_LOG_TRACE()) - } - + } + } def off() @@ -174,7 +175,7 @@ def on() zigbee.on() } -def setLevel(level) +def setLevel(level) { traceEvent(settings.logFilter, "setLevel value = $level", settings.trace, get_LOG_DEBUG()) zigbee.setLevel(level,0) @@ -184,19 +185,19 @@ def setLevel(level) * PING is used by Device-Watch in attempt to reach the Device * */ def ping() { - return zigbee.onOffRefresh() + return zigbee.onOffRefresh() } def refresh() { - def cmds = [] + def cmds = [] cmds += zigbee.readAttribute(0x0006, 0x0000) //read on/off cmds += zigbee.readAttribute(0x0008, 0x0000) //read level cmds += zigbee.readAttribute(0x0000, 0x0001) //read software version cmds += zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 599, null) //configure reporting on/off cmds += zigbee.configureReporting(0x0008, 0x0000, 0x20, 3, 602, 0x01) //configure reporting level if(checkSoftVersion() == true){//if the minimal intensity is supported - cmds += zigbee.writeAttribute(0xff01, 0x0055, 0x21, getTiming((MinimalIntensityParam)?MinimalIntensityParam.toInteger():0)) + cmds += zigbee.writeAttribute(0xff01, 0x0055, 0x21, getTiming((MinimalIntensityParam)?MinimalIntensityParam.toInteger():0)) } return sendZigbeeCommands(cmds) } @@ -206,14 +207,14 @@ def configure() traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) //allow 30 minutes without reveiving any on/off report - sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) return zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 599, null) + //configure reporting on/off zigbee.configureReporting(0x0008, 0x0000, 0x20, 3, 602, 0x01) + //configure reporting level zigbee.readAttribute(0x0006, 0x0000) + //read on/off zigbee.readAttribute(0x0008, 0x0000) + //read level zigbee.readAttribute(0x0000, 0x0001) //read software version - + } //-- Check Settings --------------------------------------------------------------------------------------- @@ -221,57 +222,57 @@ def configure() private int getTiming(def setting) {//getTiming is used to get the minimal time associated with the parameter "minimalIntensityParam" - def Timing - switch(setting) - { - case(1): - Timing = 100 - break; - case(2): - Timing = 250 - break; - case(3): - Timing = 500 - break; - case(4): - Timing = 750 - break; - case(5): - Timing = 1000 - break; - case(6): - Timing = 1250 - break; - case(7): - Timing = 1500 - break; - case(8): - Timing = 1750 - break; - case(9): - Timing = 2000 - break; - case(10): - Timing = 2250 - break; - default: - Timing = 600 - break; - } + def Timing + switch(setting) + { + case(1): + Timing = 100 + break; + case(2): + Timing = 250 + break; + case(3): + Timing = 500 + break; + case(4): + Timing = 750 + break; + case(5): + Timing = 1000 + break; + case(6): + Timing = 1250 + break; + case(7): + Timing = 1500 + break; + case(8): + Timing = 1750 + break; + case(9): + Timing = 2000 + break; + case(10): + Timing = 2250 + break; + default: + Timing = 600 + break; + } return Timing } private boolean checkSoftVersion() { - def version + def version def versionMin = "106" //the first version to support the minimal intensity is the version 106 def Build = device.currentState("swBuild")?.value traceEvent(settings.logFilter, "soft version: $Build", settings.trace, get_LOG_DEBUG()) - + if(Build > versionMin)//if the version is under 107, the minimal light intensity is not supported. { traceEvent(settings.logFilter, "intensity supported", settings.trace, get_LOG_DEBUG()) - version = true + version = true } else { @@ -283,54 +284,54 @@ private boolean checkSoftVersion() private void sendZigbeeCommands(cmds, delay = 1000) { - cmds.removeAll { it.startsWith("delay") } - // convert each command into a HubAction - cmds = cmds.collect { new physicalgraph.device.HubAction(it) } - sendHubCommand(cmds, delay) + cmds.removeAll { it.startsWith("delay") } + // convert each command into a HubAction + cmds = cmds.collect { new physicalgraph.device.HubAction(it) } + sendHubCommand(cmds, delay) } private int get_LOG_ERROR() { - return 1 + return 1 } private int get_LOG_WARN() { - return 2 + return 2 } private int get_LOG_INFO() { - return 3 + return 3 } private int get_LOG_DEBUG() { - return 4 + return 4 } private int get_LOG_TRACE() { - return 5 + return 5 } def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMessage = true) { - int LOG_ERROR = get_LOG_ERROR() - int LOG_WARN = get_LOG_WARN() - int LOG_INFO = get_LOG_INFO() - int LOG_DEBUG = get_LOG_DEBUG() - int LOG_TRACE = get_LOG_TRACE() - - if (displayEvent || traceLevel < 4) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } - } + int LOG_ERROR = get_LOG_ERROR() + int LOG_WARN = get_LOG_WARN() + int LOG_INFO = get_LOG_INFO() + int LOG_DEBUG = get_LOG_DEBUG() + int LOG_TRACE = get_LOG_TRACE() + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } + } } \ No newline at end of file From 2b20026fa18e130747836db65dcccf87b970c099 Mon Sep 17 00:00:00 2001 From: RaihaPark <74279632+RaihaPark@users.noreply.github.com> Date: Fri, 1 Apr 2022 12:15:30 +0900 Subject: [PATCH 157/184] Added a health check code By the reason for WWST certification failed, I added a health check code in the configure function. --- .../zigbee-motion-sensor-light.src/led-cpx-light.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy index cda93258309..da18e3d7ac6 100644 --- a/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy +++ b/devicetypes/smartthings/zigbee-motion-sensor-light.src/led-cpx-light.groovy @@ -113,6 +113,8 @@ def setLevel(value, rate=null) { } def configure() { + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + zigbee.configureReporting(MOTION_CLUSTER, MOTION_STATUS_ATTRIBUTE, 0x18, 30, 600, null) + zigbee.onOffConfig() + zigbee.levelConfig() + From 34748fd5f877c926cab6857ce31ad0179282d92c Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Fri, 8 Apr 2022 15:34:10 +0900 Subject: [PATCH 158/184] DevWs for SHINA SYSTEM containing containing Zigbee Multi Button (#78059) --- .../zigbee-multi-button.src/zigbee-multi-button.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy index c829563ca9b..78b7dabe35e 100644 --- a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy +++ b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy @@ -183,6 +183,8 @@ def configure() { if (isHeimanButton()) cmds += zigbee.writeAttribute(0x0000, 0x0012, DataType.BOOLEAN, 0x01) + addHubToGroup(0x000F) + addHubToGroup(0x0010) + addHubToGroup(0x0011) + addHubToGroup(0x0012) + if (isShinaButton()) + cmds += addHubToGroup(0x0000) return cmds } From 55f0754837783518f351becb936c6a183b2e44eb Mon Sep 17 00:00:00 2001 From: Focalcrest-Madi <58587489+Focalcrest-Madi@users.noreply.github.com> Date: Tue, 12 Apr 2022 17:23:29 +0800 Subject: [PATCH 159/184] DevWs for Focalcrest containing containing ZigBee Switch (#78069) * DevWs for Focalcrest containing containing ZigBee Switch * Fix: replace 4 spaces to 1 tab * Fix: Update other fingerprints * Fix: Add an empty line * Fix: replace 4 spaces to 1 tab --- .../smartthings/zigbee-switch.src/zigbee-switch.groovy | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy index 1b354241f1b..e197fbf58e0 100644 --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -133,6 +133,11 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", outClusters: "0019", manufacturer: "Focalcrest", model: "SRB01", deviceJoinName: "Focalcrest Switch" // In-Wall Relay Switch fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "EVVR", model: "SRB01A", deviceJoinName: "Evvr Switch" // Evvr IRS fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "EVVR", model: "SRB02A", deviceJoinName: "Evvr Switch" // Evvr IRS Lite + + // Evvr + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", outClusters: "0019", manufacturer: "Evvr", model: "SRB01", deviceJoinName: "Evvr Switch" // Evvr IRS + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "Evvr", model: "SRB01A", deviceJoinName: "Evvr Switch" // Evvr IRS + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "Evvr", model: "SRB02A", deviceJoinName: "Evvr Switch" // Evvr IRS Lite // SiHAS Switch fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z1", deviceJoinName: "SiHAS Switch" From 7e677d5b0c88094bbc54a57820f46f0935805d08 Mon Sep 17 00:00:00 2001 From: sky-nie <54890556+sky-nie@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:10:16 +0800 Subject: [PATCH 160/184] DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer (#78091) * DevWs for NIE-TECH CO., LTD. containing containing Min Smart Plug Dimmer * the default value restore as the previos version. Co-authored-by: Winnie Wen --- .../min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy index ef33c87f9cc..db2f2525cc4 100644 --- a/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy +++ b/devicetypes/sky-nie/min-smart-plug-dimmer.src/min-smart-plug-dimmer.groovy @@ -298,8 +298,8 @@ private getConfigParams() { powerFailureRecoveryParam, pushDimmingDurationParam, holdDimmingDurationParam, - minimumBrightnessParam - + minimumBrightnessParam, + maximumBrightnessParam, ] } From ff9f798f9c806c1900ee9b1dda2c179c8ff2e68d Mon Sep 17 00:00:00 2001 From: mingwei0827 <38943109+mingwei0827@users.noreply.github.com> Date: Mon, 25 Apr 2022 16:14:23 +0800 Subject: [PATCH 161/184] DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Window Shade Battery (#78108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 啦啦 王 --- .../zigbee-window-shade-battery.groovy | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy index d2bd8427bca..2e6522f25f9 100644 --- a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy +++ b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy @@ -39,6 +39,9 @@ metadata { // SMARTWINGS fingerprint inClusters: "0000,0001,0003,0004,0005,0102", outClusters: "0019", manufacturer: "Smartwings", model: "WM25/L-Z", deviceJoinName: "Smartwings Window Treatment" + + // SONOFF + fingerprint inClusters: "0000,0001,0003,0004,0020,0102,fc57", outClusters: "0019", manufacturer: "SONOFF", model: "ZBCurtain", deviceJoinName: "SONOFF Window Treatment" } preferences { @@ -319,15 +322,15 @@ private List readDeviceBindingTable() { } def supportsLiftPercentage() { - isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() + isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() || isSonoff() } def shouldInvertLiftPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() + return isIkeaKadrilj() || isIkeaFyrtur() || isSmartwings() || isSonoff() } def reportsBatteryPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() + return isIkeaKadrilj() || isIkeaFyrtur() || isYooksmartOrYookee() || isSmartwings() || isSonoff() } def isIkeaKadrilj() { @@ -344,4 +347,8 @@ def isYooksmartOrYookee() { def isSmartwings() { device.getDataValue("model") == "WM25/L-Z" +} + +def isSonoff() { + device.getDataValue("manufacturer") == "SONOFF" } \ No newline at end of file From 3299947ca57b7273ac12f5916641bdc21f839a4d Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 9 May 2022 14:52:10 -0700 Subject: [PATCH 162/184] BUG-4775 Only prevent sending pause for Somfy shades --- .../zigbee-window-shade.groovy | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) 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 4fc994cb38e..3282841927a 100644 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -27,11 +27,11 @@ metadata { capability "Switch Level" command "pause" - + // NodOn - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-RS-20", deviceJoinName: "NodOn Window Treatment" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-RS-20", deviceJoinName: "NodOn Window Treatment" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "0019", manufacturer: "NodOn", model: "SIN-4-RS-20_PRO", deviceJoinName: "NodOn Window Treatment" - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "eZEX Window Treatment" // SY-IoT201-BD //SOMFY Blind Controller/eZEX fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.6", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.8", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) @@ -149,10 +149,10 @@ def levelEventHandler(currentLevel) { sendEvent(name: "level", value: currentLevel, unit: "%", displayed: false) if (currentLevel == 0 || currentLevel == 100) { - if (device.getDataValue("manufacturer") == "Third Reality, Inc"){ - sendEvent(name: "windowShade", value: currentLevel == 0 ? "open" : "closed") + if (device.getDataValue("manufacturer") == "Third Reality, Inc"){ + sendEvent(name: "windowShade", value: currentLevel == 0 ? "open" : "closed") } else { - sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") + sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") } } else { if (priorLevel < currentLevel) { @@ -222,14 +222,10 @@ def pause() { log.info "pause()" def currentShadeStatus = device.currentValue("windowShade") - if (device.getDataValue("manufacturer") == "Third Reality, Inc") { - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) + if (isSomfy() && (currentShadeStatus == "open" || currentShadeStatus == "closed")) { + sendEvent(name: "windowShade", value: currentShadeStatus) } else { - if (currentShadeStatus == "open" || currentShadeStatus == "closed") { - sendEvent(name: "windowShade", value: currentShadeStatus) - } else { - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) - } + zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) } } From f0c28a6fae961876d1240ba99a12403388a979e2 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Mon, 16 May 2022 16:53:51 +0900 Subject: [PATCH 163/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#78264) --- .../sihas-multipurpose-sensor.groovy | 35 +++++-------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index 4c37dba3370..db0c960a844 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -147,31 +147,13 @@ private Map getBatteryResult(rawValue) { def maxVolts = 3.2 if (isDSM300()) maxVolts = 3.1 - - // Get the current battery percentage as a multiplier 0 - 1 - def curValVolts = Integer.parseInt(device.currentState("battery")?.value ?: "100") / 100.0 - // Find the corresponding voltage from our range - curValVolts = curValVolts * (maxVolts - minVolts) + minVolts - // Round to the nearest 10th of a volt - curValVolts = Math.round(10 * curValVolts) / 10.0 - - // Only update the battery reading if we don't have a last reading, - // OR we have received the same reading twice in a row - // 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 - if (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) - roundedPct = 1 - result.value = Math.min(100, roundedPct) - } else { - // Don't update as we want to smooth the battery values, but do report the last battery state for record keeping purposes - result.value = device.currentState("battery").value - } - - result.descriptionText = "${device.displayName} battery was ${result.value}%" - state.lastVolts = volts + + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) + result.descriptionText = "${device.displayName} battery was ${result.value}%" } return result } @@ -254,7 +236,6 @@ def refresh() { } if (isDSM300()) { - refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE) refreshCmds += zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) refreshCmds += zigbee.enrollResponse() } @@ -325,4 +306,4 @@ private Boolean isDSM300() { private Boolean isCSM300() { device.getDataValue("model") == "CSM-300Z" -} +} \ No newline at end of file From a81d68df78675e30e31f9f15b0158d67be7da2ff Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 17 May 2022 19:45:36 +0900 Subject: [PATCH 164/184] DevWs for SHINA SYSTEM containing containing Zigbee Multi Button (#78282) --- .../zigbee-multi-button.src/zigbee-multi-button.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy index 78b7dabe35e..63d9a46a978 100644 --- a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy +++ b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy @@ -157,6 +157,9 @@ def getBatteryPercentageResult(rawValue) { def minVolts = 2.1 def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) + if(pct <= 0) { + pct = 0.01 + } result.value = Math.min(100, (int)(pct * 100)) def linkText = getLinkText(device) result.descriptionText = "${linkText} battery was ${result.value}%" From d7e7a8ca1d381c676b4fa5dea10246b3479aa9f8 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Wed, 18 May 2022 11:34:52 +0800 Subject: [PATCH 165/184] UPDATE update model id --- .../smartsense-temp-humidity-sensor.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index af41fd23c1a..9b23cc87390 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -40,7 +40,7 @@ metadata { fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0020, 0402, 0405, FC57", outClusters: "0003, 0019", manufacturer: "eWeLink", model: "SNZB-02P", deviceJoinName: "eWeLink Multipurpose Sensor" //Third Reality - fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0402,0405", outClusters: "0019", manufacturer:"Third Reality, Inc", model:"3RTS20BZ", deviceJoinName: "ThirdReality Thermal & Humidity Sensor" + fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0402,0405", outClusters: "0019", manufacturer:"Third Reality, Inc", model:"3RTHS24BZ", deviceJoinName: "ThirdReality Thermal & Humidity Sensor" } simulator { From ab054dd6c7e2231ee610935c15252cff37ce6a1d Mon Sep 17 00:00:00 2001 From: aguilbault-Sinope <54598043+aguilbault-Sinope@users.noreply.github.com> Date: Thu, 19 May 2022 08:33:21 -0400 Subject: [PATCH 166/184] User27228209 16 (#78292) * DevWs for Sinope Technologies containing containing VA4200WZ-VA4200ZB Sinope Valve * correction spacing * Update va4200wz-va4200zb-sinope-valve.groovy remove commented code * Update va4200wz-va4200zb-sinope-valve.groovy spacing * Update va4200wz-va4200zb-sinope-valve.groovy spacing --- .../va4200wz-va4200zb-sinope-valve.groovy | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy index 160c2a03334..722b8118437 100644 --- a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy +++ b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy @@ -11,9 +11,7 @@ import physicalgraph.zigbee.zcl.DataType metadata { preferences { - input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - // input("logFilter", "number", title: "Trace level", range: "1..5", - // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + input("trace", "bool", title: "Trace (Only for debugging)", description: "Set it to true to enable tracing") } definition (name: "VA4200WZ-VA4200ZB Sinope Valve", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.watervalve") { @@ -140,7 +138,7 @@ def parse(String description) { } } } - + return result } @@ -204,7 +202,6 @@ private Map getBatteryResult(rawValue) { def result = [:] result.name = 'battery' result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - result.value = convertVoltToPercent(rawValue) return result } @@ -308,7 +305,7 @@ private def convertVoltToPercent(value) { } } -def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMessage = true) { +def traceEvent(logFilter, message, displayEvent = true, traceLevel, sendMessage = true) { int LOG_ERROR = get_LOG_ERROR() int LOG_WARN = get_LOG_WARN() int LOG_INFO = get_LOG_INFO() From 636e6e639bc66cf5a8d74edd6f1488080259ec32 Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 23 May 2022 12:49:01 -0700 Subject: [PATCH 167/184] Remove bintray from sources list and update artifactory url --- build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 200bc83c86c..7f4927c3ea5 100644 --- a/build.gradle +++ b/build.gradle @@ -13,26 +13,24 @@ buildscript { } repositories { mavenLocal() - jcenter() maven { credentials { username smartThingsArtifactoryUserName password smartThingsArtifactoryPassword } - url "https://smartthings.jfrog.io/smartthings/libs-release-local" + url "https://smartthings.jfrog.io/smartthings/libs-release" } } } repositories { mavenLocal() - jcenter() maven { credentials { username smartThingsArtifactoryUserName password smartThingsArtifactoryPassword } - url "https://smartthings.jfrog.io/smartthings/libs-release-local" + url "https://smartthings.jfrog.io/smartthings/libs-release" } } From 9c617262a2dbe7f309612290c550bdeed6dc23c2 Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 23 May 2022 12:49:01 -0700 Subject: [PATCH 168/184] Remove bintray from sources list and update artifactory url --- build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 200bc83c86c..7f4927c3ea5 100644 --- a/build.gradle +++ b/build.gradle @@ -13,26 +13,24 @@ buildscript { } repositories { mavenLocal() - jcenter() maven { credentials { username smartThingsArtifactoryUserName password smartThingsArtifactoryPassword } - url "https://smartthings.jfrog.io/smartthings/libs-release-local" + url "https://smartthings.jfrog.io/smartthings/libs-release" } } } repositories { mavenLocal() - jcenter() maven { credentials { username smartThingsArtifactoryUserName password smartThingsArtifactoryPassword } - url "https://smartthings.jfrog.io/smartthings/libs-release-local" + url "https://smartthings.jfrog.io/smartthings/libs-release" } } From 5b7573f3fdfe3faa4d561200cb762d87da27cb62 Mon Sep 17 00:00:00 2001 From: greens Date: Mon, 23 May 2022 13:29:19 -0700 Subject: [PATCH 169/184] HCS-3029 Add ocfDeviceType to Zigbe Lock Without Codes --- .../zigbee-lock-without-codes.groovy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 index a7dd8ac9ad5..4775d00de82 100644 --- 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 @@ -12,12 +12,12 @@ * for the specific language governing permissions and limitations under the License. * */ - + import physicalgraph.zigbee.zcl.DataType import physicalgraph.zigbee.clusters.iaszone.ZoneStatus 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) { + definition (name:"ZigBee Lock Without Codes", namespace:"smartthings", author:"SmartThings", vid:"generic-lock-2", mnmn:"SmartThings", runLocally:true, minHubCoreVersion:'000.022.00013', executeCommandsLocally:true, ocfDeviceType: "oic.d.smartlock") { capability "Actuator" capability "Lock" capability "Refresh" @@ -139,10 +139,10 @@ def initialize() { cmds += zigbee.enrollResponse() cmds += zigbee.configureReporting(CLUSTER_IAS_ZONE, IAS_ATTR_ZONE_STATUS, DataType.BITMAP16, 30, 60*5, null) } else { - cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,DataType.ENUM8, 0, 3600, null) + cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,DataType.ENUM8, 0, 3600, null) cmds += zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,DataType.UINT8, 600, 21600, 0x01) cmds += zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) - if (isSiHASLock()) cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_DOORSTATE,DataType.ENUM8, 0, 3600, null) + if (isSiHASLock()) cmds += zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_DOORSTATE,DataType.ENUM8, 0, 3600, null) cmds += refresh() } @@ -193,7 +193,7 @@ private def parseAttributeResponse(String description) { 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" From 558068c9abac466961549de1892084aa4670f063 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Tue, 24 May 2022 15:57:26 +0900 Subject: [PATCH 170/184] DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor (#78311) --- .../sihas-multipurpose-sensor.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index db0c960a844..3191342733d 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -146,7 +146,7 @@ private Map getBatteryResult(rawValue) { def minVolts = 2.3 def maxVolts = 3.2 - if (isDSM300()) maxVolts = 3.1 + if (isDSM300()) maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) From 019a5272af794b2f2d2cfa73b33203f82004a2c5 Mon Sep 17 00:00:00 2001 From: AltyorFig <95210115+AltyorFig@users.noreply.github.com> Date: Mon, 20 Jun 2022 15:11:52 +0200 Subject: [PATCH 171/184] DevWs for NodOn containing containing NodOn Roller Shutter (#78396) * DevWs for NodOn containing containing NodOn Roller Shutter * format file --- .../zigbee-window-shade.groovy | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) 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 3282841927a..00eab9a46ef 100644 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -149,17 +149,25 @@ def levelEventHandler(currentLevel) { sendEvent(name: "level", value: currentLevel, unit: "%", displayed: false) if (currentLevel == 0 || currentLevel == 100) { - if (device.getDataValue("manufacturer") == "Third Reality, Inc"){ + if (device.getDataValue("manufacturer") == "Third Reality, Inc" || device.getDataValue("manufacturer") == "NodOn"){ sendEvent(name: "windowShade", value: currentLevel == 0 ? "open" : "closed") } else { sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open") } } else { - if (priorLevel < currentLevel) { - sendEvent([name:"windowShade", value: "opening"]) - } else if (priorLevel > currentLevel) { - sendEvent([name:"windowShade", value: "closing"]) - } + if (device.getDataValue("manufacturer") == "NodOn"){ + if (priorLevel < currentLevel) { + sendEvent([name:"windowShade", value: "closing"]) + } else if (priorLevel > currentLevel) { + sendEvent([name:"windowShade", value: "opening"]) + } + } else { + if (priorLevel < currentLevel) { + sendEvent([name:"windowShade", value: "opening"]) + } else if (priorLevel > currentLevel) { + sendEvent([name:"windowShade", value: "closing"]) + } + } runIn(1, "updateFinalState", [overwrite:true]) } } From 7dbb5803d67fc1dd23c8c74f97643b6939518aea Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Fri, 24 Jun 2022 19:03:42 +0800 Subject: [PATCH 172/184] HEIMAN translate issue (#78425) --- .../smartthings/zigbee-scene-keypad.src/i18n/messages.properties | 1 + .../smartthings/zigbee-switch.src/i18n/messages.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties index 9d741777bbf..8190dbde3e6 100644 --- a/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties @@ -15,6 +15,7 @@ # Chinese '''HEIMAN Remote Control'''.zh-cn=海曼情景开关 '''HEIMAN Scene Keypad'''.zh-cn=海曼情景开关 +'''HEIMAN Scene Panel'''.zh-cn=海曼情景开关 '''ORVIBO Remote Control'''.zh-cn=欧瑞博情景开关 '''ORVIBO Scene Keypad'''.zh-cn=欧瑞博情景开关 '''GDKES Remote Control'''.zh-cn=粤奇胜情景开关 diff --git a/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties index 7179338dfc1..7433cef0364 100755 --- a/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties @@ -29,3 +29,4 @@ '''HONYAR Smart Switch'''.zh-cn=鸿雁智能墙面开关(一开) '''HEIMAN Switch'''.zh-cn=海曼智能墙面开关(一开) '''HEIMAN Smart Switch'''.zh-cn=海曼智能墙面开关(一开) +'''HEIMAN Outlet'''.zh-cn=海曼智能插座 \ No newline at end of file From 3cc8efa81eee0ac4c2a9ed420e1a6c25f88dedf0 Mon Sep 17 00:00:00 2001 From: Doczillar <66080719+Doczillar@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:27:11 -0500 Subject: [PATCH 173/184] Updating README with new Edge info (#78603) * Updating README with new Edge info * Update README.md --- README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7dc22a4722a..9224d6806c0 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ -# SmartThings Public GitHub Repo +# Welcome to the SmartThings Public GitHub Repo -An official list of SmartApps and Device Types from SmartThings. +This repo contains development code for SmartApps and Groovy DTHs (Dynamic Type Handlers). -Here are some links to help you get started coding right away: +Here are some links to help you get started: -* [GitHub-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html) -* [Full Documentation](http://docs.smartthings.com) -* [IDE & Simulator](http://ide.smartthings.com) +* [Developer Documentation](https://developer-preview.smartthings.com) +* [Developer Workspace](https://smartthings.developer.samsung.com/workspace) * [Community Forums](http://community.smartthings.com) -Follow us on the web: - -* Twitter: http://twitter.com/smartthingsdev -* Facebook: http://facebook.com/smartthingsdevelopers +> SmartThings Edge Device Drivers are the new method for integrating Hub Connected Devices into the SmartThings Platform. With the launch of SmartThings Edge, we are taking some events that would have happened in the Cloud and moving them to the SmartThings Hub. SmartThings Edge uses Lua-based device drivers and our Rules API to control and automate devices connected directly to a SmartThings Hub. This includes Zigbee, Z-Wave, and LAN devices as well as automations triggered by timers and other Hub Connected devices using drivers. In the future, this will expand to include more protocols and features, like the new Matter standard. +> To learn more about SmartThings Edge, visit [Get Started with SmartThings Edge](https://developer-preview.smartthings.com/docs/devices/hub-connected/get-started). From 4c68f433a90fe1742d75592442fc88645c0c853f Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Wed, 20 Jul 2022 03:22:17 +0900 Subject: [PATCH 174/184] Devws for shina system containin 114 (#78712) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * CSM-300Z update --- .../sihas-multipurpose-sensor.groovy | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy index 3191342733d..8ac40de5eb3 100644 --- a/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy +++ b/devicetypes/shinasys/sihas-multipurpose-sensor.src/sihas-multipurpose-sensor.groovy @@ -28,14 +28,15 @@ metadata { capability "Health Check" capability "Sensor" capability "Contact Sensor" - capability "afterguide46998.peopleCounter" - capability "afterguide46998.inOutDirection" + capability "afterguide46998.peopleCounterV2" + capability "afterguide46998.inOutDirectionV2" + capability "Momentary" fingerprint inClusters: "0000,0001,0003,0020,0400,0402,0405,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "USM-300Z", deviceJoinName: "SiHAS MultiPurpose Sensor", mnmn: "SmartThings", vid: "generic-motion-6" fingerprint inClusters: "0000,0001,0003,0020,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "OSM-300Z", deviceJoinName: "SiHAS Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2", ocfDeviceType: "x.com.st.d.sensor.motion" fingerprint inClusters: "0000,0003,0402,0001,0405", outClusters: "0004,0003,0019", manufacturer: "ShinaSystem", model: "TSM-300Z", deviceJoinName: "SiHAS Temperature/Humidity Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Temp/Humidity_Sensor", ocfDeviceType: "oic.d.thermostat" fingerprint inClusters: "0000,0001,0003,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "DSM-300Z", deviceJoinName: "SiHAS Contact Sensor", mnmn: "SmartThings", vid: "generic-contact-3", ocfDeviceType: "x.com.st.d.sensor.contact" - fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "23d6139c-b108-3467-9ddb-6a177d6cc1df", ocfDeviceType: "x.com.st.d.sensor.motion" + fingerprint inClusters: "0000,0001,0003,000C,0020,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "CSM-300Z", deviceJoinName: "SiHAS People Counter", mnmn: "SmartThingsCommunity", vid: "c924b630-4647-39d6-897e-7597acededd7", ocfDeviceType: "x.com.st.d.sensor.motion" } preferences { section { @@ -143,11 +144,12 @@ private Map getBatteryResult(rawValue) { if (!(rawValue == 0 || rawValue == 255)) { result.name = 'battery' result.translatable = true - def minVolts = 2.3 - def maxVolts = 3.2 - + def minVolts = 2.2 + def maxVolts = 3.1 + if (isDSM300()) maxVolts = 3.0 - + if (isCSM300()) minVolts = 1.9 + def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) if (roundedPct <= 0) @@ -189,18 +191,21 @@ private Map getAnalogInputResult(value) { String descriptionText2 = "${device.displayName} : $inoutString" log.debug "[$fpc] = people: $pc, dir: $inout, $inoutString" - if((inout != "ready") && (prevInOut == inoutString)) { + String motionActive = pc ? "active" : "inactive" + sendEvent(name: "motion", value: motionActive, displayed: true, isStateChange: false) + + if((inoutString != "ready") && (prevInOut == inoutString)) { sendEvent(name: "inOutDir", value: "ready", displayed: true) } - sendEvent(name: "peopleCounter", value: pc, displayed: true, descriptionText: descriptionText1 ) - + sendEvent(name: "inOutDir", value: inoutString, displayed: true, descriptionText: descriptionText2) return [ - name : 'inOutDir', - value : inoutString, - descriptionText: descriptionText2, + name : 'peopleCounter', + value : pc, + descriptionText: descriptionText1, translatable : true ] + } def setPeopleCounter(peoplecounter) { @@ -209,6 +214,9 @@ def setPeopleCounter(peoplecounter) { zigbee.writeAttribute(ANALOG_INPUT_BASIC_CLUSTER, ANALOG_INPUT_BASIC_PRESENT_VALUE_ATTRIBUTE, DataType.FLOAT4, pc) } +def push() { + setPeopleCounter(0) +} /** * PING is used by Device-Watch in attempt to reach the Device * */ From 3817703e791a132eb359e77cbcb414d431fb8538 Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Wed, 20 Jul 2022 03:22:53 +0900 Subject: [PATCH 175/184] Devws for shina system containin 70 (#78726) * DevWs for SHINA SYSTEM containing containing ZigBee Multi Switch * Move SiHAS 1gang switch to another switch DTH. * Add SiHAS Switch * Add SiHAS Switch * add blank line * update * update ISM300Z * Update zigbee-switch.groovy Recover from erroneous deletion. * Update zigbee-switch.groovy Recover from erroneous deletion. * Update zigbee-switch.groovy add blank * Update zigbee-switch.groovy update blank --- .../zigbee-multi-switch.src/zigbee-multi-switch.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy index 47d8af4f804..a103546cbcc 100644 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -101,6 +101,7 @@ metadata { fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z4", deviceJoinName: "SiHAS Switch 1" fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z5", deviceJoinName: "SiHAS Switch 1" fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "SBM300Z6", deviceJoinName: "SiHAS Switch 1" + fingerprint inClusters: "0000, 0003, 0006, 0019, ", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "ISM300Z3", deviceJoinName: "SiHAS Switch 1" } // simulator metadata simulator { @@ -294,6 +295,7 @@ private getChildCount() { case "ST-S350-ZB": case "SBM300Z3": case "HS6SW3A-W-EF-3.0": + case "ISM300Z3": return 3 case "E220-KR4N0Z0-HA": case "E220-KR4N0Z1-HA": @@ -323,4 +325,4 @@ private getChildCount() { default: return 2 } -} \ No newline at end of file +} From b5e9884815c8ffd8183c26fd9cc59da19a53994b Mon Sep 17 00:00:00 2001 From: ADUROSMART ERIA <52692745+adurosmart@users.noreply.github.com> Date: Thu, 21 Jul 2022 05:11:56 +0800 Subject: [PATCH 176/184] Dev fix dimmer plug189 (#78346) * update parseAduroSmartButtonMessage function Some customers reported that the buttons 1 and 4 are not sensitive, so restore the zigbee.ONOFF_CLUSTER event trigger of button 1 and button 4, which will increase the success rate of event reporting after the button is pressed * fix dimmer plug Identify errors Co-authored-by: Andy Yi Co-authored-by: DESKTOP-NHN41KC\linkl --- devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy | 3 ++- .../zigbee-switch-power.src/zigbee-switch-power.groovy | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy index 79de2e21568..7aa8aa2920e 100644 --- a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy @@ -27,7 +27,8 @@ metadata { // AduroSmart fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", deviceId: "0101", manufacturer: "AduroSmart Eria", model: "AD-DimmableLight3001", deviceJoinName: "Eria Light" //Eria ZigBee Dimmable Bulb - + fingerprint profileId: "0104", deviceId: "0101", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "BDP3001", deviceJoinName: "Eria Switch" //Eria Zigbee Dimmable Plug + // Aurora fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "LCBulb01UK", deviceJoinName: "AOne Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora AOne Control Dimmer (120w) fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003", manufacturer: "Aurora", model: "Dimmer", deviceJoinName: "AOne Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora AOne Control Dimmer (320w) diff --git a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy index 15563dc1217..479998275b8 100644 --- a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy +++ b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy @@ -53,7 +53,7 @@ metadata { //AduroSmart fingerprint profileId: "0104", deviceId: "0051", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 1000, 0702", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "AD-SmartPlug3001", deviceJoinName: "Eria Switch" //Eria Zigbee Smart Plug fingerprint profileId: "0104", deviceId: "010A", inClusters: "0000, 0003, 0004, 0005, 0006, 1000", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "BPU3", deviceJoinName: "Eria Switch" //Eria Zigbee On/Off Plug - fingerprint profileId: "0104", deviceId: "0101", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "BDP3001", deviceJoinName: "Eria Switch" //Eria Zigbee Dimmable Plug + } tiles(scale: 2) { From 2a3c40e8c800dd28508b0d1247d7b2f797ebf225 Mon Sep 17 00:00:00 2001 From: weihuan1111 <99949392+weihuan1111@users.noreply.github.com> Date: Fri, 22 Jul 2022 05:06:18 +0800 Subject: [PATCH 177/184] Move Third Reality Smart Button (#78743) * update * Update ikea-button.groovy * update * update * Update ikea-button.groovy * Update ikea-button.groovy --- .../ikea-button.src/ikea-button.groovy | 27 +++++++++++++++---- .../smartsense-button.groovy | 15 +---------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy index 3b0996944e6..4ea0a27ce44 100644 --- a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy +++ b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy @@ -35,6 +35,7 @@ metadata { fingerprint manufacturer: "SOMFY", model: "Situo 1 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 fingerprint inClusters: "0000, 0001, 0003", outClusters: "0003, 0006", manufacturer: "eWeLink", model: "WB01", deviceJoinName: "eWeLink Button" //eWeLink Button WB01 fingerprint inClusters: "0000, 0001, 0003, 0020, FC57", outClusters: "0003, 0006, 0019", manufacturer: "eWeLink", model: "SNZB-01P", deviceJoinName: "eWeLink Button" //eWeLink Button + fingerprint inClusters: "0000,0001,0012", outClusters: "0006,0008,0019", manufacturer: "Third Reality, Inc", model: "3RSB22BZ", deviceJoinName: "ThirdReality Smart Button" } tiles { @@ -199,7 +200,7 @@ def installed() { if (isIkeaOpenCloseRemote() || isSomfy()) { supportedButtons = ["pushed"] - } else if (isEWeLink()) { + } else if (isEWeLink() || isThirdReality()) { supportedButtons = ["pushed", "held", "double"] } else { supportedButtons = ["pushed", "held"] @@ -269,9 +270,10 @@ def parse(String description) { } else if (descMap.clusterInt == CLUSTER_SCENES || descMap.clusterInt == zigbee.ONOFF_CLUSTER || descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER || - descMap.clusterInt == CLUSTER_WINDOW_COVERING) { + descMap.clusterInt == CLUSTER_WINDOW_COVERING || + descMap.clusterInt == 0x0012) { event = getButtonEvent(descMap) - } + } } def result = [] @@ -395,7 +397,18 @@ private Map getButtonEvent(Map descMap) { buttonState = "pushed" } } - } + } else if (isThirdReality()) { + if (descMap.clusterInt == 0x0012) { + buttonNumber = 1 + if (descMap.value == "0002") { + buttonState = "double" + } else if (descMap.value == "0001") { + buttonState = "pushed" + } else if (descMap.value == "0000") { + buttonState = "held" + } + } + } if (buttonNumber != 0) { // Create old style @@ -461,4 +474,8 @@ private List addHubToGroup(Integer groupAddr) { private List readDeviceBindingTable() { ["zdo mgmt-bind 0x${device.deviceNetworkId} 0", "delay 200"] -} \ No newline at end of file +} + +private boolean isThirdReality() { + device.getDataValue("manufacturer") == "Third Reality, Inc" +} diff --git a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy index c301d5c7a6f..fa24592d589 100755 --- a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy +++ b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy @@ -28,7 +28,6 @@ metadata { capability "Sensor" fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "button", deviceJoinName: "Button" - fingerprint inClusters: "0000,0001,0012", outClusters: "0006,0008,0019", manufacturer: "Third Reality, Inc", model: "3RSB22BZ", deviceJoinName: "ThirdReality Smart Button" } simulator { @@ -137,9 +136,7 @@ def parse(String description) { } } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) { map = translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value))) - } else if ( descMap.clusterInt == 0x0012 ) { - map = translateMultiStatus(descMap.value) - } + } } } else if (map.name == "temperature") { if (tempOffset) { @@ -177,16 +174,6 @@ private Map translateZoneStatus(ZoneStatus zs) { } else { } } -private Map translateMultiStatus(String value) { - if (value == "0002" ) { - return getButtonResult('double') - } else if (value == "0001" ) { - return getButtonResult('pushed') - } else if (value == "0000"){ - return getButtonResult('held') - } else {} -} - private Map getBatteryResult(rawValue) { log.debug "Battery rawValue = ${rawValue}" def linkText = getLinkText(device) From caf4a38f6048be7cbdc4b7b822ef4d90e27cf1cd Mon Sep 17 00:00:00 2001 From: greens Date: Wed, 3 Aug 2022 16:27:52 -0700 Subject: [PATCH 178/184] CHAD-8882 Send supportedButtonValues for zigbee-button should bring devices backed by this DTH more in line with the capability definition. --- .../smartthings/zigbee-button.src/zigbee-button.groovy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy b/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy index aa74ac7193a..87edffd4152 100755 --- a/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy +++ b/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy @@ -22,7 +22,7 @@ metadata { capability "Actuator" capability "Battery" capability "Button" - capability "Holdable Button" + capability "Holdable Button" capability "Configuration" capability "Refresh" capability "Sensor" @@ -147,7 +147,7 @@ private Map parseNonIasButtonMessage(Map descMap){ button = 2 break } - + getButtonResult("release", button) } } @@ -191,6 +191,9 @@ def refresh() { def configure() { log.debug "Configuring Reporting, IAS CIE, and Bindings." + if (!device.currentState("supportedButtonValues")) { + sendEvent(name: "supportedButtonValues", value: JsonOutput.toJson(["pushed", "held"]), displayed: false) + } def cmds = [] if (device.getDataValue("model") == "3450-L") { cmds << [ From 0c7cf684359a476d0877d98ea56c33dd9cba5fcd Mon Sep 17 00:00:00 2001 From: shinasys <71238736+shinasys@users.noreply.github.com> Date: Wed, 10 Aug 2022 03:19:26 +0900 Subject: [PATCH 179/184] Devws for shina system containin 114 (#78787) * DevWs for SHINA SYSTEM containing containing SiHas Multipurpose Sensor * CSM-300Z update * SiHAS Dual Motion Sensor : new * Update sihas-dual-motion-sensor.groovy The reporting time has been changed. * Update sihas-dual-motion-sensor.groovy rollback * Update sihas-dual-motion-sensor.groovy Convert indentation to Tabs. --- .../sihas-dual-motion-sensor.groovy | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 devicetypes/shinasys/sihas-dual-motion-sensor.src/sihas-dual-motion-sensor.groovy diff --git a/devicetypes/shinasys/sihas-dual-motion-sensor.src/sihas-dual-motion-sensor.groovy b/devicetypes/shinasys/sihas-dual-motion-sensor.src/sihas-dual-motion-sensor.groovy new file mode 100644 index 00000000000..fb1036fc782 --- /dev/null +++ b/devicetypes/shinasys/sihas-dual-motion-sensor.src/sihas-dual-motion-sensor.groovy @@ -0,0 +1,205 @@ +/* + * Copyright 2022 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.clusters.iaszone.ZoneStatus +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition (name: "SiHAS Dual Motion Sensor", namespace: "shinasys", author: "SHINA SYSTEM", mnmn: "SmartThingsCommunity", vid: "868a0fcc-ae46-3a1b-9315-e342007bb3a9", ocfDeviceType: "x.com.st.d.sensor.motion") { + capability "Motion Sensor" + capability "Configuration" + capability "Battery" + capability "Refresh" + capability "Health Check" + capability "afterguide46998.dualMotionInSensor" + capability "afterguide46998.dualMotionOutSensor" + + attribute "motionInterval","number" + + fingerprint inClusters: "0000,0001,0003,0020,0406,0500", outClusters: "0003,0004,0019", manufacturer: "ShinaSystem", model: "DMS-300Z", deviceJoinName: "SiHAS Dual Motion Sensor" + } + preferences { + section { + input "motionInterval", "number", title: "Motion Interval", description: "What is the re-sensing time (seconds) after the motion sensor is detected.", range: "1..100", defaultValue: 5, required: true, displayDuringSetup: true + } + } +} + +private getOCCUPANCY_SENSING_CLUSTER() { 0x0406 } +private getPOWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE() { 0x0020 } +private getOCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE() { 0x0000 } +private getOCCUPIED_TO_UNOCCUPIED_DELAY_ATTRIBUTE() { 0x0010 } + +private List collectAttributes(Map descMap) { + List descMaps = new ArrayList() + descMaps.add(descMap) + if (descMap.additionalAttrs) { + descMaps.addAll(descMap.additionalAttrs) + } + return descMaps +} + +def parse(String description) { + log.debug "Parsing message from device: $description" + + Map map = zigbee.getEvent(description) + if (!map) { + if (description?.startsWith('zone status')) { + map = parseIasMessage(description) + } else { + Map descMap = zigbee.parseDescriptionAsMap(description) + if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value) { + List descMaps = collectAttributes(descMap) + def battMap = descMaps.find { it.attrInt == POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE } + if (battMap) { + map = getBatteryResult(Integer.parseInt(battMap.value, 16)) + } + } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap.commandInt != 0x07) { + def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 10)) + map = translateZoneStatus(zs) + } else if (descMap?.clusterInt == OCCUPANCY_SENSING_CLUSTER && descMap.attrInt == OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE && descMap?.value) { + def inMotion = descMap.value == "01" ? "active" : "inactive" + def outMotion = device.latestState('motionOut')?.value + sendDualMotionResult("motionIn", inMotion) + map = (inMotion == "active" || outMotion == "active") ? getMotionResult('active') : getMotionResult('inactive') + } else if (descMap?.clusterInt == OCCUPANCY_SENSING_CLUSTER && descMap.attrInt == OCCUPIED_TO_UNOCCUPIED_DELAY_ATTRIBUTE && descMap?.value) { + def interval = zigbee.convertToInt(descMap.value, 10) + log.debug "interval = [$interval]" + map = [name:'motionInterval',value: interval] + } + } + } + + def result = map ? createEvent(map) : [:] + + if (description?.startsWith('enroll request')) { + List cmds = zigbee.enrollResponse() + result = cmds?.collect { new physicalgraph.device.HubAction(it) } + } + log.debug "result: $result" + return result +} + +private Map parseIasMessage(String description) { + ZoneStatus zs = zigbee.parseZoneStatus(description) + translateZoneStatus(zs) +} + +private Map translateZoneStatus(ZoneStatus zs) { + def inMotion = device.latestState('motionIn')?.value + def outMotion = (zs.isAlarm1Set() || zs.isAlarm2Set()) ? "active" : "inactive" + sendDualMotionResult("motionOut", outMotion) + return (inMotion == "active" || outMotion == "active") ? getMotionResult('active') : getMotionResult('inactive') +} + +private Map getBatteryResult(rawValue) { + def linkText = getLinkText(device) + def result = [:] + def volts = rawValue / 10 + + if (!(rawValue == 0 || rawValue == 255)) { + result.name = 'battery' + result.translatable = true + def minVolts = 2.2 + def maxVolts = 3.1 + + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) + result.descriptionText = "${device.displayName} battery was ${result.value}%" + } + return result +} + +private sendDualMotionResult(name, value) { + String descriptionText = value == 'active' ? "${device.displayName} ${name} detected motion" : "${device.displayName} ${name} has stopped" + log.debug "$name = $value: $descriptionText" + + sendEvent(name: name, value: value, descriptionText: descriptionText,translatable : true) +} + +private Map getMotionResult(value) { + String descriptionText = value == 'active' ? "${device.displayName} detected motion" : "${device.displayName} motion has stopped" + return [ + name : 'motion', + value : value, + descriptionText: descriptionText, + translatable : true + ] +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE) +} + +def updated() { + log.debug "device updated $motionInterval" + + //set reportingInterval = 0 to trigger update + if (isMotionIntervalChange()) { + sendEvent(name: "motionInterval", value: getMotionReportInterval(), descriptionText: "Motion interval set to ${getMotionReportInterval()} seconds") + sendHubCommand(zigbee.writeAttribute(OCCUPANCY_SENSING_CLUSTER, OCCUPIED_TO_UNOCCUPIED_DELAY_ATTRIBUTE, DataType.UINT16, getMotionReportInterval()), 1) + } +} + +//has interval been updated +def isMotionIntervalChange() { + log.debug "isMotionIntervalChange ${getMotionReportInterval()} <- ${device.latestValue("motionInterval")}" + return (getMotionReportInterval() != device.latestValue("motionInterval")) +} + +//settings default interval +def getMotionReportInterval() { + return (motionInterval != null ? motionInterval : 5) +} + +def refresh() { + def refreshCmds = [] + + refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE) + + refreshCmds += zigbee.readAttribute(OCCUPANCY_SENSING_CLUSTER, OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE) + refreshCmds += zigbee.readAttribute(OCCUPANCY_SENSING_CLUSTER, OCCUPIED_TO_UNOCCUPIED_DELAY_ATTRIBUTE) + refreshCmds += zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) + refreshCmds += zigbee.enrollResponse() + return refreshCmds +} + +def configure() { + def configCmds = [] + + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + + // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity + // battery minReport 30 seconds, maxReportTime 6 hrs by default + // humidity minReportTime 30 seconds, maxReportTime 60 min + // illuminance minReportTime 30 seconds, maxReportTime 60 min + // occupancy sensing minReportTime 10 seconds, maxReportTime 60 min + // ex) zigbee.configureReporting(0x0001, 0x0020, DataType.UINT8, 600, 21600, 0x01) + // This is for cluster 0x0001 (power cluster), attribute 0x0021 (battery level), whose type is UINT8, + // the minimum time between reports is 10 minutes (600 seconds) and the maximum time between reports is 6 hours (21600 seconds), + // and the amount of change needed to trigger a report is 1 unit (0x01). + configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, POWER_CONFIGURATION_BATTERY_VOLTAGE_ATTRIBUTE, DataType.UINT8, 30, 21600, 0x01/*100mv*1*/) + + configCmds += zigbee.configureReporting(OCCUPANCY_SENSING_CLUSTER, OCCUPANCY_SENSING_OCCUPANCY_ATTRIBUTE, DataType.BITMAP8, 1, 600, 1) + configCmds += zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 0, 0xffff, null) + return configCmds + refresh() +} From 78747fa5a3b42a0c801f1095f8f7521da968ba42 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Mon, 5 Sep 2022 18:26:06 +0800 Subject: [PATCH 180/184] WWST-7986, WWST-7980 (#78929) * DG Light * DG Light * DG Light --- .../i18n/messages.properties | 16 ++++++++++++++++ .../zigbee-white-color-temperature-bulb.groovy | 5 +++++ 2 files changed, 21 insertions(+) create mode 100644 devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/i18n/messages.properties diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/i18n/messages.properties new file mode 100644 index 00000000000..7a99c7e68fa --- /dev/null +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/i18n/messages.properties @@ -0,0 +1,16 @@ +# 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. + +# Chinese +'''DG Light'''.zh-cn=DG智能灯 diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index b2e1aca9909..c6b9462439b 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -34,6 +34,11 @@ metadata { // Generic fingerprint profileId: "0104", deviceId: "010C", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic Color Temperature Light + // DuraGreen + fingerprint profileId: "0104", deviceId: "010C", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003, 0019", manufacturer: "DURAGREEN", model: "DG-CW-02", deviceJoinName: "DG Light" //DuraGreen Track Light + fingerprint profileId: "0104", deviceId: "010C", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003, 0019", manufacturer: "DURAGREEN", model: "DG-CW-01", deviceJoinName: "DG Light" //DuraGreen LED Strip + fingerprint profileId: "0104", deviceId: "010C", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003, 0019", manufacturer: "DURAGREEN", model: "DG-CCT-01", deviceJoinName: "DG Light" //DuraGreen Down Light + // ABL fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "ABL-LIGHT-Z-001", deviceJoinName: "Juno Connect", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-001" //Wafer fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Juno", model: "ABL-LIGHT-Z-001", deviceJoinName: "Juno Connect", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-001" From 28d1f9f5264c9ad112c686b08ecfecd39701eee6 Mon Sep 17 00:00:00 2001 From: LUZhanchang <86645710+LUZhanchang@users.noreply.github.com> Date: Thu, 8 Dec 2022 16:50:07 +0800 Subject: [PATCH 181/184] Wwst 8008 (#79403) * Totem door lock * Totem door lock * modify device join name * modify device join name --- .../zigbee-lock.src/i18n/messages.properties | 16 ++++++++++++++++ .../zigbee-lock.src/zigbee-lock.groovy | 2 ++ 2 files changed, 18 insertions(+) create mode 100644 devicetypes/smartthings/zigbee-lock.src/i18n/messages.properties diff --git a/devicetypes/smartthings/zigbee-lock.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-lock.src/i18n/messages.properties new file mode 100644 index 00000000000..c2b1244f979 --- /dev/null +++ b/devicetypes/smartthings/zigbee-lock.src/i18n/messages.properties @@ -0,0 +1,16 @@ +# 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. + +# Chinese +'''TOTEM Door Lock'''.zh-cn=TOTEM智能门锁 diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index 2121d9d531a..09e9b55abe3 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -28,6 +28,8 @@ metadata { capability "Health Check" fingerprint profileId: "0104", inClusters: "0000,0001,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Deadbolt Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0101", outClusters: "0019", manufacturer: "TOTEM", model: "H60/H90", deviceJoinName: "TOTEM Door Lock" //TOTEM Door lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0101", outClusters: "0019", manufacturer: "TOTEM", model: "P30", deviceJoinName: "TOTEM Door Lock" //TOTEM Door lock fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Lever Lock fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Door Lock" //Yale Push Button Deadbolt Lock fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Deadbolt Lock From 5550e3d6b345a73fb3ce7c8992ca3d0d7ee648e8 Mon Sep 17 00:00:00 2001 From: greens Date: Fri, 20 Jan 2023 12:14:09 -0800 Subject: [PATCH 182/184] Update Circle deploy script with new S3 security --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3dbfd1df712..2f93e152ab8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,19 +19,19 @@ jobs: <<: *defaults steps: - checkout - - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_DEV" + - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_DEV" -PawsAccessKey="$S3_IAM_PREPROD_USERNAME" -PawsSecretKey="$S3_IAM_PREPROD_PASSWORD" - run: ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL" --stacktrace deploy-stage: <<: *defaults steps: - checkout - - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_STAGE" + - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_STAGE" -PawsAccessKey="$S3_IAM_PREPROD_USERNAME" -PawsSecretKey="$S3_IAM_PREPROD_PASSWORD" - run: ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL_STAGE" --stacktrace deploy-accept: <<: *defaults steps: - checkout - - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_ACCEPT" + - run: ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_ACCEPT" -PawsAccessKey="$S3_IAM_ACCEPTANCE_USERNAME" -PawsSecretKey="$S3_IAM_ACCEPTANCE_PASSWORD" - run: ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL_ACCEPT" --stacktrace workflows: version: 2 From b4c0cd2b1823226ac022056a940341d50a35f529 Mon Sep 17 00:00:00 2001 From: Ryan Greyling Date: Mon, 12 Jun 2023 14:54:31 -0500 Subject: [PATCH 183/184] PRT-1088-Vietnam-Copyright --- .../smart-care-daily-routine.groovy | 16 ++++++++-------- .../smart-care-detect-motion.groovy | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/smartapps/smartthings/smart-care-daily-routine.src/smart-care-daily-routine.groovy b/smartapps/smartthings/smart-care-daily-routine.src/smart-care-daily-routine.groovy index fa2ac9c3db2..c5f77cdaf8b 100644 --- a/smartapps/smartthings/smart-care-daily-routine.src/smart-care-daily-routine.groovy +++ b/smartapps/smartthings/smart-care-daily-routine.src/smart-care-daily-routine.groovy @@ -35,10 +35,10 @@ preferences { } def disclaimerPage() { - def disclaimerText = "SMARTTHINGS INC. SMART CARE SUPPLEMENTAL TERMS AND DISCLAIMER\n" + - "SmartThings Inc. is not an emergency medical response service of any kind and does not provide " + + def disclaimerText = "Samsung Electronics Co., LTD. SMART CARE SUPPLEMENTAL TERMS AND DISCLAIMER\n" + + "Samsung Electronics Co., LTD. is not an emergency medical response service of any kind and does not provide " + "medical or health-related advice, which should be obtained from qualified medical personnel. " + - "SmartThings Inc., the contents of the app (such as text, graphics, images, videos, data and "+ + "Samsung Electronics Co., LTD., the contents of the app (such as text, graphics, images, videos, data and "+ "information contained therein) and such materials obtained from third parties are provided for " + "information purposes only and are not substitutes for professional medical advice, diagnosis, " + "examination, or treatment by a health care provider. If you think you or a loved one has a medical " + @@ -52,12 +52,12 @@ def disclaimerPage() { "avoid, or delay obtaining medical or health-related advice " + "relating to treatment or standard of care because of information contained in or transmitted through the app. "+ "RELIANCE ON ANY INFORMATION PROVIDED BY THE APP OR OTHER THIRD-PARTY PLATFORMS IS SOLELY AT YOUR OWN RISK.\n\n" + - "While SmartThings Inc. strives to make the information on the app as timely and accurate as possible, " + - "SmartThings Inc. makes no claims, promises, or guarantees about the accuracy, completeness, " + - "or adequacy of the content or information on the app. SmartThings Inc. expressly disclaims liability for any errors "+ + "While Samsung Electronics Co., LTD. strives to make the information on the app as timely and accurate as possible, " + + "Samsung Electronics Co., LTD. makes no claims, promises, or guarantees about the accuracy, completeness, " + + "or adequacy of the content or information on the app. Samsung Electronics Co., LTD. expressly disclaims liability for any errors "+ "and omissions in content or for the availability of content on the app. " + - "SmartThings Inc. will not be liable for any losses, injuries, or damages arising from the display " + - "or use of content on the app. SMARTTHINGS INC., ITS OFFICERS, " + + "Samsung Electronics Co., LTD. will not be liable for any losses, injuries, or damages arising from the display " + + "or use of content on the app. Samsung Electronics Co., LTD., ITS OFFICERS, " + "EMPLOYEES AND AGENTS DO NOT ACCEPT LIABILITY HOWEVER ARISING, INCLUDING LIABILITY FOR NEGLIGENCE, " + "FOR ANY LOSS RESULTING FROM THE USE OF OR RELIANCE UPON THE INFORMATION AND/OR SERVICES AT ANY TIME." diff --git a/smartapps/smartthings/smart-care-detect-motion.src/smart-care-detect-motion.groovy b/smartapps/smartthings/smart-care-detect-motion.src/smart-care-detect-motion.groovy index f51655a97fb..0742f45ca1a 100644 --- a/smartapps/smartthings/smart-care-detect-motion.src/smart-care-detect-motion.groovy +++ b/smartapps/smartthings/smart-care-detect-motion.src/smart-care-detect-motion.groovy @@ -32,10 +32,10 @@ preferences { } def disclaimerPage() { - def disclaimerText = "SMARTTHINGS INC. SMART CARE SUPPLEMENTAL TERMS AND DISCLAIMER\n" + - "SmartThings Inc. is not an emergency medical response service of any kind and does not provide " + + def disclaimerText = "Samsung Electronics Co., LTD. SMART CARE SUPPLEMENTAL TERMS AND DISCLAIMER\n" + + "Samsung Electronics Co., LTD. is not an emergency medical response service of any kind and does not provide " + "medical or health-related advice, which should be obtained from qualified medical personnel. " + - "SmartThings Inc., the contents of the app (such as text, graphics, images, videos, data and "+ + "Samsung Electronics Co., LTD., the contents of the app (such as text, graphics, images, videos, data and "+ "information contained therein) and such materials obtained from third parties are provided for " + "information purposes only and are not substitutes for professional medical advice, diagnosis, " + "examination, or treatment by a health care provider. If you think you or a loved one has a medical " + @@ -49,12 +49,12 @@ def disclaimerPage() { "avoid, or delay obtaining medical or health-related advice " + "relating to treatment or standard of care because of information contained in or transmitted through the app. "+ "RELIANCE ON ANY INFORMATION PROVIDED BY THE APP OR OTHER THIRD-PARTY PLATFORMS IS SOLELY AT YOUR OWN RISK.\n\n" + - "While SmartThings Inc. strives to make the information on the app as timely and accurate as possible, " + - "SmartThings Inc. makes no claims, promises, or guarantees about the accuracy, completeness, " + - "or adequacy of the content or information on the app. SmartThings Inc. expressly disclaims liability for any errors "+ + "While Samsung Electronics Co., LTD. strives to make the information on the app as timely and accurate as possible, " + + "Samsung Electronics Co., LTD. makes no claims, promises, or guarantees about the accuracy, completeness, " + + "or adequacy of the content or information on the app. Samsung Electronics Co., LTD. expressly disclaims liability for any errors "+ "and omissions in content or for the availability of content on the app. " + - "SmartThings Inc. will not be liable for any losses, injuries, or damages arising from the display " + - "or use of content on the app. SMARTTHINGS INC., ITS OFFICERS, " + + "Samsung Electronics Co., LTD. will not be liable for any losses, injuries, or damages arising from the display " + + "or use of content on the app. Samsung Electronics Co., LTD., ITS OFFICERS, " + "EMPLOYEES AND AGENTS DO NOT ACCEPT LIABILITY HOWEVER ARISING, INCLUDING LIABILITY FOR NEGLIGENCE, " + "FOR ANY LOSS RESULTING FROM THE USE OF OR RELIANCE UPON THE INFORMATION AND/OR SERVICES AT ANY TIME." From 34b7178fddc413066f550dd58e6cedeebdcc795a Mon Sep 17 00:00:00 2001 From: Saul Flores Date: Wed, 21 Jun 2023 17:09:13 -0600 Subject: [PATCH 184/184] docs: update copyright company name --- .../tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy | 2 +- .../tile-basic-colorwheel.src/tile-basic-colorwheel.groovy | 2 +- .../tile-ux/tile-basic-presence.src/tile-basic-presence.groovy | 2 +- .../tile-ux/tile-basic-slider.src/tile-basic-slider.groovy | 2 +- .../tile-ux/tile-basic-standard.src/tile-basic-standard.groovy | 2 +- .../tile-ux/tile-basic-value.src/tile-basic-value.groovy | 2 +- .../tile-multiattribute-generic.groovy | 2 +- .../tile-multiattribute-lighting.groovy | 2 +- .../tile-multiattribute-mediaplayer.groovy | 2 +- .../tile-multiattribute-thermostat.groovy | 2 +- .../tile-multiattribute-videoplayer.groovy | 2 +- smartapps/smartthings/mood-cube.src/mood-cube.groovy | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy b/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy index 0af22a23af4..04667d32bfe 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy b/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy index 102f9e3f294..4a7ce00814f 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy b/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy index 392866c2fe3..c62687368a8 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy b/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy index 68872b512f1..c1f4cf55ea5 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy b/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy index 21fcea6c544..05db6ff7810 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy b/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy index e1efb8a1dd9..e1f32441e82 100644 --- a/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy +++ b/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy index 6ba0e1c3e8f..a4eaa34b322 100644 --- a/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy index 81e9121c657..1533a5d15e3 100644 --- a/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy index 2ad41f42b87..56759a27388 100644 --- a/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy index a784ac57da9..4889190b35a 100644 --- a/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy index c6dc80da0ff..7e684c578ed 100644 --- a/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2016 SmartThings, Inc. + * Copyright 2016 Samsung Electronics Co., LTD. * * 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: diff --git a/smartapps/smartthings/mood-cube.src/mood-cube.groovy b/smartapps/smartthings/mood-cube.src/mood-cube.groovy index 1c7b6cf5806..bef5bf06f47 100644 --- a/smartapps/smartthings/mood-cube.src/mood-cube.groovy +++ b/smartapps/smartthings/mood-cube.src/mood-cube.groovy @@ -1,7 +1,7 @@ /** * Mood Cube * - * Copyright 2014 SmartThings, Inc. + * Copyright 2014 Samsung Electronics Co., LTD. * * 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: