Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- *
- * Aeotec Inc Dual Nano Switch without Energy Reading
- *
- * github: Eric Maycock (erocm123)
- * Date: 2018-01-02
- * Copyright Eric Maycock
- *
- * Includes all configuration parameters and ease of advanced configuration.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
- * for the specific language governing permissions and limitations under the License.
- *
- */
- metadata {
- definition (name: "Aeotec Inc Dual Nano Switch (ZW140)", namespace: "erocm123", author: "Eric Maycock") {
- capability "Actuator"
- capability "Switch"
- capability "Polling"
- capability "Configuration"
- capability "Refresh"
- capability "Power Meter"
- capability "Energy Meter"
- capability "Temperature Measurement"
- capability "Health Check"
- command "childOn"
- command "childOff"
- command "childRefresh"
- fingerprint mfr: "0086", model: "008C" // Aeon brand
- //inClusters:"0x5E,0x25,0x27,0x32,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A"
- }
- simulator {
- }
- preferences {
- input description: "Once you change values on this page, the corner of the \"configuration\" icon will change orange until all configuration parameters are updated.", title: "Settings", displayDuringSetup: false, type: "paragraph", element: "paragraph"
- generate_preferences(configuration_model())
- }
- }
- def parse(String description) {
- def result = []
- def cmd = zwave.parse(description)
- if (cmd) {
- result += zwaveEvent(cmd)
- logging("Parsed ${cmd} to ${result.inspect()}", 1)
- } else {
- logging("Non-parsed event: ${description}", 2)
- }
- def statusTextmsg = ""
- result.each {
- if ((it instanceof Map) == true && it.find{ it.key == "name" }?.value == "power") {
- statusTextmsg = "${it.value} W ${device.currentValue('energy')? device.currentValue('energy') : "0"} kWh"
- }
- if ((it instanceof Map) == true && it.find{ it.key == "name" }?.value == "energy") {
- statusTextmsg = "${device.currentValue('power')? device.currentValue('power') : "0"} W ${it.value} kWh"
- }
- }
- if (statusTextmsg != "") sendEvent(name:"statusText", value:statusTextmsg, displayed:false)
- return result
- }
- def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
- logging("BasicReport ${cmd}", 2)
- }
- def zwaveEvent(hubitat.zwave.commands.basicv1.BasicSet cmd) {
- logging("BasicSet ${cmd}", 2)
- def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
- def cmds = []
- cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
- cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
- return [result, response(commands(cmds))] // returns the result of reponse()
- }
- def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep=null) {
- logging("SwitchBinaryReport ${cmd} , ${ep}", 2)
- if (ep) {
- def childDevice = childDevices.find{it.deviceNetworkId == "$device.deviceNetworkId-ep$ep"}
- if (childDevice)
- childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
- } else {
- def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
- def cmds = []
- cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
- cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
- return [result, response(commands(cmds))] // returns the result of reponse()
- }
- }
- def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
- logging("MultiChannelCmdEncap ${cmd}", 2)
- def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1])
- if (encapsulatedCommand) {
- zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
- }
- }
- def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
- logging("ManufacturerSpecificReport ${cmd}", 2)
- def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
- logging("msr: $msr", 2)
- updateDataValue("MSR", msr)
- }
- def zwaveEvent(hubitat.zwave.Command cmd) {
- // This will capture any commands not handled by other instances of zwaveEvent
- // and is recommended for development so you can see every command the device sends
- logging("Unhandled Event: ${cmd}", 2)
- }
- def on() {
- logging("on()", 1)
- commands([
- zwave.switchAllV1.switchAllOn(),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
- ])
- }
- def off() {
- logging("off()", 1)
- commands([
- zwave.switchAllV1.switchAllOff(),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
- ])
- }
- def childOn(String dni) {
- logging("childOn($dni)", 1)
- def cmds = []
- cmds << new hubitat.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
- cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
- cmds
- }
- def childOff(String dni) {
- logging("childOff($dni)", 1)
- def cmds = []
- cmds << new hubitat.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
- cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
- cmds
- }
- def childRefresh(String dni) {
- logging("childRefresh($dni)", 1)
- def cmds = []
- cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
- cmds
- }
- def poll() {
- logging("poll()", 1)
- commands([
- encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
- ])
- }
- def refresh() {
- logging("refresh()", 1)
- commands([
- encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
- encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
- ])
- }
- def ping() {
- logging("ping()", 1)
- refresh()
- }
- def installed() {
- logging("installed()", 1)
- command(zwave.manufacturerSpecificV1.manufacturerSpecificGet())
- createChildDevices()
- }
- def configure() {
- logging("configure()", 1)
- def cmds = []
- cmds = update_needed_settings()
- if (cmds != []) commands(cmds)
- }
- def updated() {
- logging("updated()", 1)
- if (!childDevices) {
- createChildDevices()
- } else if (device.label != state.oldLabel) {
- childDevices.each {
- if (it.label == "${state.oldLabel} (Q${channelNumber(it.deviceNetworkId)})") {
- def newLabel = "${device.displayName} (Q${channelNumber(it.deviceNetworkId)})"
- it.setLabel(newLabel)
- }
- }
- state.oldLabel = device.label
- }
- def cmds = []
- cmds = update_needed_settings()
- sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
- sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
- if (cmds != []) commands(cmds)
- }
- def generate_preferences(configuration_model) {
- def configuration = new XmlSlurper().parseText(configuration_model)
- configuration.Value.each {
- if(it.@hidden != "true" && it.@disabled != "true") {
- switch(it.@type) {
- case ["number"]:
- input "${it.@index}", "number",
- title:"${it.@label}\n" + "${it.Help}",
- range: "${it.@min}..${it.@max}",
- defaultValue: "${it.@value}",
- displayDuringSetup: "${it.@displayDuringSetup}"
- break
- case "list":
- def items = []
- it.Item.each { items << ["${it.@value}":"${it.@label}"] }
- input "${it.@index}", "enum",
- title:"${it.@label}\n" + "${it.Help}",
- defaultValue: "${it.@value}",
- displayDuringSetup: "${it.@displayDuringSetup}",
- options: items
- break
- case "decimal":
- input "${it.@index}", "decimal",
- title:"${it.@label}\n" + "${it.Help}",
- range: "${it.@min}..${it.@max}",
- defaultValue: "${it.@value}",
- displayDuringSetup: "${it.@displayDuringSetup}"
- break
- case "boolean":
- input "${it.@index}", "boolean",
- title:"${it.@label}\n" + "${it.Help}",
- defaultValue: "${it.@value}",
- displayDuringSetup: "${it.@displayDuringSetup}"
- break
- }
- }
- }
- }
- /* Code has elements from other community source @CyrilPeponnet (Z-Wave Parameter Sync). */
- def update_current_properties(cmd) {
- def currentProperties = state.currentProperties ?: [:]
- currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
- def parameterSettings = new XmlSlurper().parseText(configuration_model()).Value.find{it.@index == "${cmd.parameterNumber}"}
- if (settings."${cmd.parameterNumber}" != null || parameterSettings.@hidden == "true") {
- if (convertParam(cmd.parameterNumber, parameterSettings.@hidden != "true"? settings."${cmd.parameterNumber}" : parameterSettings.@value) == cmd2Integer(cmd.configurationValue)) {
- sendEvent(name:"needUpdate", value:"NO", displayed:false, isStateChange: true)
- } else {
- sendEvent(name:"needUpdate", value:"YES", displayed:false, isStateChange: true)
- }
- }
- state.currentProperties = currentProperties
- }
- def update_needed_settings() {
- def cmds = []
- def currentProperties = state.currentProperties ?: [:]
- def configuration = new XmlSlurper().parseText(configuration_model())
- def isUpdateNeeded = "NO"
- //cmds << zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,1])
- //cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 1)
- cmds << zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId)
- cmds << zwave.associationV2.associationGet(groupingIdentifier: 1)
- configuration.Value.each {
- if ("${it.@setting_type}" == "zwave" && it.@disabled != "true") {
- if (currentProperties."${it.@index}" == null) {
- if (it.@setonly == "true") {
- logging("Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}"), 2)
- def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
- cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Cmd(convertedConfigurationValue, it.@byteSize.toInteger()), parameterNumber: it.@index.toInteger(), size: it.@byteSize.toInteger())
- } else {
- isUpdateNeeded = "YES"
- logging("Current value of parameter ${it.@index} is unknown", 2)
- cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
- }
- } else if ((settings."${it.@index}" != null || "${it.@hidden}" == "true") && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), "${it.@hidden}" != "true"? settings."${it.@index}" : "${it.@value}")) {
- isUpdateNeeded = "YES"
- logging("Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), "${it.@hidden}" != "true"? settings."${it.@index}" : "${it.@value}"), 2)
- def convertedConfigurationValue = convertParam(it.@index.toInteger(), "${it.@hidden}" != "true"? settings."${it.@index}" : "${it.@value}")
- cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Cmd(convertedConfigurationValue, it.@byteSize.toInteger()), parameterNumber: it.@index.toInteger(), size: it.@byteSize.toInteger())
- cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
- }
- }
- }
- sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)
- return cmds
- }
- def convertParam(number, value) {
- def parValue
- switch (number) {
- case 110:
- if (value < 0)
- parValue = value * -1 + 1000
- else
- parValue = value
- break
- default:
- parValue = value
- break
- }
- return parValue.toInteger()
- }
- private def logging(message, level) {
- log.debug message
- /*if (logLevel != "0") {
- switch (logLevel) {
- case "1":
- if (level > 1)
- log.debug "$message"
- break
- case "99":
- log.debug "$message"
- break
- }
- }*/
- }
- /**
- * Convert byte values to integer
- */
- def cmd2Integer(array) {
- switch(array.size()) {
- case 1:
- array[0]
- break
- case 2:
- ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
- break
- case 3:
- ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
- break
- case 4:
- ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
- break
- }
- }
- def integer2Cmd(value, size) {
- switch(size) {
- case 1:
- [value]
- break
- case 2:
- def short value1 = value & 0xFF
- def short value2 = (value >> 8) & 0xFF
- [value2, value1]
- break
- case 3:
- def short value1 = value & 0xFF
- def short value2 = (value >> 8) & 0xFF
- def short value3 = (value >> 16) & 0xFF
- [value3, value2, value1]
- break
- case 4:
- def short value1 = value & 0xFF
- def short value2 = (value >> 8) & 0xFF
- def short value3 = (value >> 16) & 0xFF
- def short value4 = (value >> 24) & 0xFF
- [value4, value3, value2, value1]
- break
- }
- }
- def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
- update_current_properties(cmd)
- logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'", 2)
- }
- private encap(cmd, endpoint) {
- if (endpoint) {
- zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd)
- } else {
- cmd
- }
- }
- private command(hubitat.zwave.Command cmd) {
- if (state.sec) {
- zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
- } else {
- cmd.format()
- }
- }
- private commands(commands, delay=1000) {
- delayBetween(commands.collect{ command(it) }, delay)
- }
- private channelNumber(String dni) {
- dni.split("-ep")[-1] as Integer
- }
- private void createChildDevices() {
- state.oldLabel = device.label
- try {
- for (i in 1..2) {
- addChildDevice("Metering Switch Child Device", "${device.deviceNetworkId}-ep${i}",
- [completedSetup: true, label: "${device.displayName} (Q${i})",
- isComponent: false, componentName: "ep$i", componentLabel: "Output $i"])
- }
- } catch (e) {
- log.debug e
- runIn(2, "sendAlert")
- }
- }
- private sendAlert() {
- sendEvent(
- descriptionText: "Child device creation failed. Please make sure that the \"Metering Switch Child Device\" is installed and published.",
- eventType: "ALERT",
- name: "childDeviceCreation",
- value: "failed",
- displayed: true,
- )
- }
- def configuration_model() {
- '''
- <configuration>
- <Value type="list" byteSize="1" index="4" label="Overheat Protection. " min="0" max="1" value="0" setting_type="zwave" fw="">
- <Help>
- The output load will automatically turn off after 30 seconds if temperature is over 100 C.
- 0 - Disable
- 1 - Enable
- Range: 0~1
- Default: 0 (Previous State)
- </Help>
- <Item label="Disable" value="0" />
- <Item label="Enable" value="1" />
- </Value>
- <Value type="list" byteSize="1" index="20" label="After a power outage" min="0" max="2" value="0" setting_type="zwave" fw="">
- <Help>
- Configure the output load status after re-power from a power outage.
- 0 - Last status before power outage.
- 1 - Always ON
- 2 - Always OFF
- Range: 0~2
- Default: 0 (Previous State)
- </Help>
- <Item label="Last Status" value="0" />
- <Item label="Always On" value="1" />
- <Item label="Always Off" value="2" />
- </Value>
- <Value type="list" byteSize="1" index="80" label="Instant Notification" min="0" max="3" value="2" setting_type="zwave" fw="">
- <Help>
- Notification report of status change sent to Group Assocation #1 when state of output load changes. Used to instantly update status to your gateway typically.
- 0 - Nothing
- 1 - Hail CC (uses more bandwidth)
- 2 - Basic Report CC
- 3 - Hail CC when external switch is used to change status of either load.
- Range: 0~3
- Default: 2 (Previous State)
- </Help>
- <Item label="None" value="0" />
- <Item label="Hail CC" value="1" />
- <Item label="Basic Report CC" value="2" />
- <Item label="Hail when External Switch used" value="3" />
- </Value>
- <Value type="list" byteSize="1" index="81" label="Notification send with S1 Switch" min="0" max="1" value="1" setting_type="zwave" fw="">
- <Help>
- To set which notification would be sent to the associated nodes in association group 3 when using the external switch 1 to switch the loads.
- 0 = Send Nothing
- 1 = Basic Set CC.
- Range: 0~1
- Default: 1 (Previous State)
- </Help>
- <Item label="Nothing" value="0" />
- <Item label="Basic Set CC" value="1" />
- </Value>
- <Value type="list" byteSize="1" index="82" label="Notification send with S2 Switch" min="0" max="1" value="1" setting_type="zwave" fw="">
- <Help>
- To set which notification would be sent to the associated nodes in association group 4 when using the external switch 2 to switch the loads.
- 0 = Send Nothing
- 1 = Basic Set CC.
- Range: 0~1
- Default: 1 (Previous State)
- </Help>
- <Item label="Nothing" value="0" />
- <Item label="Basic Set CC" value="1" />
- </Value>
- <Value type="list" byteSize="1" index="83" label="State of Internal LED use" min="0" max="2" value="0" setting_type="zwave" fw="">
- <Help>
- Configure the state of LED when it is in 3 modes below:
- 0 = Energy mode. The LED will follow the status (on/off).
- 1 = Momentary indicate mode. When the state of Switch’s load changed, the LED will follow the status (on/off) of its load, but the LED will turn off after 5 seconds if there is no any switch action.
- 2 = Night light mode. The LED will remain ON state.
- </Help>
- <Item label="Energy Mode" value="0" />
- <Item label="Momentary Mode" value="1" />
- <Item label="Night Light Mode" value="2" />
- </Value>
- <Value type="list" byteSize="1" index="120" label="External Switch S1 Setting" min="0" max="4" value="0" setting_type="zwave" fw="">
- <Help>
- Configure the external switch mode for S1 via Configuration Set.
- 0 = Unidentified mode.
- 1 = 2-state switch mode.
- 2 = 3-way switch mode.
- 3 = momentary switch button mode.
- 4 = Enter automatic identification mode. //can enter this mode by tapping internal button 4x times within 2 seconds.
- Note: When the mode is determined, this mode value will not be reset after exclusion.
- Range: 0~4
- Default: 0 (Previous State)
- </Help>
- <Item label="Unidentified" value="0" />
- <Item label="2-State Switch Mode" value="1" />
- <Item label="3-way Switch Mode" value="2" />
- <Item label="Momentary Push Button Mode" value="3" />
- <Item label="Automatic Identification" value="4" />
- </Value>
- <Value type="list" byteSize="1" index="121" label="External Switch S2 Setting" min="0" max="4" value="0" setting_type="zwave" fw="">
- <Help>
- Configure the external switch mode for S2 via Configuration Set.
- 0 = Unidentified mode.
- 1 = 2-state switch mode.
- 2 = 3-way switch mode.
- 3 = momentary switch button mode.
- 4 = Enter automatic identification mode. //can enter this mode by tapping internal button 6x times within 2 seconds.
- Note: When the mode is determined, this mode value will not be reset after exclusion.
- Range: 0~4
- Default: 0 (Previous State)
- </Help>
- <Item label="Unidentified" value="0" />
- <Item label="2-State Switch Mode" value="1" />
- <Item label="3-way Switch Mode" value="2" />
- <Item label="Momentary Push Button Mode" value="3" />
- <Item label="Automatic Identification" value="4" />
- </Value>
- </configuration>
- '''
- }
- //For Later: 83-87, 123
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement