That is some interesting code (see a couple of ideas that I need to examine more closely). Don’t see anything obvious, could you set the logging level to debug and repeat one of the actions that lead to the error. Thanks.
Sure thing.. let me know if this helps.
dev:9312022-04-16 10:45:12.601 pm errororg.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack: No signature of method: user_driver_codahq_hubitat_Aeon_WallMote_914.release() is applicable for argument types: (java.math.BigDecimal) values: [1]
Possible solutions: isCase(java.lang.Object) (method release)
dev:9312022-04-16 10:45:00.298 pm debugParameter 5 will be updated to 65280
dev:9312022-04-16 10:45:00.262 pm debugGetting Manufacturer Specific Info
dev:9312022-04-16 10:45:00.259 pm debugSetting association group 9
dev:9312022-04-16 10:45:00.216 pm debugSetting association group 7
dev:9312022-04-16 10:45:00.202 pm debugupdated() is being called
Hmmmm, was expecting to see this running through the parse method but not getting there in this instance. Outside of these errors, is the driver working as expected/needed?
Other than the button push, hold, release from the driver it does seem to work on the device side.
Given that see if this works:
Modified Code
/**
* Aeon WallMote (with slide functionality)
*
* Copyright 2019 Ben Rimmasch
*
* 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.
*
* Aeon WallMote Quad
* https://aeotec.freshdesk.com/support/solutions/articles/6000162392-wallmote-quad-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000166184-wallmote-quad-technical-specifications-
* https://aeotec.freshdesk.com/support/solutions/articles/6000187144-wallmote-quad-group-association-explanation-for-direct-communication-
*
* Aeon WallMote Dual
* https://aeotec.freshdesk.com/support/solutions/articles/6000176572-wallmote-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000176570-wallmote-technical-specification-
* No group associations document but the above document for quad is applicable
*
* Author: Ben Rimmasch (codahq)
* Original Author: Eric Maycock (erocm123)
* Date: 2019-01-23
*
* Change Log:
* 2020-01-23: Initial
* 2020-01-26: Fixed logging for those that switch to this driver and have never set a logging level yet
* Change to two pushed buttons instead of one button that is pushed and held
* Bug fixes for some events
* Handled the event sent when a user initiates a connectivity health test from the remote's button
* Fixed firmware reporting for current Hubitat command classes
*
*
* Previous Author's Change Log:
* 2017-06-19: Added check to only send color change config for three wakeups. Editing preferences
* and hitting "done" will reset the counter. This is an attempt to prevent freezing
* caused by updating preferences.
*/
metadata {
definition (name: "Aeon WallMote", namespace: "codahq-hubitat", author: "Ben Rimmasch",
importUrl: "https://raw.githubusercontent.com/codahq/hubitat_codahq/master/devicestypes/aeon-wallmote.groovy") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "ReleasableButton"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "sequenceNumber", "number"
attribute "needUpdate", "string"
fingerprint mfr: "0086", prod: "0102", model: "0082", deviceJoinName: "Aeon WallMote"
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x73,0x98,0x86,0x85,0x59,0x8E,0x60,0x72,0x5A,0x84,0x5B,0x71,0x70,0x80,0x7A", outClusters: "0x25,0x26" // secure inclusion
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x85,0x59,0x8E,0x60,0x86,0x70,0x72,0x5A,0x73,0x84,0x80,0x5B,0x71,0x7A", outClusters: "0x25,0x26"
}
preferences {
input description: "Once you change values on this page, the attribute value \"needUpdate\" will show \"YES\" until all configuration parameters are updated.", title: "<b>Settings</b>", displayDuringSetup: false, type: "paragraph", element: "paragraph"
generate_preferences(configuration_model())
}
}
def parse(String description) {
logDebug "parse(String description)"
logTrace "description: $description"
def results = []
if (description.startsWith("Err")) {
results = createEvent(descriptionText:description, displayed:true)
}
else {
def cmd = zwave.parse(description, [0x2B: 1, 0x80: 1, 0x84: 1])
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
return results
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd)"
logTrace "cmd: $cmd"
def result = []
//if not held buttons and button slide is enabled
if (!getHeldButtons() && settings."3" == "1") {
switch (cmd.upDown) {
case false: // Up
logTrace "Slide up"
result << buttonEvent(device.currentValue("numberOfButtons") - 1, "pushed")
break
case true: // Down
logTrace "Slide down"
result << buttonEvent(device.currentValue("numberOfButtons"), "pushed")
break
default:
logDebug "Unhandled SwitchMultilevelStartLevelChange: ${cmd}"
break
}
}
result
}
def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd)"
logTrace "cmd: $cmd"
def result = []
sendEvent(name: "sequenceNumber", value: cmd.sequenceNumber, displayed:false)
switch (cmd.keyAttributes) {
case 0:
result << buttonEvent(cmd.sceneNumber, "pushed")
break
case 1: // released
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (!settings.holdMode || settings.holdMode == "2") result << buttonEvent(cmd.sceneNumber, "held")
result << buttonEvent(cmd.sceneNumber, "released")
break
case 2: // held
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (settings.holdMode == "1") result << buttonEvent(cmd.sceneNumber, "held")
break
default:
logDebug "Unhandled CentralSceneNotification: ${cmd}"
break
}
result
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x5B: 1, 0x20: 1, 0x31: 5, 0x30: 2, 0x84: 1, 0x70: 1])
state.sec = 1
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)"
logTrace "cmd: $cmd"
state.wakeInterval = cmd.seconds
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)"
logTrace "cmd: $cmd"
logInfo "Device ${device.displayName} woke up"
def request = update_needed_settings()
request << zwave.versionV1.versionGet()
if (!state.lastBatteryReport || (now() - state.lastBatteryReport) / 60000 >= 60 * 24) {
logDebug "Over 24hr since last battery report. Requesting report"
request << zwave.batteryV1.batteryGet()
}
state.wakeCount? (state.wakeCount = state.wakeCount + 1) : (state.wakeCount = 2)
if (request != []) {
response(commands(request) + ["delay 5000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
else {
logDebug "No commands to send"
response([zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
}
def buttonEvent(button, name) {
def msg = "$device.displayName button $button was $name"
logInfo msg
createEvent(name: name, value: button, descriptionText: msg, isStateChange: true)
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd)"
logTrace "cmd: $cmd"
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
state.lastBatteryReport = now()
createEvent(map)
}
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd)"
logTrace "cmd: $cmd"
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
updateDataValue("fw", fw)
if (state.MSR == "003B-6341-5044") {
updateDataValue("ver", "${cmd.firmware0Version >> 4}.${cmd.firmware0SubVersion & 0xF}")
}
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd)"
logTrace "cmd: $cmd"
logInfo "Connectivity testing performed by user at remote..."
}
def zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwaveEvent: ${cmd}"
}
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logDebug "msr: $msr"
updateDataValue("MSR", msr)
}
def installed() {
log.info "...Aeon WallMote Installed..."
configure()
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated() {
logDebug "updated() is being called"
state.wakeCount = 1
def cmds = update_needed_settings()
sendEvent(name: "checkInterval", value: 2 * 60 * 12 * 60 + 5 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
if (cmds != []) response(commands(cmds))
}
def configure() {
logDebug "Configuring Device For Use"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
if (cmds != []) commands(cmds)
}
private getNumButtons() {
return settings.buttons ? (settings."3" == "1" ? settings.buttons.toInteger() + 2 : settings.buttons) : (settings."3" ? 4 + 2 : 4)
}
def ping() {
logDebug "ping()"
log.warn "Battery Device - Not sending ping commands"
}
def generate_preferences(configuration_model) {
def configuration = new XmlSlurper().parseText(configuration_model)
configuration.Value.each {
switch(it.@type) {
case ["byte","short","four"]:
input "${it.@index}", "number", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "list":
def items = []
it.Item.each { items << ["${it.@value}": "${it.@label}"] }
input "${it.@index}", "enum", title:"<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}", options: items,
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "decimal":
input "${it.@index}", "decimal", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "boolean":
input "${it.@index}", "bool", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "string":
input "${it.@index}", "text", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
}
}
}
def update_current_properties(cmd) {
def currentProperties = state.currentProperties ?: [:]
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
if (settings."${cmd.parameterNumber}" != null) {
if (convertParam(cmd.parameterNumber, settings."${cmd.parameterNumber}") == 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"
if (state.wakeInterval == null || state.wakeInterval != 86400) {
logDebug "Setting Wake Interval to 86400"
cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId)
cmds << zwave.wakeUpV1.wakeUpIntervalGet()
}
if (settings."3" == "1") {
if (!state.association3 || state.association3 == "" || state.association3 == "1") {
logDebug "Setting association group 3"
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:3)
}
if (!state.association5 || state.association5 == "" || state.association5 == "1") {
logDebug "Setting association group 5"
cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:5)
}
if (!state.association7 || state.association7 == "" || state.association7 == "1") {
logDebug "Setting association group 7"
cmds << zwave.associationV2.associationSet(groupingIdentifier:7, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:7)
}
if (!state.association9 || state.association9 == "" || state.association9 == "1") {
logDebug "Setting association group 9"
cmds << zwave.associationV2.associationSet(groupingIdentifier:9, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:9)
}
}
if (state.MSR == null){
logDebug "Getting Manufacturer Specific Info"
cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet()
}
configuration.Value.each {
if ("${it.@setting_type}" == "zwave") {
if (currentProperties."${it.@index}" == null) {
if (it.@setonly == "true"){
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else {
isUpdateNeeded = "YES"
logDebug "Current value of parameter ${it.@index} is unknown"
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), settings."${it.@index}")) {
isUpdateNeeded = "YES"
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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) {
long parValue
switch (number) {
case 5:
switch (value) {
case "1":
parValue = 4278190080
break
case "2":
parValue = 16711680
break
case "3":
parValue = 65280
break
default:
parValue = value
break
}
break
default:
parValue = value.toLong()
break
}
return parValue
}
private def getHeldButtons() {
def heldButtons = (1..device.currentValue("numberOfButtons"))
heldButtons = heldButtons.find { button ->
state."${button}" == 2
}
logTrace "heldButtons $heldButtons"
return heldButtons
}
private logInfo(msg) {
if (settings.loggingLevel?.toInteger() >= 1) log.info msg
}
def logDebug(msg) {
if (settings.loggingLevel?.toInteger() >= 2) log.debug msg
}
def logTrace(msg) {
if (settings.loggingLevel?.toInteger() >= 3) log.trace msg
}
/**
* Convert 1 and 2 bytes values to integer
*/
def cmd2Integer(array) {
long value
if (array != [255, 0, 0, 0]){
switch(array.size()) {
case 1:
value = array[0]
break
case 2:
value = ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
break
case 3:
value = ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
break
case 4:
value = ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
break
}
}
else {
value = 4278190080
}
return value
}
def integer2Cmd(value, size) {
switch(size) {
case 1:
[value.toInteger()]
break
case 2:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
[value2.toInteger(), value1.toInteger()]
break
case 3:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
def short value3 = (value >> 16) & 0xFF
[value3.toInteger(), value2.toInteger(), value1.toInteger()]
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.toInteger(), value3.toInteger(), value2.toInteger(), value1.toInteger()]
break
}
}
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)
}
def configuration_model() {
'''
<configuration>
<Value type="list" byteSize="1" index="buttons" label="WallMote Model" min="2" max="4" value="" setting_type="preference" deviceId="" displayDuringSetup="true">
<Help>
Which model of WallMote is this?
</Help>
<Item label="Dual" value="2" />
<Item label="Quad" value="4" />
</Value>
<Value type="list" byteSize="1" index="1" label="Touch Sound" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch sound.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="2" label="Touch Vibration" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch vibration.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="3" label="Button Slide" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the function of button slide.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="4" index="5" label="LED Color" min="1" max="3" value="3" setting_type="zwave" deviceId="" setonly="true">
<Help>
To configure which color will be displayed when the button is pressed.<br/>
Default: Blue
</Help>
<Item label="Red" value="1" />
<Item label="Green" value="2" />
<Item label="Blue" value="3" />
</Value>
<Value type="list" byteSize="4" index="holdMode" label="Hold Mode" min="1" max="2" value="2" setting_type="preference" deviceId="">
<Help>
Multiple "held" events on botton hold? With this option, the controller will send a "held" event about every second while holding down a button. If set to No it will send a "held" event a single time when the button is released.<br/>
Default: No
</Help>
<Item label="No" value="2" />
<Item label="Yes" value="1" />
</Value>
<Value type="list" byteSize="1" index="loggingLevel" label="Logging Level?" min="0" max="3" value="0" setting_type="preference" deviceId="" required="true">
<Help>
Set the verbosity of the logs.
</Help>
<Item label="No Logging" value="0" />
<Item label="Descriptive Text" value="1" />
<Item label="Debug" value="2" />
<Item label="Trace" value="3" />
</Value>
</configuration>
'''
}
def push(btnNum) {
buttonEvent(btnNum.toInteger, "pushed")
}
def release(btnNum) {
buttonEvent(btnNum.toInteger, "released")
}
def hold(btnNum) {
buttonEvent(btnNum.toInteger, "held")
}
Thank you so much I'll give it a try. Either way thank you so much for looking at it.
Getting different errors. Looking better... Physical setting still work.
Thank you again for looking at it.
Small change:
More Modified Code
/**
* Aeon WallMote (with slide functionality)
*
* Copyright 2019 Ben Rimmasch
*
* 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.
*
* Aeon WallMote Quad
* https://aeotec.freshdesk.com/support/solutions/articles/6000162392-wallmote-quad-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000166184-wallmote-quad-technical-specifications-
* https://aeotec.freshdesk.com/support/solutions/articles/6000187144-wallmote-quad-group-association-explanation-for-direct-communication-
*
* Aeon WallMote Dual
* https://aeotec.freshdesk.com/support/solutions/articles/6000176572-wallmote-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000176570-wallmote-technical-specification-
* No group associations document but the above document for quad is applicable
*
* Author: Ben Rimmasch (codahq)
* Original Author: Eric Maycock (erocm123)
* Date: 2019-01-23
*
* Change Log:
* 2020-01-23: Initial
* 2020-01-26: Fixed logging for those that switch to this driver and have never set a logging level yet
* Change to two pushed buttons instead of one button that is pushed and held
* Bug fixes for some events
* Handled the event sent when a user initiates a connectivity health test from the remote's button
* Fixed firmware reporting for current Hubitat command classes
*
*
* Previous Author's Change Log:
* 2017-06-19: Added check to only send color change config for three wakeups. Editing preferences
* and hitting "done" will reset the counter. This is an attempt to prevent freezing
* caused by updating preferences.
*/
metadata {
definition (name: "Aeon WallMote", namespace: "codahq-hubitat", author: "Ben Rimmasch",
importUrl: "https://raw.githubusercontent.com/codahq/hubitat_codahq/master/devicestypes/aeon-wallmote.groovy") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "ReleasableButton"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "sequenceNumber", "number"
attribute "needUpdate", "string"
fingerprint mfr: "0086", prod: "0102", model: "0082", deviceJoinName: "Aeon WallMote"
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x73,0x98,0x86,0x85,0x59,0x8E,0x60,0x72,0x5A,0x84,0x5B,0x71,0x70,0x80,0x7A", outClusters: "0x25,0x26" // secure inclusion
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x85,0x59,0x8E,0x60,0x86,0x70,0x72,0x5A,0x73,0x84,0x80,0x5B,0x71,0x7A", outClusters: "0x25,0x26"
}
preferences {
input description: "Once you change values on this page, the attribute value \"needUpdate\" will show \"YES\" until all configuration parameters are updated.", title: "<b>Settings</b>", displayDuringSetup: false, type: "paragraph", element: "paragraph"
generate_preferences(configuration_model())
}
}
def parse(String description) {
logDebug "parse(String description)"
logTrace "description: $description"
def results = []
if (description.startsWith("Err")) {
results = createEvent(descriptionText:description, displayed:true)
}
else {
def cmd = zwave.parse(description, [0x2B: 1, 0x80: 1, 0x84: 1])
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
return results
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd)"
logTrace "cmd: $cmd"
def result = []
//if not held buttons and button slide is enabled
if (!getHeldButtons() && settings."3" == "1") {
switch (cmd.upDown) {
case false: // Up
logTrace "Slide up"
result << buttonEvent(device.currentValue("numberOfButtons") - 1, "pushed")
break
case true: // Down
logTrace "Slide down"
result << buttonEvent(device.currentValue("numberOfButtons"), "pushed")
break
default:
logDebug "Unhandled SwitchMultilevelStartLevelChange: ${cmd}"
break
}
}
result
}
def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd)"
logTrace "cmd: $cmd"
def result = []
sendEvent(name: "sequenceNumber", value: cmd.sequenceNumber, displayed:false)
switch (cmd.keyAttributes) {
case 0:
result << buttonEvent(cmd.sceneNumber, "pushed")
break
case 1: // released
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (!settings.holdMode || settings.holdMode == "2") result << buttonEvent(cmd.sceneNumber, "held")
result << buttonEvent(cmd.sceneNumber, "released")
break
case 2: // held
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (settings.holdMode == "1") result << buttonEvent(cmd.sceneNumber, "held")
break
default:
logDebug "Unhandled CentralSceneNotification: ${cmd}"
break
}
result
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x5B: 1, 0x20: 1, 0x31: 5, 0x30: 2, 0x84: 1, 0x70: 1])
state.sec = 1
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)"
logTrace "cmd: $cmd"
state.wakeInterval = cmd.seconds
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)"
logTrace "cmd: $cmd"
logInfo "Device ${device.displayName} woke up"
def request = update_needed_settings()
request << zwave.versionV1.versionGet()
if (!state.lastBatteryReport || (now() - state.lastBatteryReport) / 60000 >= 60 * 24) {
logDebug "Over 24hr since last battery report. Requesting report"
request << zwave.batteryV1.batteryGet()
}
state.wakeCount? (state.wakeCount = state.wakeCount + 1) : (state.wakeCount = 2)
if (request != []) {
response(commands(request) + ["delay 5000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
else {
logDebug "No commands to send"
response([zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
}
def buttonEvent(button, name) {
def msg = "$device.displayName button $button was $name"
logInfo msg
createEvent(name: name, value: button, descriptionText: msg, isStateChange: true)
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd)"
logTrace "cmd: $cmd"
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
state.lastBatteryReport = now()
createEvent(map)
}
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd)"
logTrace "cmd: $cmd"
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
updateDataValue("fw", fw)
if (state.MSR == "003B-6341-5044") {
updateDataValue("ver", "${cmd.firmware0Version >> 4}.${cmd.firmware0SubVersion & 0xF}")
}
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd)"
logTrace "cmd: $cmd"
logInfo "Connectivity testing performed by user at remote..."
}
def zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwaveEvent: ${cmd}"
}
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logDebug "msr: $msr"
updateDataValue("MSR", msr)
}
def installed() {
log.info "...Aeon WallMote Installed..."
configure()
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated() {
logDebug "updated() is being called"
state.wakeCount = 1
def cmds = update_needed_settings()
sendEvent(name: "checkInterval", value: 2 * 60 * 12 * 60 + 5 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
if (cmds != []) response(commands(cmds))
}
def configure() {
logDebug "Configuring Device For Use"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
if (cmds != []) commands(cmds)
}
private getNumButtons() {
return settings.buttons ? (settings."3" == "1" ? settings.buttons.toInteger() + 2 : settings.buttons) : (settings."3" ? 4 + 2 : 4)
}
def ping() {
logDebug "ping()"
log.warn "Battery Device - Not sending ping commands"
}
def generate_preferences(configuration_model) {
def configuration = new XmlSlurper().parseText(configuration_model)
configuration.Value.each {
switch(it.@type) {
case ["byte","short","four"]:
input "${it.@index}", "number", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "list":
def items = []
it.Item.each { items << ["${it.@value}": "${it.@label}"] }
input "${it.@index}", "enum", title:"<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}", options: items,
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "decimal":
input "${it.@index}", "decimal", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "boolean":
input "${it.@index}", "bool", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "string":
input "${it.@index}", "text", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
}
}
}
def update_current_properties(cmd) {
def currentProperties = state.currentProperties ?: [:]
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
if (settings."${cmd.parameterNumber}" != null) {
if (convertParam(cmd.parameterNumber, settings."${cmd.parameterNumber}") == 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"
if (state.wakeInterval == null || state.wakeInterval != 86400) {
logDebug "Setting Wake Interval to 86400"
cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId)
cmds << zwave.wakeUpV1.wakeUpIntervalGet()
}
if (settings."3" == "1") {
if (!state.association3 || state.association3 == "" || state.association3 == "1") {
logDebug "Setting association group 3"
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:3)
}
if (!state.association5 || state.association5 == "" || state.association5 == "1") {
logDebug "Setting association group 5"
cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:5)
}
if (!state.association7 || state.association7 == "" || state.association7 == "1") {
logDebug "Setting association group 7"
cmds << zwave.associationV2.associationSet(groupingIdentifier:7, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:7)
}
if (!state.association9 || state.association9 == "" || state.association9 == "1") {
logDebug "Setting association group 9"
cmds << zwave.associationV2.associationSet(groupingIdentifier:9, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:9)
}
}
if (state.MSR == null){
logDebug "Getting Manufacturer Specific Info"
cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet()
}
configuration.Value.each {
if ("${it.@setting_type}" == "zwave") {
if (currentProperties."${it.@index}" == null) {
if (it.@setonly == "true"){
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else {
isUpdateNeeded = "YES"
logDebug "Current value of parameter ${it.@index} is unknown"
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), settings."${it.@index}")) {
isUpdateNeeded = "YES"
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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) {
long parValue
switch (number) {
case 5:
switch (value) {
case "1":
parValue = 4278190080
break
case "2":
parValue = 16711680
break
case "3":
parValue = 65280
break
default:
parValue = value
break
}
break
default:
parValue = value.toLong()
break
}
return parValue
}
private def getHeldButtons() {
def heldButtons = (1..device.currentValue("numberOfButtons"))
heldButtons = heldButtons.find { button ->
state."${button}" == 2
}
logTrace "heldButtons $heldButtons"
return heldButtons
}
private logInfo(msg) {
if (settings.loggingLevel?.toInteger() >= 1) log.info msg
}
def logDebug(msg) {
if (settings.loggingLevel?.toInteger() >= 2) log.debug msg
}
def logTrace(msg) {
if (settings.loggingLevel?.toInteger() >= 3) log.trace msg
}
/**
* Convert 1 and 2 bytes values to integer
*/
def cmd2Integer(array) {
long value
if (array != [255, 0, 0, 0]){
switch(array.size()) {
case 1:
value = array[0]
break
case 2:
value = ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
break
case 3:
value = ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
break
case 4:
value = ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
break
}
}
else {
value = 4278190080
}
return value
}
def integer2Cmd(value, size) {
switch(size) {
case 1:
[value.toInteger()]
break
case 2:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
[value2.toInteger(), value1.toInteger()]
break
case 3:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
def short value3 = (value >> 16) & 0xFF
[value3.toInteger(), value2.toInteger(), value1.toInteger()]
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.toInteger(), value3.toInteger(), value2.toInteger(), value1.toInteger()]
break
}
}
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)
}
def configuration_model() {
'''
<configuration>
<Value type="list" byteSize="1" index="buttons" label="WallMote Model" min="2" max="4" value="" setting_type="preference" deviceId="" displayDuringSetup="true">
<Help>
Which model of WallMote is this?
</Help>
<Item label="Dual" value="2" />
<Item label="Quad" value="4" />
</Value>
<Value type="list" byteSize="1" index="1" label="Touch Sound" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch sound.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="2" label="Touch Vibration" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch vibration.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="3" label="Button Slide" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the function of button slide.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="4" index="5" label="LED Color" min="1" max="3" value="3" setting_type="zwave" deviceId="" setonly="true">
<Help>
To configure which color will be displayed when the button is pressed.<br/>
Default: Blue
</Help>
<Item label="Red" value="1" />
<Item label="Green" value="2" />
<Item label="Blue" value="3" />
</Value>
<Value type="list" byteSize="4" index="holdMode" label="Hold Mode" min="1" max="2" value="2" setting_type="preference" deviceId="">
<Help>
Multiple "held" events on botton hold? With this option, the controller will send a "held" event about every second while holding down a button. If set to No it will send a "held" event a single time when the button is released.<br/>
Default: No
</Help>
<Item label="No" value="2" />
<Item label="Yes" value="1" />
</Value>
<Value type="list" byteSize="1" index="loggingLevel" label="Logging Level?" min="0" max="3" value="0" setting_type="preference" deviceId="" required="true">
<Help>
Set the verbosity of the logs.
</Help>
<Item label="No Logging" value="0" />
<Item label="Descriptive Text" value="1" />
<Item label="Debug" value="2" />
<Item label="Trace" value="3" />
</Value>
</configuration>
'''
}
def push(btnNum) {
buttonEvent(btnNum.intValue(), "pushed")
}
def release(btnNum) {
buttonEvent(btnNum.intValue(), "released")
}
def hold(btnNum) {
buttonEvent(btnNum.intValue(), "held")
}
Both in debug and Trace logging.
I just get this and no action.
If I physically push the button, I get this and the action works.
Please, let me know if this helps and thank you again.
Not sure if we can fake it or not. Using the debug for a button press you could try:
Attempt at Faking Button Press
/**
* Aeon WallMote (with slide functionality)
*
* Copyright 2019 Ben Rimmasch
*
* 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.
*
* Aeon WallMote Quad
* https://aeotec.freshdesk.com/support/solutions/articles/6000162392-wallmote-quad-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000166184-wallmote-quad-technical-specifications-
* https://aeotec.freshdesk.com/support/solutions/articles/6000187144-wallmote-quad-group-association-explanation-for-direct-communication-
*
* Aeon WallMote Dual
* https://aeotec.freshdesk.com/support/solutions/articles/6000176572-wallmote-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000176570-wallmote-technical-specification-
* No group associations document but the above document for quad is applicable
*
* Author: Ben Rimmasch (codahq)
* Original Author: Eric Maycock (erocm123)
* Date: 2019-01-23
*
* Change Log:
* 2020-01-23: Initial
* 2020-01-26: Fixed logging for those that switch to this driver and have never set a logging level yet
* Change to two pushed buttons instead of one button that is pushed and held
* Bug fixes for some events
* Handled the event sent when a user initiates a connectivity health test from the remote's button
* Fixed firmware reporting for current Hubitat command classes
*
*
* Previous Author's Change Log:
* 2017-06-19: Added check to only send color change config for three wakeups. Editing preferences
* and hitting "done" will reset the counter. This is an attempt to prevent freezing
* caused by updating preferences.
*/
metadata {
definition (name: "Aeon WallMote", namespace: "codahq-hubitat", author: "Ben Rimmasch",
importUrl: "https://raw.githubusercontent.com/codahq/hubitat_codahq/master/devicestypes/aeon-wallmote.groovy") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "ReleasableButton"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "sequenceNumber", "number"
attribute "needUpdate", "string"
fingerprint mfr: "0086", prod: "0102", model: "0082", deviceJoinName: "Aeon WallMote"
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x73,0x98,0x86,0x85,0x59,0x8E,0x60,0x72,0x5A,0x84,0x5B,0x71,0x70,0x80,0x7A", outClusters: "0x25,0x26" // secure inclusion
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x85,0x59,0x8E,0x60,0x86,0x70,0x72,0x5A,0x73,0x84,0x80,0x5B,0x71,0x7A", outClusters: "0x25,0x26"
}
preferences {
input description: "Once you change values on this page, the attribute value \"needUpdate\" will show \"YES\" until all configuration parameters are updated.", title: "<b>Settings</b>", displayDuringSetup: false, type: "paragraph", element: "paragraph"
generate_preferences(configuration_model())
}
}
def parse(String description) {
logDebug "parse(String description)"
logTrace "description: $description"
def results = []
if (description.startsWith("Err")) {
results = createEvent(descriptionText:description, displayed:true)
}
else {
def cmd = zwave.parse(description, [0x2B: 1, 0x80: 1, 0x84: 1])
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
return results
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd)"
logTrace "cmd: $cmd"
def result = []
//if not held buttons and button slide is enabled
if (!getHeldButtons() && settings."3" == "1") {
switch (cmd.upDown) {
case false: // Up
logTrace "Slide up"
result << buttonEvent(device.currentValue("numberOfButtons") - 1, "pushed")
break
case true: // Down
logTrace "Slide down"
result << buttonEvent(device.currentValue("numberOfButtons"), "pushed")
break
default:
logDebug "Unhandled SwitchMultilevelStartLevelChange: ${cmd}"
break
}
}
result
}
def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd)"
logTrace "cmd: $cmd"
def result = []
sendEvent(name: "sequenceNumber", value: cmd.sequenceNumber, displayed:false)
switch (cmd.keyAttributes) {
case 0:
result << buttonEvent(cmd.sceneNumber, "pushed")
break
case 1: // released
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (!settings.holdMode || settings.holdMode == "2") result << buttonEvent(cmd.sceneNumber, "held")
result << buttonEvent(cmd.sceneNumber, "released")
break
case 2: // held
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (settings.holdMode == "1") result << buttonEvent(cmd.sceneNumber, "held")
break
default:
logDebug "Unhandled CentralSceneNotification: ${cmd}"
break
}
result
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x5B: 1, 0x20: 1, 0x31: 5, 0x30: 2, 0x84: 1, 0x70: 1])
state.sec = 1
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)"
logTrace "cmd: $cmd"
state.wakeInterval = cmd.seconds
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)"
logTrace "cmd: $cmd"
logInfo "Device ${device.displayName} woke up"
def request = update_needed_settings()
request << zwave.versionV1.versionGet()
if (!state.lastBatteryReport || (now() - state.lastBatteryReport) / 60000 >= 60 * 24) {
logDebug "Over 24hr since last battery report. Requesting report"
request << zwave.batteryV1.batteryGet()
}
state.wakeCount? (state.wakeCount = state.wakeCount + 1) : (state.wakeCount = 2)
if (request != []) {
response(commands(request) + ["delay 5000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
else {
logDebug "No commands to send"
response([zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
}
def buttonEvent(button, name) {
def msg = "$device.displayName button $button was $name"
logInfo msg
createEvent(name: name, value: button, descriptionText: msg, isStateChange: true)
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd)"
logTrace "cmd: $cmd"
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
state.lastBatteryReport = now()
createEvent(map)
}
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd)"
logTrace "cmd: $cmd"
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
updateDataValue("fw", fw)
if (state.MSR == "003B-6341-5044") {
updateDataValue("ver", "${cmd.firmware0Version >> 4}.${cmd.firmware0SubVersion & 0xF}")
}
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd)"
logTrace "cmd: $cmd"
logInfo "Connectivity testing performed by user at remote..."
}
def zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwaveEvent: ${cmd}"
}
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logDebug "msr: $msr"
updateDataValue("MSR", msr)
}
def installed() {
log.info "...Aeon WallMote Installed..."
configure()
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated() {
logDebug "updated() is being called"
state.wakeCount = 1
def cmds = update_needed_settings()
sendEvent(name: "checkInterval", value: 2 * 60 * 12 * 60 + 5 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
if (cmds != []) response(commands(cmds))
}
def configure() {
logDebug "Configuring Device For Use"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
if (cmds != []) commands(cmds)
}
private getNumButtons() {
return settings.buttons ? (settings."3" == "1" ? settings.buttons.toInteger() + 2 : settings.buttons) : (settings."3" ? 4 + 2 : 4)
}
def ping() {
logDebug "ping()"
log.warn "Battery Device - Not sending ping commands"
}
def generate_preferences(configuration_model) {
def configuration = new XmlSlurper().parseText(configuration_model)
configuration.Value.each {
switch(it.@type) {
case ["byte","short","four"]:
input "${it.@index}", "number", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "list":
def items = []
it.Item.each { items << ["${it.@value}": "${it.@label}"] }
input "${it.@index}", "enum", title:"<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}", options: items,
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "decimal":
input "${it.@index}", "decimal", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "boolean":
input "${it.@index}", "bool", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "string":
input "${it.@index}", "text", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
}
}
}
def update_current_properties(cmd) {
def currentProperties = state.currentProperties ?: [:]
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
if (settings."${cmd.parameterNumber}" != null) {
if (convertParam(cmd.parameterNumber, settings."${cmd.parameterNumber}") == 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"
if (state.wakeInterval == null || state.wakeInterval != 86400) {
logDebug "Setting Wake Interval to 86400"
cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId)
cmds << zwave.wakeUpV1.wakeUpIntervalGet()
}
if (settings."3" == "1") {
if (!state.association3 || state.association3 == "" || state.association3 == "1") {
logDebug "Setting association group 3"
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:3)
}
if (!state.association5 || state.association5 == "" || state.association5 == "1") {
logDebug "Setting association group 5"
cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:5)
}
if (!state.association7 || state.association7 == "" || state.association7 == "1") {
logDebug "Setting association group 7"
cmds << zwave.associationV2.associationSet(groupingIdentifier:7, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:7)
}
if (!state.association9 || state.association9 == "" || state.association9 == "1") {
logDebug "Setting association group 9"
cmds << zwave.associationV2.associationSet(groupingIdentifier:9, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:9)
}
}
if (state.MSR == null){
logDebug "Getting Manufacturer Specific Info"
cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet()
}
configuration.Value.each {
if ("${it.@setting_type}" == "zwave") {
if (currentProperties."${it.@index}" == null) {
if (it.@setonly == "true"){
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else {
isUpdateNeeded = "YES"
logDebug "Current value of parameter ${it.@index} is unknown"
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), settings."${it.@index}")) {
isUpdateNeeded = "YES"
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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) {
long parValue
switch (number) {
case 5:
switch (value) {
case "1":
parValue = 4278190080
break
case "2":
parValue = 16711680
break
case "3":
parValue = 65280
break
default:
parValue = value
break
}
break
default:
parValue = value.toLong()
break
}
return parValue
}
private def getHeldButtons() {
def heldButtons = (1..device.currentValue("numberOfButtons"))
heldButtons = heldButtons.find { button ->
state."${button}" == 2
}
logTrace "heldButtons $heldButtons"
return heldButtons
}
private logInfo(msg) {
if (settings.loggingLevel?.toInteger() >= 1) log.info msg
}
def logDebug(msg) {
if (settings.loggingLevel?.toInteger() >= 2) log.debug msg
}
def logTrace(msg) {
if (settings.loggingLevel?.toInteger() >= 3) log.trace msg
}
/**
* Convert 1 and 2 bytes values to integer
*/
def cmd2Integer(array) {
long value
if (array != [255, 0, 0, 0]){
switch(array.size()) {
case 1:
value = array[0]
break
case 2:
value = ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
break
case 3:
value = ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
break
case 4:
value = ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
break
}
}
else {
value = 4278190080
}
return value
}
def integer2Cmd(value, size) {
switch(size) {
case 1:
[value.toInteger()]
break
case 2:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
[value2.toInteger(), value1.toInteger()]
break
case 3:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
def short value3 = (value >> 16) & 0xFF
[value3.toInteger(), value2.toInteger(), value1.toInteger()]
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.toInteger(), value3.toInteger(), value2.toInteger(), value1.toInteger()]
break
}
}
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)
}
def configuration_model() {
'''
<configuration>
<Value type="list" byteSize="1" index="buttons" label="WallMote Model" min="2" max="4" value="" setting_type="preference" deviceId="" displayDuringSetup="true">
<Help>
Which model of WallMote is this?
</Help>
<Item label="Dual" value="2" />
<Item label="Quad" value="4" />
</Value>
<Value type="list" byteSize="1" index="1" label="Touch Sound" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch sound.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="2" label="Touch Vibration" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch vibration.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="3" label="Button Slide" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the function of button slide.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="4" index="5" label="LED Color" min="1" max="3" value="3" setting_type="zwave" deviceId="" setonly="true">
<Help>
To configure which color will be displayed when the button is pressed.<br/>
Default: Blue
</Help>
<Item label="Red" value="1" />
<Item label="Green" value="2" />
<Item label="Blue" value="3" />
</Value>
<Value type="list" byteSize="4" index="holdMode" label="Hold Mode" min="1" max="2" value="2" setting_type="preference" deviceId="">
<Help>
Multiple "held" events on botton hold? With this option, the controller will send a "held" event about every second while holding down a button. If set to No it will send a "held" event a single time when the button is released.<br/>
Default: No
</Help>
<Item label="No" value="2" />
<Item label="Yes" value="1" />
</Value>
<Value type="list" byteSize="1" index="loggingLevel" label="Logging Level?" min="0" max="3" value="0" setting_type="preference" deviceId="" required="true">
<Help>
Set the verbosity of the logs.
</Help>
<Item label="No Logging" value="0" />
<Item label="Descriptive Text" value="1" />
<Item label="Debug" value="2" />
<Item label="Trace" value="3" />
</Value>
</configuration>
'''
}
def push(btnNum) {
buttonEvent(btnNum.intValue(), "pushed")
results = parse( "zw device: 18, command: 2601, payload: 00 FF, isMulticast: false")
return results
}
def release(btnNum) {
buttonEvent(btnNum.intValue(), "released")
results = parse("Err NOT IMPLEMENTED")
return results
}
def hold(btnNum) {
buttonEvent(btnNum.intValue(), "held")
results = parse("Err NOT IMPLEMENTED")
return results
}
Looks like you are so close to sorting this out.
Hold button1
Event log Shows two states but not action.
Push Button1
Nothing in the event logs – Action doesn’t occur
Thank you again!
Try clicking the Push command instead of the Hold.
I did that was the second action.
Hmmm, I don't have a device, but when I put a 1 in the button number and click Push
With Trace logging I get
I’m getting the same thing
Virtual Push 1
Nothing in the event logs.
Debug log
Physical Push 1
Event Logs
Debug
Thank you again. If this is a pain, I understand.
Not a pain, just not an area I've done a lot in so learning as I go (this is a good thing).
New Code
/**
* Aeon WallMote (with slide functionality)
*
* Copyright 2019 Ben Rimmasch
*
* 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.
*
* Aeon WallMote Quad
* https://aeotec.freshdesk.com/support/solutions/articles/6000162392-wallmote-quad-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000166184-wallmote-quad-technical-specifications-
* https://aeotec.freshdesk.com/support/solutions/articles/6000187144-wallmote-quad-group-association-explanation-for-direct-communication-
*
* Aeon WallMote Dual
* https://aeotec.freshdesk.com/support/solutions/articles/6000176572-wallmote-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000176570-wallmote-technical-specification-
* No group associations document but the above document for quad is applicable
*
* Author: Ben Rimmasch (codahq)
* Original Author: Eric Maycock (erocm123)
* Date: 2019-01-23
*
* Change Log:
* 2020-01-23: Initial
* 2020-01-26: Fixed logging for those that switch to this driver and have never set a logging level yet
* Change to two pushed buttons instead of one button that is pushed and held
* Bug fixes for some events
* Handled the event sent when a user initiates a connectivity health test from the remote's button
* Fixed firmware reporting for current Hubitat command classes
*
*
* Previous Author's Change Log:
* 2017-06-19: Added check to only send color change config for three wakeups. Editing preferences
* and hitting "done" will reset the counter. This is an attempt to prevent freezing
* caused by updating preferences.
*/
metadata {
definition (name: "Aeon WallMote", namespace: "codahq-hubitat", author: "Ben Rimmasch",
importUrl: "https://raw.githubusercontent.com/codahq/hubitat_codahq/master/devicestypes/aeon-wallmote.groovy") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "ReleasableButton"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "sequenceNumber", "number"
attribute "needUpdate", "string"
fingerprint mfr: "0086", prod: "0102", model: "0082", deviceJoinName: "Aeon WallMote"
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x73,0x98,0x86,0x85,0x59,0x8E,0x60,0x72,0x5A,0x84,0x5B,0x71,0x70,0x80,0x7A", outClusters: "0x25,0x26" // secure inclusion
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x85,0x59,0x8E,0x60,0x86,0x70,0x72,0x5A,0x73,0x84,0x80,0x5B,0x71,0x7A", outClusters: "0x25,0x26"
}
preferences {
input description: "Once you change values on this page, the attribute value \"needUpdate\" will show \"YES\" until all configuration parameters are updated.", title: "<b>Settings</b>", displayDuringSetup: false, type: "paragraph", element: "paragraph"
generate_preferences(configuration_model())
}
}
def parse(String description) {
logDebug "parse(String description)"
logTrace "description: $description"
def results = []
if (description.startsWith("Err")) {
results = createEvent(descriptionText:description, displayed:true)
}
else {
def cmd = zwave.parse(description, [0x2B: 1, 0x80: 1, 0x84: 1])
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
return results
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd)"
logTrace "cmd: $cmd"
def result = []
//if not held buttons and button slide is enabled
if (!getHeldButtons() && settings."3" == "1") {
switch (cmd.upDown) {
case false: // Up
logTrace "Slide up"
result << buttonEvent(device.currentValue("numberOfButtons") - 1, "pushed")
break
case true: // Down
logTrace "Slide down"
result << buttonEvent(device.currentValue("numberOfButtons"), "pushed")
break
default:
logDebug "Unhandled SwitchMultilevelStartLevelChange: ${cmd}"
break
}
}
result
}
def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd)"
logTrace "cmd: $cmd"
def result = []
sendEvent(name: "sequenceNumber", value: cmd.sequenceNumber, displayed:false)
switch (cmd.keyAttributes) {
case 0:
result << buttonEvent(cmd.sceneNumber, "pushed")
break
case 1: // released
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (!settings.holdMode || settings.holdMode == "2") result << buttonEvent(cmd.sceneNumber, "held")
result << buttonEvent(cmd.sceneNumber, "released")
break
case 2: // held
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (settings.holdMode == "1") result << buttonEvent(cmd.sceneNumber, "held")
break
default:
logDebug "Unhandled CentralSceneNotification: ${cmd}"
break
}
result
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x5B: 1, 0x20: 1, 0x31: 5, 0x30: 2, 0x84: 1, 0x70: 1])
state.sec = 1
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)"
logTrace "cmd: $cmd"
state.wakeInterval = cmd.seconds
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)"
logTrace "cmd: $cmd"
logInfo "Device ${device.displayName} woke up"
def request = update_needed_settings()
request << zwave.versionV1.versionGet()
if (!state.lastBatteryReport || (now() - state.lastBatteryReport) / 60000 >= 60 * 24) {
logDebug "Over 24hr since last battery report. Requesting report"
request << zwave.batteryV1.batteryGet()
}
state.wakeCount? (state.wakeCount = state.wakeCount + 1) : (state.wakeCount = 2)
if (request != []) {
response(commands(request) + ["delay 5000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
else {
logDebug "No commands to send"
response([zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
}
def buttonEvent(button, name) {
def msg = "$device.displayName button $button was $name"
logInfo msg
createEvent(name: name, value: button, descriptionText: msg, isStateChange: true)
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd)"
logTrace "cmd: $cmd"
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
state.lastBatteryReport = now()
createEvent(map)
}
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd)"
logTrace "cmd: $cmd"
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
updateDataValue("fw", fw)
if (state.MSR == "003B-6341-5044") {
updateDataValue("ver", "${cmd.firmware0Version >> 4}.${cmd.firmware0SubVersion & 0xF}")
}
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd)"
logTrace "cmd: $cmd"
logInfo "Connectivity testing performed by user at remote..."
}
def zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwaveEvent: ${cmd}"
}
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logDebug "msr: $msr"
updateDataValue("MSR", msr)
}
def installed() {
log.info "...Aeon WallMote Installed..."
configure()
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated() {
logDebug "updated() is being called"
state.wakeCount = 1
def cmds = update_needed_settings()
sendEvent(name: "checkInterval", value: 2 * 60 * 12 * 60 + 5 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
if (cmds != []) response(commands(cmds))
}
def configure() {
logDebug "Configuring Device For Use"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
if (cmds != []) commands(cmds)
}
private getNumButtons() {
return settings.buttons ? (settings."3" == "1" ? settings.buttons.toInteger() + 2 : settings.buttons) : (settings."3" ? 4 + 2 : 4)
}
def ping() {
logDebug "ping()"
log.warn "Battery Device - Not sending ping commands"
}
def generate_preferences(configuration_model) {
def configuration = new XmlSlurper().parseText(configuration_model)
configuration.Value.each {
switch(it.@type) {
case ["byte","short","four"]:
input "${it.@index}", "number", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "list":
def items = []
it.Item.each { items << ["${it.@value}": "${it.@label}"] }
input "${it.@index}", "enum", title:"<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}", options: items,
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "decimal":
input "${it.@index}", "decimal", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "boolean":
input "${it.@index}", "bool", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "string":
input "${it.@index}", "text", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
}
}
}
def update_current_properties(cmd) {
def currentProperties = state.currentProperties ?: [:]
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
if (settings."${cmd.parameterNumber}" != null) {
if (convertParam(cmd.parameterNumber, settings."${cmd.parameterNumber}") == 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"
if (state.wakeInterval == null || state.wakeInterval != 86400) {
logDebug "Setting Wake Interval to 86400"
cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId)
cmds << zwave.wakeUpV1.wakeUpIntervalGet()
}
if (settings."3" == "1") {
if (!state.association3 || state.association3 == "" || state.association3 == "1") {
logDebug "Setting association group 3"
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:3)
}
if (!state.association5 || state.association5 == "" || state.association5 == "1") {
logDebug "Setting association group 5"
cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:5)
}
if (!state.association7 || state.association7 == "" || state.association7 == "1") {
logDebug "Setting association group 7"
cmds << zwave.associationV2.associationSet(groupingIdentifier:7, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:7)
}
if (!state.association9 || state.association9 == "" || state.association9 == "1") {
logDebug "Setting association group 9"
cmds << zwave.associationV2.associationSet(groupingIdentifier:9, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:9)
}
}
if (state.MSR == null){
logDebug "Getting Manufacturer Specific Info"
cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet()
}
configuration.Value.each {
if ("${it.@setting_type}" == "zwave") {
if (currentProperties."${it.@index}" == null) {
if (it.@setonly == "true"){
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else {
isUpdateNeeded = "YES"
logDebug "Current value of parameter ${it.@index} is unknown"
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), settings."${it.@index}")) {
isUpdateNeeded = "YES"
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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) {
long parValue
switch (number) {
case 5:
switch (value) {
case "1":
parValue = 4278190080
break
case "2":
parValue = 16711680
break
case "3":
parValue = 65280
break
default:
parValue = value
break
}
break
default:
parValue = value.toLong()
break
}
return parValue
}
private def getHeldButtons() {
def heldButtons = (1..device.currentValue("numberOfButtons"))
heldButtons = heldButtons.find { button ->
state."${button}" == 2
}
logTrace "heldButtons $heldButtons"
return heldButtons
}
private logInfo(msg) {
if (settings.loggingLevel?.toInteger() >= 1) log.info msg
}
def logDebug(msg) {
if (settings.loggingLevel?.toInteger() >= 2) log.debug msg
}
def logTrace(msg) {
if (settings.loggingLevel?.toInteger() >= 3) log.trace msg
}
/**
* Convert 1 and 2 bytes values to integer
*/
def cmd2Integer(array) {
long value
if (array != [255, 0, 0, 0]){
switch(array.size()) {
case 1:
value = array[0]
break
case 2:
value = ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
break
case 3:
value = ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
break
case 4:
value = ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
break
}
}
else {
value = 4278190080
}
return value
}
def integer2Cmd(value, size) {
switch(size) {
case 1:
[value.toInteger()]
break
case 2:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
[value2.toInteger(), value1.toInteger()]
break
case 3:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
def short value3 = (value >> 16) & 0xFF
[value3.toInteger(), value2.toInteger(), value1.toInteger()]
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.toInteger(), value3.toInteger(), value2.toInteger(), value1.toInteger()]
break
}
}
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)
}
def configuration_model() {
'''
<configuration>
<Value type="list" byteSize="1" index="buttons" label="WallMote Model" min="2" max="4" value="" setting_type="preference" deviceId="" displayDuringSetup="true">
<Help>
Which model of WallMote is this?
</Help>
<Item label="Dual" value="2" />
<Item label="Quad" value="4" />
</Value>
<Value type="list" byteSize="1" index="1" label="Touch Sound" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch sound.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="2" label="Touch Vibration" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch vibration.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="3" label="Button Slide" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the function of button slide.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="4" index="5" label="LED Color" min="1" max="3" value="3" setting_type="zwave" deviceId="" setonly="true">
<Help>
To configure which color will be displayed when the button is pressed.<br/>
Default: Blue
</Help>
<Item label="Red" value="1" />
<Item label="Green" value="2" />
<Item label="Blue" value="3" />
</Value>
<Value type="list" byteSize="4" index="holdMode" label="Hold Mode" min="1" max="2" value="2" setting_type="preference" deviceId="">
<Help>
Multiple "held" events on botton hold? With this option, the controller will send a "held" event about every second while holding down a button. If set to No it will send a "held" event a single time when the button is released.<br/>
Default: No
</Help>
<Item label="No" value="2" />
<Item label="Yes" value="1" />
</Value>
<Value type="list" byteSize="1" index="loggingLevel" label="Logging Level?" min="0" max="3" value="0" setting_type="preference" deviceId="" required="true">
<Help>
Set the verbosity of the logs.
</Help>
<Item label="No Logging" value="0" />
<Item label="Descriptive Text" value="1" />
<Item label="Debug" value="2" />
<Item label="Trace" value="3" />
</Value>
</configuration>
'''
}
def push(btnNum) {
buttonEvent(btnNum.intValue(), "pushed")
sendEvent(name:"pushed", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was pushed (digital)")
results = parse( "zw device: 18, command: 2601, payload: 00 FF, isMulticast: false")
return results
}
def release(btnNum) {
buttonEvent(btnNum.intValue(), "released")
sendEvent(name:"released", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was released (digital)")
results = parse("Err NOT IMPLEMENTED")
return results
}
def hold(btnNum) {
buttonEvent(btnNum.intValue(), "held")
sendEvent(name:"held", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was held (digital)")
results = parse("Err NOT IMPLEMENTED")
return results
}
Let’s try a different tactic, and try just forcing the button event independently:
Send Event Only
/**
* Aeon WallMote (with slide functionality)
*
* Copyright 2019 Ben Rimmasch
*
* 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.
*
* Aeon WallMote Quad
* https://aeotec.freshdesk.com/support/solutions/articles/6000162392-wallmote-quad-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000166184-wallmote-quad-technical-specifications-
* https://aeotec.freshdesk.com/support/solutions/articles/6000187144-wallmote-quad-group-association-explanation-for-direct-communication-
*
* Aeon WallMote Dual
* https://aeotec.freshdesk.com/support/solutions/articles/6000176572-wallmote-user-guide-
* https://aeotec.freshdesk.com/support/solutions/articles/6000176570-wallmote-technical-specification-
* No group associations document but the above document for quad is applicable
*
* Author: Ben Rimmasch (codahq)
* Original Author: Eric Maycock (erocm123)
* Date: 2019-01-23
*
* Change Log:
* 2020-01-23: Initial
* 2020-01-26: Fixed logging for those that switch to this driver and have never set a logging level yet
* Change to two pushed buttons instead of one button that is pushed and held
* Bug fixes for some events
* Handled the event sent when a user initiates a connectivity health test from the remote's button
* Fixed firmware reporting for current Hubitat command classes
*
*
* Previous Author's Change Log:
* 2017-06-19: Added check to only send color change config for three wakeups. Editing preferences
* and hitting "done" will reset the counter. This is an attempt to prevent freezing
* caused by updating preferences.
*/
metadata {
definition (name: "Aeon WallMote", namespace: "codahq-hubitat", author: "Ben Rimmasch",
importUrl: "https://raw.githubusercontent.com/codahq/hubitat_codahq/master/devicestypes/aeon-wallmote.groovy") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "ReleasableButton"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "sequenceNumber", "number"
attribute "needUpdate", "string"
fingerprint mfr: "0086", prod: "0102", model: "0082", deviceJoinName: "Aeon WallMote"
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x73,0x98,0x86,0x85,0x59,0x8E,0x60,0x72,0x5A,0x84,0x5B,0x71,0x70,0x80,0x7A", outClusters: "0x25,0x26" // secure inclusion
fingerprint deviceId: "0x1801", inClusters: "0x5E,0x85,0x59,0x8E,0x60,0x86,0x70,0x72,0x5A,0x73,0x84,0x80,0x5B,0x71,0x7A", outClusters: "0x25,0x26"
}
preferences {
input description: "Once you change values on this page, the attribute value \"needUpdate\" will show \"YES\" until all configuration parameters are updated.", title: "<b>Settings</b>", displayDuringSetup: false, type: "paragraph", element: "paragraph"
generate_preferences(configuration_model())
}
}
def parse(String description) {
logDebug "parse(String description)"
logTrace "description: $description"
def results = []
if (description.startsWith("Err")) {
results = createEvent(descriptionText:description, displayed:true)
}
else {
def cmd = zwave.parse(description, [0x2B: 1, 0x80: 1, 0x84: 1])
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
return results
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd)"
logTrace "cmd: $cmd"
//not needed. do nothing.
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd)"
logTrace "cmd: $cmd"
def result = []
//if not held buttons and button slide is enabled
if (!getHeldButtons() && settings."3" == "1") {
switch (cmd.upDown) {
case false: // Up
logTrace "Slide up"
result << buttonEvent(device.currentValue("numberOfButtons") - 1, "pushed")
break
case true: // Down
logTrace "Slide down"
result << buttonEvent(device.currentValue("numberOfButtons"), "pushed")
break
default:
logDebug "Unhandled SwitchMultilevelStartLevelChange: ${cmd}"
break
}
}
result
}
def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd)"
logTrace "cmd: $cmd"
def result = []
sendEvent(name: "sequenceNumber", value: cmd.sequenceNumber, displayed:false)
switch (cmd.keyAttributes) {
case 0:
result << buttonEvent(cmd.sceneNumber, "pushed")
break
case 1: // released
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (!settings.holdMode || settings.holdMode == "2") result << buttonEvent(cmd.sceneNumber, "held")
result << buttonEvent(cmd.sceneNumber, "released")
break
case 2: // held
state."${cmd.sceneNumber}" = cmd.keyAttributes
if (settings.holdMode == "1") result << buttonEvent(cmd.sceneNumber, "held")
break
default:
logDebug "Unhandled CentralSceneNotification: ${cmd}"
break
}
result
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x5B: 1, 0x20: 1, 0x31: 5, 0x30: 2, 0x84: 1, 0x70: 1])
state.sec = 1
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)"
logTrace "cmd: $cmd"
state.wakeInterval = cmd.seconds
}
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)"
logTrace "cmd: $cmd"
logInfo "Device ${device.displayName} woke up"
def request = update_needed_settings()
request << zwave.versionV1.versionGet()
if (!state.lastBatteryReport || (now() - state.lastBatteryReport) / 60000 >= 60 * 24) {
logDebug "Over 24hr since last battery report. Requesting report"
request << zwave.batteryV1.batteryGet()
}
state.wakeCount? (state.wakeCount = state.wakeCount + 1) : (state.wakeCount = 2)
if (request != []) {
response(commands(request) + ["delay 5000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
else {
logDebug "No commands to send"
response([zwave.wakeUpV1.wakeUpNoMoreInformation().format()])
}
}
def buttonEvent(button, name) {
def msg = "$device.displayName button $button was $name"
logInfo msg
createEvent(name: name, value: button, descriptionText: msg, isStateChange: true)
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd)"
logTrace "cmd: $cmd"
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
state.lastBatteryReport = now()
createEvent(map)
}
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd)"
logTrace "cmd: $cmd"
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
update_current_properties(cmd)
logDebug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'"
}
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
updateDataValue("fw", fw)
if (state.MSR == "003B-6341-5044") {
updateDataValue("ver", "${cmd.firmware0Version >> 4}.${cmd.firmware0SubVersion & 0xF}")
}
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd) {
logDebug "zwaveEvent(hubitat.zwave.commands.powerlevelv1.PowerlevelTestNodeReport cmd)"
logTrace "cmd: $cmd"
logInfo "Connectivity testing performed by user at remote..."
}
def zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwaveEvent: ${cmd}"
}
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logDebug "msr: $msr"
updateDataValue("MSR", msr)
}
def installed() {
log.info "...Aeon WallMote Installed..."
configure()
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated() {
logDebug "updated() is being called"
state.wakeCount = 1
def cmds = update_needed_settings()
sendEvent(name: "checkInterval", value: 2 * 60 * 12 * 60 + 5 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
if (cmds != []) response(commands(cmds))
}
def configure() {
logDebug "Configuring Device For Use"
def cmds = []
cmds = update_needed_settings()
sendEvent(name: "numberOfButtons", value: getNumButtons(), displayed: true)
if (cmds != []) commands(cmds)
}
private getNumButtons() {
return settings.buttons ? (settings."3" == "1" ? settings.buttons.toInteger() + 2 : settings.buttons) : (settings."3" ? 4 + 2 : 4)
}
def ping() {
logDebug "ping()"
log.warn "Battery Device - Not sending ping commands"
}
def generate_preferences(configuration_model) {
def configuration = new XmlSlurper().parseText(configuration_model)
configuration.Value.each {
switch(it.@type) {
case ["byte","short","four"]:
input "${it.@index}", "number", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "list":
def items = []
it.Item.each { items << ["${it.@value}": "${it.@label}"] }
input "${it.@index}", "enum", title:"<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}", options: items,
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "decimal":
input "${it.@index}", "decimal", title:"<b>${it.@label}</b>", description: "${it.Help}", range: "${it.@min}..${it.@max}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "boolean":
input "${it.@index}", "bool", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
case "string":
input "${it.@index}", "text", title: "<b>${it.@label}</b>", description: "${it.Help}", defaultValue: "${it.@value}",
displayDuringSetup: "${it.@displayDuringSetup}", required: "${it.@required}"
break
}
}
}
def update_current_properties(cmd) {
def currentProperties = state.currentProperties ?: [:]
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
if (settings."${cmd.parameterNumber}" != null) {
if (convertParam(cmd.parameterNumber, settings."${cmd.parameterNumber}") == 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"
if (state.wakeInterval == null || state.wakeInterval != 86400) {
logDebug "Setting Wake Interval to 86400"
cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId)
cmds << zwave.wakeUpV1.wakeUpIntervalGet()
}
if (settings."3" == "1") {
if (!state.association3 || state.association3 == "" || state.association3 == "1") {
logDebug "Setting association group 3"
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:3)
}
if (!state.association5 || state.association5 == "" || state.association5 == "1") {
logDebug "Setting association group 5"
cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:5)
}
if (!state.association7 || state.association7 == "" || state.association7 == "1") {
logDebug "Setting association group 7"
cmds << zwave.associationV2.associationSet(groupingIdentifier:7, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:7)
}
if (!state.association9 || state.association9 == "" || state.association9 == "1") {
logDebug "Setting association group 9"
cmds << zwave.associationV2.associationSet(groupingIdentifier:9, nodeId:zwaveHubNodeId)
cmds << zwave.associationV2.associationGet(groupingIdentifier:9)
}
}
if (state.MSR == null){
logDebug "Getting Manufacturer Specific Info"
cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet()
}
configuration.Value.each {
if ("${it.@setting_type}" == "zwave") {
if (currentProperties."${it.@index}" == null) {
if (it.@setonly == "true"){
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}"? settings."${it.@index}" : "${it.@value}")
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())
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else {
isUpdateNeeded = "YES"
logDebug "Current value of parameter ${it.@index} is unknown"
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
}
}
else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != convertParam(it.@index.toInteger(), settings."${it.@index}")) {
isUpdateNeeded = "YES"
if (it.@index == 5) {
if (state.wakeCount <= 3) {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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())
}
else {
logDebug "Parameter has already sent. Will not send again until updated() gets called"
}
}
else {
logDebug "Parameter ${it.@index} will be updated to " + convertParam(it.@index.toInteger(), settings."${it.@index}")
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}")
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) {
long parValue
switch (number) {
case 5:
switch (value) {
case "1":
parValue = 4278190080
break
case "2":
parValue = 16711680
break
case "3":
parValue = 65280
break
default:
parValue = value
break
}
break
default:
parValue = value.toLong()
break
}
return parValue
}
private def getHeldButtons() {
def heldButtons = (1..device.currentValue("numberOfButtons"))
heldButtons = heldButtons.find { button ->
state."${button}" == 2
}
logTrace "heldButtons $heldButtons"
return heldButtons
}
private logInfo(msg) {
if (settings.loggingLevel?.toInteger() >= 1) log.info msg
}
def logDebug(msg) {
if (settings.loggingLevel?.toInteger() >= 2) log.debug msg
}
def logTrace(msg) {
if (settings.loggingLevel?.toInteger() >= 3) log.trace msg
}
/**
* Convert 1 and 2 bytes values to integer
*/
def cmd2Integer(array) {
long value
if (array != [255, 0, 0, 0]){
switch(array.size()) {
case 1:
value = array[0]
break
case 2:
value = ((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
break
case 3:
value = ((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
break
case 4:
value = ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
break
}
}
else {
value = 4278190080
}
return value
}
def integer2Cmd(value, size) {
switch(size) {
case 1:
[value.toInteger()]
break
case 2:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
[value2.toInteger(), value1.toInteger()]
break
case 3:
def short value1 = value & 0xFF
def short value2 = (value >> 8) & 0xFF
def short value3 = (value >> 16) & 0xFF
[value3.toInteger(), value2.toInteger(), value1.toInteger()]
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.toInteger(), value3.toInteger(), value2.toInteger(), value1.toInteger()]
break
}
}
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)
}
def configuration_model() {
'''
<configuration>
<Value type="list" byteSize="1" index="buttons" label="WallMote Model" min="2" max="4" value="" setting_type="preference" deviceId="" displayDuringSetup="true">
<Help>
Which model of WallMote is this?
</Help>
<Item label="Dual" value="2" />
<Item label="Quad" value="4" />
</Value>
<Value type="list" byteSize="1" index="1" label="Touch Sound" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch sound.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="2" label="Touch Vibration" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the touch vibration.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="1" index="3" label="Button Slide" min="0" max="1" value="1" setting_type="zwave" deviceId="">
<Help>
Enable/disable the function of button slide.<br/>
Default: Enable
</Help>
<Item label="Disable" value="0" />
<Item label="Enable" value="1" />
</Value>
<Value type="list" byteSize="4" index="5" label="LED Color" min="1" max="3" value="3" setting_type="zwave" deviceId="" setonly="true">
<Help>
To configure which color will be displayed when the button is pressed.<br/>
Default: Blue
</Help>
<Item label="Red" value="1" />
<Item label="Green" value="2" />
<Item label="Blue" value="3" />
</Value>
<Value type="list" byteSize="4" index="holdMode" label="Hold Mode" min="1" max="2" value="2" setting_type="preference" deviceId="">
<Help>
Multiple "held" events on botton hold? With this option, the controller will send a "held" event about every second while holding down a button. If set to No it will send a "held" event a single time when the button is released.<br/>
Default: No
</Help>
<Item label="No" value="2" />
<Item label="Yes" value="1" />
</Value>
<Value type="list" byteSize="1" index="loggingLevel" label="Logging Level?" min="0" max="3" value="0" setting_type="preference" deviceId="" required="true">
<Help>
Set the verbosity of the logs.
</Help>
<Item label="No Logging" value="0" />
<Item label="Descriptive Text" value="1" />
<Item label="Debug" value="2" />
<Item label="Trace" value="3" />
</Value>
</configuration>
'''
}
def push(btnNum) {
sendEvent(name:"pushed", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was pushed (digital)", isStateChange: true)
}
def release(btnNum) {
sendEvent(name:"released", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was released (digital)", isStateChange: true)
}
def hold(btnNum) {
sendEvent(name:"held", value: btnNum.intValue(), descriptionText: "Button ${btnNum.intValue()} was held (digital)", isStateChange: true)
}
NICE!!!!! It looks like it works perfectly.
Dig vs manual.... This is great!!! you make it your own Put it HPM... What can I do for you? I'm very grateful.
Excellent! I was overthinking it.