Caring is Sharing WallMote & ZW97

Special Thanks to @thebearmay
He took one the DH that I had for the WallMote and sorted out some of the issues with this DH. Now it works perfectly.

/**
 *  Aeon WallMote (with slide functionality)
 *
 *  Copyright 2019 Custom
 *
 *  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: custom (custom)
 *  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: "Custom", author: "Custom",
      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)
}

I had bought the EVALogik ZW97 and I had some issues with the existing DH that defaults with Hubitat. I worked with the manufacturer, and they created a DH that works perfectly too. I would like to share with you all.

EVALogik ZW97

/**
 *  Outdoor Smart Plug 2-Channel ZW97
 *  Author: 
 *  Date: 
 *   Reference:https://raw.githubusercontent.com/InovelliUSA/Hubitat/master/Drivers/inovelli-2-channel-outdoor-smart-plug-nzw97.src/inovelli-2-channel-outdoor-smart-plug-nzw97.groovy
 *  Copyright 2020
 *
 *  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.
 *
 *  2019-11-20: Fixed Association Group management.
 *
 *  2018-05-02: Added support for Z-Wave Association Tool SmartApp. Associations require firmware 1.02+.
 *
 */
import java.util.concurrent.*
metadata {
    definition(
        name: "Outdoor Smart Plug 2-Channel ZW97", 
        namespace: "Evalogik",
        author: "sky-nie",
        importUrl: "https://raw.githubusercontent.com/sky-nie/hubitat/main/evalogik/evalogik-outdoor-smart-plug.groovy"
    ) {
        capability "Actuator"
        capability "Sensor"
        capability "Switch"
        capability "Polling"
        capability "Refresh"
        capability "Health Check"
        capability "PushableButton"
        capability "Configuration"

        attribute "lastActivity", "String"
        attribute "lastEvent", "String"

        command "setAssociationGroup", [[name: "Group Number*",type:"NUMBER", description: "Provide the association group number to edit"],
                                        [name: "Z-Wave Node*", type:"STRING", description: "Enter the node number (in hex) associated with the node"],
                                        [name: "Action*", type:"ENUM", constraints: ["Add", "Remove"]],
                                        [name:"Multi-channel Endpoint", type:"NUMBER", description: "Currently not implemented"]]

        command "childOn"
        command "childOff"
        command "childRefresh"
        command "componentOn"
        command "componentOff"
        command "componentRefresh"

        fingerprint mfr: "0312", prod: "C000", deviceId: "C007", deviceJoinName: "Outdoor Smart Plug 2-Channel ZW97", inClusters:"0x5E,0x6C,0x55,0x9F"  // ZW97
        fingerprint mfr: "0312", prod: "C000", deviceId: "C007", deviceJoinName: "Outdoor Smart Plug 2-Channel ZW97", inClusters:"0x86,0x25,0x85,0x8E,0x59,0x60,0x72,0x5A,0x73,0x70,0x7A"
    }

    simulator {}

    preferences {
        input "autoOff1", "number", title: "Auto Off Channel 1\n\nAutomatically turn switch off after this number of seconds\nRange: 0 to 32767", description: "Tap to set", required: false, range: "0..32767"
        input "autoOff2", "number", title: "Auto Off Channel 2\n\nAutomatically turn switch off after this number of seconds\nRange: 0 to 32767", description: "Tap to set", required: false, range: "0..32767"
        input "ledIndicator", "enum", title: "LED Indicator\n\nTurn LED indicator on when switch is:\n", description: "Tap to set", required: false, options:[["0": "On"], ["1": "Off"], ["2": "Disable"]], defaultValue: "0"
        input description: "Use the \"Z-Wave Association Tool\" SmartApp to set device associations. (Firmware 1.02+)\n\nGroup 2: Sends on/off commands to associated devices when switch is pressed (BASIC_SET).", title: "Associations", displayDuringSetup: false, type: "paragraph", element: "paragraph"
    }

    tiles {
        multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
            tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
                attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
                attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
                attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
                attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
            }
        }

        standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
            state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh"
        }

        valueTile("lastActivity", "device.lastActivity", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
            state "default", label: 'Last Activity: ${currentValue}',icon: "st.Health & Wellness.health9"
        }

        valueTile("icon", "device.icon", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
            state "default", label: '', icon: "https://inovelli.com/wp-content/uploads/Device-Handler/Inovelli-Device-Handler-Logo.png"
        }
    }
}

private static getCommandClassVersions() {
    [
            0x20: 1, // Basic
            0x25: 1, // Switch Binary
            0x70: 2, // Configuration
            0x60: 3, // Multi Channel
            0x8E: 2, // Multi Channel Association
            0x72: 2, // Manufacturer Specific
            0x85: 2, // Association
            0x86: 1, // Version
    ]
}

com.hubitat.app.DeviceWrapper getTargetDeviceByEndPoint(ep = null ) {
    if (ep) {
        return getChildDevices().find{ (it.deviceNetworkId.split("-ep")[-1] as Integer) == (ep as Integer)}
    } else {
        return device
    }
}

String secure(String cmd, ep = null ){
    if (ep) {
        return zwaveSecureEncap(zwave.multiChannelV4.multiChannelCmdEncap(sourceEndPoint: 0, bitAddress: 0, res01:0, destinationEndPoint: ep).encapsulate(cmd))
    } else {
        return zwaveSecureEncap(cmd)
    }
}

String secure(hubitat.zwave.Command cmd, ep = null ){
    if (ep) {
        return zwaveSecureEncap(zwave.multiChannelV4.multiChannelCmdEncap(sourceEndPoint: 0, bitAddress: 0, res01:0, destinationEndPoint: ep).encapsulate(cmd))
    } else {
        return zwaveSecureEncap(cmd)
    }
}

def parse(String description) {
    def result = []
    def cmd = zwave.parse(description, commandClassVersions)
    if (cmd) {
        result += zwaveEvent(cmd)
        log.debug "Parsed ${cmd} to ${result.inspect()}"
    } else {
        log.debug "Non-parsed event: ${description}"
    }

    def now
    if(location.timeZone)
        now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
    else
        now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
    sendEvent(name: "lastActivity", value: now, displayed:false)

    return result
}

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd, ep = null) {
    log.debug "BasicReport ${cmd} - ep ${ep}"
    if (ep) {
        def event
        childDevices.each {
            childDevice ->
                if (childDevice.deviceNetworkId == "$device.deviceNetworkId-ep$ep") {
                    childDevice.sendEvent(name: "switch", value: cmd.value == 0xFF ? "on" : "off")
                }
        }
        if (cmd.value == 0xFF) {
            event = [createEvent([name: "switch", value: "on"])]
        } else {
            def allOff = true
            childDevices.each {
                n ->
                    if (n.currentState("switch").value != "off") allOff = false
            }
            if (allOff) {
                event = [createEvent([name: "switch", value: "off"])]
            } else {
                event = [createEvent([name: "switch", value: "on"])]
            }
        }
        return event
    }
}

def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) {
    log.debug "SwitchBinaryReport ${cmd} - ep ${ep}"
    if (ep) {
        def event
        def childDevice = childDevices.find {
            it.deviceNetworkId == "$device.deviceNetworkId-ep$ep"
        }
        if (childDevice) {
            childDevice.sendEvent(name: "switch", value: cmd.value == 0xFF ? "on" : "off")
        }
        sendEvent(name: "ep" + ep, value: cmd.value == 0xFF ? "on" : "off", displayed: true)
        if (cmd.value == 0xFF) {
            event = [createEvent([name: "switch", value: "on"])]
        } else {
            def allOff = true
            childDevices.each {
                n->
                    if (n.deviceNetworkId != "$device.deviceNetworkId-ep$ep" && n.currentState("switch")?.value != "off") allOff = false
            }
            if (allOff) {
                event = [createEvent([name: "switch", value: "off"])]
            } else {
                event = [createEvent([name: "switch", value: "on"])]
            }
        }
        sendEvent(event)
        return []
    } else {
        def result = createEvent(name: "switch", value: cmd.value == 0xFF? "on" : "off", type: "digital")
        sendEvent(result)
        return [] // returns the result of reponse()
    }
}

def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
    // log.debug "MultiChannelCmdEncap ${cmd}"
    def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions)
    if (encapsulatedCommand) {
        zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
    }
}

def zwaveEvent(hubitat.zwave.commands.supervisionv1.SupervisionReport cmd, ep = null )
{
    log.debug "SupervisionReport ${cmd} - ep ${ep}"
    com.hubitat.app.DeviceWrapper targetDevice = getTargetDeviceByEndPoint(ep)

    ConcurrentHashMap whatThisDeviceSent = supervisionSentCommands?.get(device.getDeviceNetworkId() as String)

    switch (cmd.status as Integer)
    {
        case 0x00: // "No Support"
            whatWasSent = whatThisDeviceSent?.remove(cmd.sessionID as Integer)
            if (ignoreSupervisionNoSupportCode()) {
                if (logEnable) log.warn "Received a 'No Support' supervision report ${cmd} for command ${whatWasSent}, but this device has known problems with its Supervision implementation so the 'No Support' code was ignored."
            } else 	{
                log.warn "Device ${targetDevice.displayName}: Z-Wave Command supervision reported as 'No Support' for command ${whatWasSent}. If you see this warning repeatedly, please report as an issue on https://github.com/jvmahon/HubitatCustom/issues. Please provide the manufacturer, deviceType, and deviceId code for your device as shown on the device's Hubitat device web page."
            }
            break
        case 0x01: // "working"
            whatWasSent = whatThisDeviceSent?.get(cmd.sessionID as Integer)
            if (txtEnable) log.info "Device ${targetDevice.displayName}: Still processing command: ${whatWasSent}."
            runIn(5, supervisionCheck)
            break
        case 0x02: // "Fail"
            whatWasSent = whatThisDeviceSent?.remove(cmd.sessionID as Integer)
            log.warn "Device ${targetDevice.displayName}: Z-Wave supervised command reported failure. Failed command: ${whatWasSent}."
            sendUnsupervised(zwave.basicV1.basicGet(), ep)
            break
        case 0xFF: // "Success"
            whatWasSent = whatThisDeviceSent?.remove(cmd.sessionID as Integer)
            if (txtEnable || logEnable) log.info "Device ${targetDevice.displayName}: Device successfully processed supervised command ${whatWasSent}."
            break
    }
    if (whatThisDeviceSent?.size() < 1) unschedule(supervisionCheck)
}

def zwaveEvent(hubitat.zwave.commands.supervisionv1.SupervisionGet cmd, ep = null ) {
    //log.debug "SupervisionGet ${cmd} - ep ${ep}"
    hubitat.zwave.Command encapsulatedCommand = cmd.encapsulatedCommand(defaultParseMap)

    if (encapsulatedCommand) {
        if ( ep ) {
            zwaveEvent(encapsulatedCommand, ep)
        } else {
            zwaveEvent(encapsulatedCommand)
        }
    }

    hubitat.zwave.Command confirmationReport = (new hubitat.zwave.commands.supervisionv1.SupervisionReport(sessionID: cmd.sessionID, reserved: 0, moreStatusUpdates: false, status: 0xFF, duration: 0))
    sendHubCommand(new hubitat.device.HubAction(secure(confirmationReport, ep), hubitat.device.Protocol.ZWAVE))
}

def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
    log.debug "ManufacturerSpecificReport ${cmd}"
    def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
    log.debug "msr: $msr"
    updateDataValue("MSR", msr)
}

def zwaveEvent(hubitat.zwave.Command cmd) {
    // This will capture any commands not handled by other instances of zwaveEvent
    // and is recommended for development so you can see every command the device sends
    log.debug "Unhandled Event: ${cmd}"
}

def on() {
    log.debug "on()"
    commands([
            //zwave.switchAllV1.switchAllOn(),
            encap(zwave.basicV1.basicSet(value: 0xFF), 1),
            encap(zwave.basicV1.basicSet(value: 0xFF), 2)
    ])
}

def off() {
    log.debug "off()"
    commands([
            //zwave.switchAllV1.switchAllOff(),
            encap(zwave.basicV1.basicSet(value: 0x00), 1),
            encap(zwave.basicV1.basicSet(value: 0x00), 2)
    ])
}

def childOn(String dni) {
    log.debug "childOn($dni)"
    def cmds = []
    cmds << new hubitat.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
    //cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
    cmds
}

def childOff(String dni) {
    log.debug "childOff($dni)"
    def cmds = []
    cmds << new hubitat.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
    //cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
    cmds
}

def childRefresh(String dni) {
    log.debug "childRefresh($dni)"
    def cmds = []
    cmds << new hubitat.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
    cmds
}

def componentOn(cd) {
    if (infoEnable) log.info "${device.label?device.label:device.name}: componentOn($cd)"
    return childOn(cd.deviceNetworkId)
}

def componentOff(cd) {
    if (infoEnable) log.info "${device.label?device.label:device.name}: componentOff($cd)"
    return childOff(cd.deviceNetworkId)
}

def componentRefresh(cd) {
    if (infoEnable) log.info "${device.label?device.label:device.name}: componentRefresh($cd)"
    return childRefresh(cd.deviceNetworkId)
}

def poll() {
    log.debug "poll()"
    refresh()
}

def refresh() {
    log.debug "refresh()"
    commands([
            encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
            encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
    ])
}

def ping() {
    log.debug "ping()"
    refresh()
}

def installed() {
    refresh()
}

def configure() {
    log.debug "configure()"
    def cmds = initialize()
    commands(cmds)
}

def integer2Cmd(value, size) {
    try{
        switch(size) {
            case 1:
                [value]
                break
            case 2:
                short value1   = value & 0xFF
                short value2 = (value >> 8) & 0xFF
                [value2, value1]
                break
            case 3:
                short value1   = value & 0xFF
                short value2 = (value >> 8) & 0xFF
                short value3 = (value >> 16) & 0xFF
                [value3, value2, value1]
                break
            case 4:
                short value1 = value & 0xFF
                short value2 = (value >> 8) & 0xFF
                short value3 = (value >> 16) & 0xFF
                short value4 = (value >> 24) & 0xFF
                [value4, value3, value2, value1]
                break
        }
    } catch (e) {
        log.debug "Error: integer2Cmd $e Value: $value"
    }
}

def updated() {
    if (!state.lastRan || now() >= state.lastRan + 2000) {
        log.debug "updated()"
        state.lastRan = now()
        def cmds = initialize()
        commands(cmds)
    } else {
        log.debug "updated() ran within the last 2 seconds. Skipping execution."
    }
}

def initialize() {
    log.debug "initialize()"
    if (!childDevices) {
        createChildDevices()
    } else if (device.label != state.oldLabel) {
        childDevices.each {
            if (it.label == "${state.oldLabel} (CH${channelNumber(it.deviceNetworkId)})") {
                def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})"
                it.setLabel(newLabel)
            }
        }
        state.oldLabel = device.label
    }
    sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
    sendEvent(name: "numberOfButtons", value: 1, displayed: true)
    def cmds = processAssociations()
    cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: ledIndicator!=null? ledIndicator.toInteger() : 0, parameterNumber: 1, size: 1)
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 1)
    cmds << zwave.configurationV1.configurationSet(configurationValue: autoOff1!=null? integer2Cmd(autoOff1.toInteger(), 2) : integer2Cmd(0,2), parameterNumber: 2, size: 2)
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 2)
    cmds << zwave.configurationV1.configurationSet(configurationValue: autoOff2!=null? integer2Cmd(autoOff2.toInteger(), 2) : integer2Cmd(0,2), parameterNumber: 3, size: 2)
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 3)
    return cmds
}

def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
    log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'"
}

private encap(cmd, endpoint) {
    if (endpoint) {
        zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
    } else {
        cmd
    }
}

private command(hubitat.zwave.Command cmd) {
    if (state.sec) {
        zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
    } else {
        cmd.format()
    }
}

private commands(commands, delay = 500) {
    delayBetween(commands.collect {
        command(it)
    }, delay)
}

private static channelNumber(String dni) {
    dni.split("-ep")[-1] as Integer
}
private void createChildDevices() {
    state.oldLabel = device.label
    for (i in 1..2) {
        addChildDevice("hubitat", "Generic Component Switch", "${device.deviceNetworkId}-ep${i}", [completedSetup: true, label: "${device.displayName} (CH${i})",
            isComponent: false, componentName: "ep$i", componentLabel: "Channel $i"
        ])
    }
}

def setDefaultAssociations() {
    def smartThingsHubID = String.format('%02x', zwaveHubNodeId).toUpperCase()
    state.defaultG1 = [smartThingsHubID]
    state.defaultG2 = []
    state.defaultG3 = []
}

def setAssociationGroup(group, nodes, action, endpoint = null){
    // Normalize the arguments to be backwards compatible with the old method
    action = "${action}" == "1" ? "Add" : "${action}" == "0" ? "Remove" : "${action}" // convert 1/0 to Add/Remove
    group  = "${group}" =~ /\d+/ ? (group as int) : group                             // convert group to int (if possible)
    nodes  = [] + nodes ?: [nodes]                                                    // convert to collection if not already a collection

    if (! nodes.every { it =~ /[0-9A-F]+/ }) {
        log.error "invalid Nodes ${nodes}"
        return
    }

    if (group < 1 || group > maxAssociationGroup()) {
        log.error "Association group is invalid 1 <= ${group} <= ${maxAssociationGroup()}"
        return
    }

    def associations = state."desiredAssociation${group}"?:[]
    nodes.each {
        node = "${it}"
        switch (action) {
            case "Remove":
                if (logEnable) log.debug "Removing node ${node} from association group ${group}"
                associations = associations - node
                break
            case "Add":
                if (logEnable) log.debug "Adding node ${node} to association group ${group}"
                associations << node
                break
        }
    }
    state."desiredAssociation${group}" = associations.unique()
}

def maxAssociationGroup(){
    if (!state.associationGroups) {
        if (logEnable) log.debug "Getting supported association groups from device"
        zwave.associationV2.associationGroupingsGet() // execute the update immediately
    }
    (state.associationGroups?: 5) as int
}

def processAssociations(){
    def cmds = []
    setDefaultAssociations()
    def associationGroups = maxAssociationGroup()
    for (int i = 1; i <= associationGroups; i++){
        if(state."actualAssociation${i}" != null){
            if(state."desiredAssociation${i}" != null || state."defaultG${i}") {
                def refreshGroup = false
                ((state."desiredAssociation${i}"? state."desiredAssociation${i}" : [] + state."defaultG${i}") - state."actualAssociation${i}").each {
                    if (logEnable) log.debug "Adding node $it to group $i"
                    cmds << zwave.associationV2.associationSet(groupingIdentifier:i, nodeId:hubitat.helper.HexUtils.hexStringToInt(it))
                    refreshGroup = true
                }
                ((state."actualAssociation${i}" - state."defaultG${i}") - state."desiredAssociation${i}").each {
                    if (logEnable) log.debug "Removing node $it from group $i"
                    cmds << zwave.associationV2.associationRemove(groupingIdentifier:i, nodeId:hubitat.helper.HexUtils.hexStringToInt(it))
                    refreshGroup = true
                }
                if (refreshGroup) cmds << zwave.associationV2.associationGet(groupingIdentifier:i)
                else if (logEnable) log.debug "There are no association actions to complete for group $i"
            }
        } else {
            if (logEnable) log.debug "Association info not known for group $i. Requesting info from device."
            cmds << zwave.associationV2.associationGet(groupingIdentifier:i)
        }
    }
    return cmds
}

void zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
    def temp = []
    if (cmd.nodeId != []) {
        cmd.nodeId.each {
            temp += it.toString().format( '%02x', it.toInteger() ).toUpperCase()
        }
    }
    state."actualAssociation${cmd.groupingIdentifier}" = temp
    log.debug "Associations for Group ${cmd.groupingIdentifier}: ${temp}"
    updateDataValue("associationGroup${cmd.groupingIdentifier}", "$temp")
}

def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationGroupingsReport cmd) {
    log.debug "Supported association groups: ${cmd.supportedGroupings}"
    state.associationGroups = cmd.supportedGroupings
    createEvent(name: "groups", value: cmd.supportedGroupings)
}

void zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
    log.debug cmd
    if(cmd.applicationVersion && cmd.applicationSubVersion) {
        def firmware = "${cmd.applicationVersion}.${cmd.applicationSubVersion.toString().padLeft(2,'0')}"
        state.needfwUpdate = "false"
        sendEvent(name: "status", value: "fw: ${firmware}")
        updateDataValue("firmware", firmware)
    }
}

I Hope you find these helpful!!

4 Likes