Device:refresh() method put in a function to handle it in a subdriver or the main driver Zwave (Z-Wave Switch stock and others)

Hi @nayelyz

device:refresh() method put in a function to handle it in a subdriver or the main driver Zwave (Z-Wave Switch stock and others) causes the driver to enter an infinite loop until the driver is reset

local function device_refresh( self, device)
    device:refresh()
end

local fibaro_double_switch = {
  NAME = "fibaro double switch",
  capability_handlers = {
    [capabilities.refresh.ID] = {
      [capabilities.refresh.commands.refresh.NAME] = device_refresh,
    }
  },
Loop Logs after refresh command until driver reinitialize it self

2022-09-30T19:12:29.773944967+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:29.799463301+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:29.865944967+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:29.892842634+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:29.949766634+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:30.021680967+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:30.132494967+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:30.769417301+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:31.297622968+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:31.420268635+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:31.507650301+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:31.610564968+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2022-09-30T19:12:41.137265639+00:00 TRACE Z-Wave Switch and Child Mc Setup driver zwave_switch with lifecycle handlers:
DeviceLifecycleDispatcher: zwave_switch
default_handlers:
added:
removed:
infoChanged:
driverSwitched:
doConfigure:
init:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → eaton accessory dimmer
default_handlers:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → Inovelli LED
default_handlers:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → inovelli dimmer
default_handlers:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → Dawon smart plug
default_handlers:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → Inovelli 2 channel smart plug
default_handlers:
init:
doConfigure:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → zwave dual switch
default_handlers:
added:
child_dispatchers:
DeviceLifecycleDispatcher: zwave_switch → zwave dual switch → fibaro walli double switch
default_handlers:
init:
child_dispatchers:

With Z-wave Switch stock with device:refresh() in subdriver “fibaro-double-switch”
Tihis log is after driver self reinitialized and to perform added lifecycle added, that contains device:refresh()

2022-09-30T19:10:32.915238004+00:00 TRACE Z-Wave Switch Z-Wave Device: bd5c15c7-76f5-4430-b95d-c8ea349e9f61
Manufacturer: 0x010F Product Type: 0x0203 Product ID: 0x1000
[0]: SWITCH_MULTILEVEL, SWITCH_BINARY, DEVICE_RESET_LOCALLY, ASSOCIATION, CONFIGURATION, MULTI_CHANNEL_ASSOCIATION, MULTI_CHANNEL, PROTECTION, CENTRAL_SCENE, ZWAVEPLUS_INFO, VERSION, MANUFACTURER_SPECIFIC, ASSOCIATION_GRP_INFO, POWERLEVEL, APPLICATION_STATUS, CRC_16_ENCAP, METER, NOTIFICATION, SECURITY, FIRMWARE_UPDATE_MD [1]: SWITCH_MULTILEVEL, SWITCH_BINARY, DEVICE_RESET_LOCALLY, ASSOCIATION, CONFIGURATION, MULTI_CHANNEL_ASSOCIATION, MULTI_CHANNEL, PROTECTION, CENTRAL_SCENE, ZWAVEPLUS_INFO, VERSION, MANUFACTURER_SPECIFIC, ASSOCIATION_GRP_INFO, POWERLEVEL, APPLICATION_STATUS, CRC_16_ENCAP, METER, NOTIFICATION, SECURITY, FIRMWARE_UPDATE_MD
2022-09-30T19:10:32.930331004+00:00 TRACE Z-Wave Switch Received event with handler _resync
2022-09-30T19:10:32.939160004+00:00 TRACE Z-Wave Switch Received event with handler environment_info
2022-09-30T19:10:32.982978338+00:00 TRACE Z-Wave Switch Found DeviceLifecycleDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:32.989219338+00:00 DEBUG Z-Wave Switch Luz Entrada device thread event handled
2022-09-30T19:10:32.999226671+00:00 TRACE Z-Wave Switch Received event with handler environment_info
2022-09-30T19:10:33.004994004+00:00 DEBUG Z-Wave Switch Z-Wave hub node ID environment changed.
2022-09-30T19:10:33.027262338+00:00 TRACE Z-Wave Switch Received event with handler device_lifecycle
2022-09-30T19:10:33.039204671+00:00 INFO Z-Wave Switch <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> received lifecycle event: added
2022-09-30T19:10:33.065859004+00:00 TRACE Z-Wave Switch Found DeviceLifecycleDispatcher handler in zwave_switch
2022-09-30T19:10:33.077784004+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.089521338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.101314671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.192578338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.236287671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.264326338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.279162671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch2022-09-30T19:10:32.915238004+00:00 TRACE Z-Wave Switch Z-Wave Device: bd5c15c7-76f5-4430-b95d-c8ea349e9f61
Manufacturer: 0x010F Product Type: 0x0203 Product ID: 0x1000
[0]: SWITCH_MULTILEVEL, SWITCH_BINARY, DEVICE_RESET_LOCALLY, ASSOCIATION, CONFIGURATION, MULTI_CHANNEL_ASSOCIATION, MULTI_CHANNEL, PROTECTION, CENTRAL_SCENE, ZWAVEPLUS_INFO, VERSION, MANUFACTURER_SPECIFIC, ASSOCIATION_GRP_INFO, POWERLEVEL, APPLICATION_STATUS, CRC_16_ENCAP, METER, NOTIFICATION, SECURITY, FIRMWARE_UPDATE_MD [1]: SWITCH_MULTILEVEL, SWITCH_BINARY, DEVICE_RESET_LOCALLY, ASSOCIATION, CONFIGURATION, MULTI_CHANNEL_ASSOCIATION, MULTI_CHANNEL, PROTECTION, CENTRAL_SCENE, ZWAVEPLUS_INFO, VERSION, MANUFACTURER_SPECIFIC, ASSOCIATION_GRP_INFO, POWERLEVEL, APPLICATION_STATUS, CRC_16_ENCAP, METER, NOTIFICATION, SECURITY, FIRMWARE_UPDATE_MD
2022-09-30T19:10:32.930331004+00:00 TRACE Z-Wave Switch Received event with handler _resync
2022-09-30T19:10:32.939160004+00:00 TRACE Z-Wave Switch Received event with handler environment_info
2022-09-30T19:10:32.982978338+00:00 TRACE Z-Wave Switch Found DeviceLifecycleDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:32.989219338+00:00 DEBUG Z-Wave Switch Luz Entrada device thread event handled
2022-09-30T19:10:32.999226671+00:00 TRACE Z-Wave Switch Received event with handler environment_info
2022-09-30T19:10:33.004994004+00:00 DEBUG Z-Wave Switch Z-Wave hub node ID environment changed.
2022-09-30T19:10:33.027262338+00:00 TRACE Z-Wave Switch Received event with handler device_lifecycle
2022-09-30T19:10:33.039204671+00:00 INFO Z-Wave Switch <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> received lifecycle event: added
2022-09-30T19:10:33.065859004+00:00 TRACE Z-Wave Switch Found DeviceLifecycleDispatcher handler in zwave_switch
2022-09-30T19:10:33.077784004+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.089521338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.101314671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.192578338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.236287671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.264326338+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch
2022-09-30T19:10:33.279162671+00:00 TRACE Z-Wave Switch Found CapabilityCommandDispatcher handler in zwave_switch → fibaro double switch

I have seen in several subdrivers that this method is not used directly and a GET command is used to obtain the status of each C.C.

The Z-Wave Switch stock and others have in main driver init.lua device:refresh() in the function that handles the lifecycle added. It works fine normally

local function device_added(driver, device)
  device:refresh()
end

-------------------------------------------------------------------------------------------
-- Register message handlers and run driver
-------------------------------------------------------------------------------------------
local driver_template = {
  supported_capabilities = {
    capabilities.switch,
    capabilities.switchLevel,
    capabilities.battery,
    capabilities.energyMeter,
    capabilities.powerMeter,
    capabilities.colorControl,
    capabilities.button,
    capabilities.temperatureMeasurement,
    capabilities.relativeHumidityMeasurement
  },
  sub_drivers = {
    require("eaton-accessory-dimmer"),
    require("inovelli-LED"),
    require("dawon-smart-plug"),
    require("inovelli-2-channel-smart-plug"),
    require("zwave-dual-switch"),
    require("eaton-anyplace-switch"),
    require("fibaro-wall-plug-us"),
    require("dawon-wall-smart-switch"),
    require("zooz-power-strip"),
    require("aeon-smart-strip"),
    require("qubino-switches"),
    require("fibaro-double-switch"),
    require("fibaro-single-switch"),
    require("eaton-5-scene-keypad"),
    require("ecolink-switch"),
    require("zooz-zen-30-dimmer-relay")
  },
  lifecycle_handlers = {
    init = device_init,
    infoChanged = info_changed,
    doConfigure = do_configure,
    added = device_added
  }

Can device:refresh() be used to handle Refresh capability command manually on Z-Wave drivers as used in Zigbee without problems?

There’s your loop - you’re calling refresh from within the refresh handler

I don’t understand why.

It only enters this function when the External Refresh command is received and what this function executes is the reading of the attributes in zigbee or the C.C. in Zwave, it doesn’t resend the refresh() command and so don’t have to go back in here.

I did this test on a zigbee controller. I added a print <<<<<<< refresh function handler>>>>>>>> to see how many times it executes the function and it works perfectly in zigbee drivers, it only executes it once:

local function device_refresh( self, device)
   print("<<<<<<< refresh fuction handler>>>>>>>>")
    device:refresh()

end

---- Driver template config
local zigbee_switch_driver_template = {
  supported_capabilities = {
    capabilities.switch,
    capabilities.battery,
    capabilities.refresh
  },
  lifecycle_handlers = {
    infoChanged = random.do_Preferences,
    init = random.do_init,
    removed = random.do_removed,
    driverSwitched = driver_Switched,
    doConfigure = do_configure
  },
  capability_handlers = {
    [capabilities.refresh.ID] = {
      [capabilities.refresh.commands.refresh.NAME] = device_refresh,
    },

2022-09-30T21:01:11.822078813+00:00 TRACE Zigbee Switch Mc-test Received event with handler capability
2022-09-30T21:01:11.830761480+00:00 INFO Zigbee Switch Mc-test <ZigbeeDevice: 0a4b023f-c186-43a2-b025-938277836195 [0x4B10] (Lidl Plug)> received command: {“args”:{},“capability”:“refresh”,“command”:“refresh”,“component”:“main”,“positional_args”:{}}
2022-09-30T21:01:11.836742480+00:00 TRACE Zigbee Switch Mc-test Found CapabilityCommandDispatcher handler in Zigbee_Switch
2022-09-30T21:01:11.841834480+00:00 PRINT Zigbee Switch Mc-test <<<<<<< refresh fuction handler>>>>>>>>
2022-09-30T21:01:11.850298480+00:00 INFO Zigbee Switch Mc-test <ZigbeeDevice: 0a4b023f-c186-43a2-b025-938277836195 [0x4B10] (Lidl Plug)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x4B10, dest_endpoint: 0x0B, profile: 0x0104, cluster: OnOff >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x00, seqno: 0x00, ZCLCommandId: 0x00 >, < ReadAttribute || AttributeId: 0x0000 > > >
2022-09-30T21:01:11.876072813+00:00 DEBUG Zigbee Switch Mc-test Lidl Plug device thread event handled
2022-09-30T21:01:11.925079146+00:00 TRACE Zigbee Switch Mc-test Received event with handler zigbee
2022-09-30T21:01:11.936168813+00:00 INFO Zigbee Switch Mc-test <ZigbeeDevice: 0a4b023f-c186-43a2-b025-938277836195 [0x4B10] (Lidl Plug)> received Zigbee message: < ZigbeeMessageRx
|| type: 0x00, < AddressHeader || src_addr: 0x4B10, src_endpoint: 0x0B, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: OnOff >, lqi: 0xC8, rssi: -71, body_length: 0x0008, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x52, ZCLCommandId: 0x01 >, < ReadAttributeResponse || < AttributeRecord || AttributeId: 0x0000, ZclStatus: SUCCESS, DataType: Boolean, OnOff: false > > > >
2022-09-30T21:01:11.971677146+00:00 TRACE Zigbee Switch Mc-test Found ZigbeeMessageDispatcher handler in Zigbee_Switch
2022-09-30T21:01:11.978068480+00:00 INFO Zigbee Switch Mc-test Executing ZclClusterAttributeValueHandler: cluster: OnOff, attribute: OnOff
2022-09-30T21:01:11.988868813+00:00 PRINT Zigbee Switch Mc-test value.value >>>>>>>>>>> false
2022-09-30T21:01:11.994052146+00:00 PRINT Zigbee Switch Mc-test New value.value >>>>>>>>>>> false
2022-09-30T21:01:12.004728480+00:00 INFO Zigbee Switch Mc-test <ZigbeeDevice: 0a4b023f-c186-43a2-b025-938277836195 [0x4B10] (Lidl Plug)> emitting event: {“attribute_id”:“signalMetrics”,“capability_id”:“legendabsolute60149.signalMetrics”,“component_id”:“main”,“state”:{“value”:“dni: 0x4B10, lqi: 200, rssi: -71dBm”},“visibility”:{“displayed”:false}}
2022-09-30T21:01:12.041103146+00:00 PRINT Zigbee Switch Mc-test <<<<<<< Power meter Timer >>>>> OFF
2022-09-30T21:01:12.047384146+00:00 INFO Zigbee Switch Mc-test <ZigbeeDevice: 0a4b023f-c186-43a2-b025-938277836195 [0x4B10] (Lidl Plug)> emitting event: {“attribute_id”:“switch”,“capability_id”:“switch”,“component_id”:“main”,“state”:{“value”:“off”}}
2022-09-30T21:01:12.072069146+00:00 DEBUG Zigbee Switch Mc-test Lidl Plug device thread event handled
2022-09-30T21:01:33.296563149+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:02:03.305179486+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:02:33.312842823+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:03:03.319861160+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:03:33.317558497+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:04:03.322744833+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:04:33.322983883+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:05:03.338529898+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:05:33.335751579+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:06:03.346205260+00:00 DEBUG Zigbee Switch Mc-test driver device thread event handled
2022-09-30T21:06:12.063239264+00:00 TRACE Zigbee Switch Mc-test Received event with handler zigbee

I asked the team and they mentioned the refresh function on a Z-Wave device just sends the refresh command to the driver, which is why this ends up in an infinite loop. So:

2 Likes

Feedback - this isn’t a good architecture - it should behave the same on both objects since both are special instances of the parent Driver object and since zwave default_refresh accomplishes the same outcome as the ZigBee refresh, it should be normalized and behave the same way in both cases.

2 Likes

I can’t read that without hearing fingernails dragging down a blackboard.

I am sure it may have applications outside creating infinite loops but it instinctively feels like something to be hidden away in a jam jar on a shelf in the shed.

1 Like

I have read this thread multiple times and I don’t grasp the context of the response. Let me try to understand what is being said. Trying to understand how to use refresh for a Z-WAVE device. I plan to use the refresh function to ensure that Smartthings driver state and the switch are in sync. I am doing so, so that if my rules ask for a power on, I can ignore it if the switch status state is already on. This opens the possibility that the driver state and the physical state could, at times, become out of sync, and thus I would use the refresh command to force a resend.

  1. I added refresh as a supported capability.
  2. I added a refresh capability handler. In this handler, I will add logic to sync the Smartthings state and physical device state.
  1. The switch exposes a refresh capability which, it looks like, is invoked if I swipe down on the switch panel.

All good, I think.

Now, I am trying to figure out the following:

  1. Is this the correct approach to address the possible issue?
  2. How does refresh and default:refresh come to bear in this? And how should I handle?
  3. Am I correct to assume that a call device:refresh() would invoke (and only invoke) my capability handler?

Thanks all,

Hi @harobinson

To do what you want you don’t need to write a specific line of code. The default switch.lua libraries in the firmware do it all automatically.
These are the libraries that are in the firmware 47.x hub

This is the code from st/zwave/defaults/switch.lua that does everything you want to do:

-- Copyright 2021 SmartThings
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
local capabilities = require "st.capabilities"
local log = require "log"
--- @type st.zwave.CommandClass
local cc  = require "st.zwave.CommandClass"
--- @type st.zwave.constants
local constants = require "st.zwave.constants"
--- @type st.zwave.CommandClass.Basic
local Basic = (require "st.zwave.CommandClass.Basic")({version=1,strict=true})
--- @type st.zwave.CommandClass.SwitchBinary
local SwitchBinary = (require "st.zwave.CommandClass.SwitchBinary")({version=2,strict=true})
--- @type st.zwave.CommandClass.SwitchMultilevel
local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({version=4,strict=true})

local zwave_handlers = {}

--- Default handler for basic, binary and multilevel switch reports for
--- switch-implementing devices
---
--- This converts the command value from 0 -> Switch.switch.off, otherwise
--- Switch.switch.on.
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param cmd st.zwave.CommandClass.SwitchMultilevel.Report|st.zwave.CommandClass.SwitchBinary.Report|st.zwave.CommandClass.Basic.Report
function zwave_handlers.report(driver, device, cmd)
  local event
  if cmd.args.value ~= nil then
    if cmd.args.value == SwitchBinary.value.OFF_DISABLE then
      event = capabilities.switch.switch.off()
    else
      event = capabilities.switch.switch.on()
    end
  else
    if cmd.args.target_value == SwitchBinary.value.OFF_DISABLE then
      event = capabilities.switch.switch.off()
    else
      event = capabilities.switch.switch.on()
    end
  end
  device:emit_event_for_endpoint(cmd.src_channel, event)
end

--- Interrogate the device's supported command classes to determine whether a
--- BASIC, SWITCH_BINARY or SWITCH_MULTILEVEL set should be issued to fulfill
--- the on/off capability command.
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param value number st.zwave.CommandClass.SwitchBinary.value.OFF_DISABLE or st.zwave.CommandClass.SwitchBinary.value.ON_ENABLE
--- @param command table The capability command table
local function switch_set_helper(driver, device, value, command)
  local set
  local get
  local delay = constants.DEFAULT_GET_STATUS_DELAY

  if device:is_cc_supported(cc.SWITCH_MULTILEVEL) then
    log.trace_with({ hub_logs = true }, "SWITCH_MULTILEVEL supported.")
    set = SwitchMultilevel:Set({
      value = value,
      duration = constants.DEFAULT_DIMMING_DURATION
    })
    delay = constants.MIN_DIMMING_GET_STATUS_DELAY
    get = SwitchMultilevel:Get({})
  elseif device:is_cc_supported(cc.SWITCH_BINARY) then
    log.trace_with({ hub_logs = true }, "SWITCH_BINARY supported.")
    set = SwitchBinary:Set({
      target_value = value,
      duration = 0
    })
    get = SwitchBinary:Get({})
  else
    log.trace_with({ hub_logs = true }, "SWITCH_BINARY and SWITCH_MULTILEVEL NOT supported. Use Basic.Set()")
    set = Basic:Set({
      value = value
    })
    get = Basic:Get({})
  end
  device:send_to_component(set, command.component)
  local query_device = function()
    device:send_to_component(get, command.component)
  end
  device.thread:call_with_delay(delay, query_device)
end

local capability_handlers = {}

--- Issue a switch-on command to the specified device.
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param command table The capability command table
function capability_handlers.on(driver, device, command)
  switch_set_helper(driver, device, SwitchBinary.value.ON_ENABLE, command)
end

--- Issue a switch-off command to the specified device.
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param command table The capability command table
function capability_handlers.off(driver, device, command)
  switch_set_helper(driver, device, SwitchBinary.value.OFF_DISABLE, command)
end

--- Find single best match from
--- {SwitchMultilevel:Get(), SwitchBinary:Get(), Basic:Get()}
--- based on supported combination of 2 capabilities:{`switch` and `switch level`}
--- and 3 command classes { Basic, SwitchBinary, SwitchMultilevel }
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param component string
--- @param endpoint integer
local function get_refresh_commands(driver, device, component, endpoint)
  if device:supports_capability_by_id(capabilities.switchLevel.ID, component) and device:is_cc_supported(cc.SWITCH_MULTILEVEL, endpoint) then
    -- it is exeeds `SwitchBinary` default driver scope of responcibility
    -- but we want to handle this special case: issue command for `SwitchMultilevel`
    -- if supported
    return {SwitchMultilevel:Get({}, {dst_channels = {endpoint}})}
  elseif device:supports_capability_by_id(capabilities.switch.ID, component) and device:is_cc_supported(cc.SWITCH_BINARY, endpoint) then
    return {SwitchBinary:Get({}, {dst_channels = {endpoint}})}
  elseif device:supports_capability_by_id(capabilities.switch.ID, component) and device:is_cc_supported(cc.BASIC, endpoint) then
    return {Basic:Get({}, {dst_channels = {endpoint}})}
  end
end

--- @class st.zwave.defaults.switch
--- @alias switch_defaults st.zwave.defaults.switch
--- @field public zwave_handlers table
--- @field public capability_handlers table
--- @field public get_refresh_commands function
local switch_defaults = {
  zwave_handlers = {
    [cc.BASIC] = {
      [Basic.REPORT] = zwave_handlers.report
    },
    [cc.SWITCH_BINARY] = {
      [SwitchBinary.REPORT] = zwave_handlers.report
    },
    [cc.SWITCH_MULTILEVEL] = {
      [SwitchMultilevel.REPORT] = zwave_handlers.report
    }
  },
  capability_handlers = {
    [capabilities.switch.commands.on] = capability_handlers.on,
    [capabilities.switch.commands.off] = capability_handlers.off
  },
  get_refresh_commands = get_refresh_commands,
}

return switch_defaults

Ok, so I am learning more and more as I go along.

I am writing an edge driver for a Leviton VRCS4 device. So far, I have written my own capability handlers and z-wave handlers.

Question: do these replace the default handlers or are they included in addition?

Surely if I monitor the driver through logical, I don’t see any of these commands being issued?

Thanks

Henry

  1. I would suggest that the refresh capability is a bit of a distraction in this case. It’s intended use is, arguably, in working with devices that do not routinely inform SmartThings of status changes at their end, requiring SmartThings to be brought up to date before any interactions. So if you were using the mobile app you would always request a refresh before reading the status or issuing any commands, and similarly any automations involving the device would call refresh first. For something like a Z-Wave device your driver, working with the libraries, should already be doing anything that you might conceivably put in a refresh command handler to avoid the ‘possible issue’ happening in the first place. That doesn’t mean you shouldn’t have one, it is just that its purpose would be to try and restore sanity when something has gone wrong that the driver can’t recover from.
  2. My understanding is that, subject to your device behaving in a standard fashion and not doing anything too exotic, if you did want to create a refresh command handler from scratch it would only need to call device.default_refresh() as that will do something sensible.
  3. In the Z-Wave libraries, device.refresh() seems to be the equivalent of sending the refresh command and so invoking your capability handler.
  4. I know there wasn’t a 4) but Mariano’s response wasn’t there when I started typing and I think is complementary to this one anyway.

If you don’t write the capbility and zwave handlers then the Hub firmware defaults are executed.

If you write the handlers then the ones you write will be executed

This would be a basic inti.lua, which would work with the defaults for a profile with switch and refresh capabilities

profile:

name: switch
components:
  - id: main
    capabilities:
      - id: switch
        version: 1
      - id: refresh
        version: 1
    categories:
      - name: Switch

init.lua

-- switch test driver

local function device_added(driver, device)
 device:refresh()
end
-------------------------------------------------------------------------------------------
-- Register message handlers and run driver
-------------------------------------------------------------------------------------------
local driver_template = {
 supported_capabilities = {
   capabilities.switch,
   capabilities.refresh,
 },
 zwave_handlers = {

 },

 lifecycle_handlers = {
    added = device_added
 }
}

defaults.register_for_default_handlers(driver_template, driver_template.supported_capabilities)
--- @type st.zwave.Driver
local switch = ZwaveDriver("zwave_switch", driver_template)
switch:run()

Add a fingerprints.yml and a config.yml

you deploy everything in the corresponding profiles and src folders as you can see in the stock beta examples in github and you have a driver.

If you need to add some configuration parameters or preferences, look at how the stock driver does it with preferences.lua and configuration.lua on github drivers

This makes sense. If I understand what you are saying, the default handlers would be used for any of the supported capabilities.

Is it also correct to assume that if I register a z-wave handler, then it would replace the default handler?

    supported_capabilities = {
    capabilities.switch,
    capabilities.switchLevel,
    capabilities.refresh
  },
  --]]
    capability_handlers = {
    [capabilities.switch.ID] = {
      [capabilities.switch.commands.on.NAME] = handle_on,
      [capabilities.switch.commands.off.NAME] = handle_off,
    },
    [capabilities.switchLevel.ID] = {
      [capabilities.switchLevel.commands.setLevel.NAME] = switch_level_set
    },

    },

Correct?

So, my handler would be used for capabilities.switch, capabilities.switchLevel, but the default would be used for capabilities.refresh?

As defined, your custom handler would handle the switch on, off and level commands received from the app or routines and scenes.

The default handlers would handle:

  • the on, off, level commands received from the physical device, to emit the status received to the app and platform
  • the refresh command received from the app or from the driver itself with device.refresh()

This is starting to make sense. But when you have that the default handlers would handle the commands to emit status to the app or platform, do the default handlers do anything other than send events to your driver (that the command was issued, i.e. you get a Z-wave message) or somehow change the status of the device? What would show up in the log (“logcat”) as to what the default handler would do?

I am asking because I wrote a custom handler for each capability and am responding to the status (z-wave message) that I receive from the hub.

  • This is the log of a command On received fron App and handled by a custom handler in a main driver init.lua:
    The PRINT logs I have put them to debug what functions the driver executes

2023-04-02T19:35:55.618749719+00:00 TRACE Z-Wave Switch and Child Mc Z-Wave command(6e799936) queued for radio transmission: CC:Switch Binary, CID:0x01
2023-04-02T19:35:55.625580385+00:00 INFO Z-Wave Switch and Child Mc <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> received command: {“args”:{},“capability":"switch”,“command”:“on”,“component”:“main”,“positional_args”:{}}
2023-04-02T19:35:55.626982719+00:00 TRACE Z-Wave Switch and Child Mc Found CapabilityCommandDispatcher handler in zwave_switch
2023-04-02T19:35:55.629095052+00:00 PRINT Z-Wave Switch and Child Mc <<<<< switch_on_handler in main driver >>>>>>>
2023-04-02T19:35:55.631210385+00:00 PRINT Z-Wave Switch and Child Mc <<<<< switch_set_helper in main driver >>>>>>>

  • This is the command send by custom handler to device to set On the switch

2023-04-02T19:35:55.633406719+00:00 INFO Z-Wave Switch and Child Mc <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> sending Z-Wave command: {args={duration=0, target_value=“ON_ENABLE”}, cmd_class=“SWITCH_BINARY”, cmd_id="SET", dst_channels={1}, encap=“AUTO”, payload=“\xFF\x00”, src_channel=0, version=2}
2023-04-02T19:35:55.651302385+00:00 DEBUG Z-Wave Switch and Child Mc Luz Entrada device thread event handled
2023-04-02T19:35:55.652168052+00:00 DEBUG Z-Wave Switch and Child Mc Luz Entrada device thread event handled
2023-04-02T19:35:56.298439385+00:00 TRACE Z-Wave Switch and Child Mc Z-Wave command(6e799936) transmit status: TRANSMIT_COMPLETE_OK

  • This is the command send by custom handler to Get te current status of real switch after execute the On command:

2023-04-02T19:35:56.664388052+00:00 TRACE Z-Wave Switch and Child Mc Z-Wave command(649ecbb7) queued for radio transmission: CC:Switch Binary, CID:0x02
2023-04-02T19:35:56.670690052+00:00 INFO Z-Wave Switch and Child Mc <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> sending Z-Wave command: {args={}, cmd_class=“SWITCH_BINARY”, cmd_id=“GET”, dst_channels={1}, encap=“AUTO”, payload=“”, src_channel=0, version=1}
2023-04-02T19:35:56.672262052+00:00 DEBUG Z-Wave Switch and Child Mc Luz Entrada device thread event handled

  • This is the device response to Get command:

2023-04-02T19:35:57.384329386+00:00 TRACE Z-Wave Switch and Child Mc Received event with handler unnamed
2023-04-02T19:35:57.385320719+00:00 INFO Z-Wave Switch and Child Mc <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> received Z-Wave command: {args={value=“ON_ENABLE”}, cmd_class="SWITCH_BINARY", cmd_id="REPORT", dst_channels={0}, encap=“S0”, payload=“\xFF”, src_channel=1, version=1}

  • This is emitting On event to App and platform, executed by the subdriver: fibaro double switch that was defined to handle the the Zwave cmd_class="SWITCH_BINARY.REPORT received

2023-04-02T19:35:57.409105386+00:00 TRACE Z-Wave Switch and Child Mc Found ZwaveDispatcher handler in zwave_switch → fibaro double switch
2023-04-02T19:35:57.415764052+00:00 PRINT Z-Wave Switch and Child Mc <<<<< zwave_handlers_report in subdriver >>>>>>>
2023-04-02T19:35:57.417126719+00:00 INFO Z-Wave Switch and Child Mc <ZwaveDevice: bd5c15c7-76f5-4430-b95d-c8ea349e9f61 [1E] (Luz Entrada)> emitting event: {“attribute_id”:“switch”,“capability_id”:“switch”,“component_id”:“main”,“state”:{“value”:“on”}}

If the default were executed, you would see the same thing, but with the debug print that has the defualt code written.