Zigbee Driver Capability Defaults

Within the ZigbeeDriver you will be registering a number of zigbee_handlers which are used handle incoming Zigbee messages from a device. Provided within the library, however, are a number of default implementations that follow the natural mapping of Zigbee ZCL attribute/command -> SmartThings capability event. These can either be manually referenced from your driver by simply requiring the correct default file, or you can have all the defaults registered by making a call do register_for_default_handlers(driver_template, { capabilities.switch, capabilities.switchLevel }) listing all the capabilities you are interested in registering the default handlers for.

Each Zigbee defaults file will be named according the single SmartThings capability it is providing defaults for and it will contain several key components.

Handler Functions

First any Zigbee message or capability command handlers that are specific to the capability will be defined within the file. Below are a couple of examples of these functions defined for the switch capability:

--- Default handler for on off attribute on the on off cluster
---
--- This converts the boolean value from true -> Switch.switch.on and false to Switch.switch.off.
---
--- @param driver Driver The current driver running containing necessary context for execution
--- @param device ZigbeeDevice The device this message was received from containing identifying information
--- @param value Boolean the value of the On Off cluster On Off attribute
function switch_defaults.on_off_attr_handler(driver, device, value)
  local attr = capabilities.switch.switch
  device:emit_event(value.value and attr.on() or attr.off())
end

--- Default handler for the Switch.on command
---
--- This will send the on command to the on off cluster
---
--- @param driver Driver The current driver running containing necessary context for execution
--- @param device Device The device this message was received from containing identifying information
--- @param command table The capability command table
function switch_defaults.on(driver, device, command)
  device:send(zcl_clusters.OnOffCluster.commands.client.On(device))
end

--- Default handler for the Switch.off command
---
--- This will send the off command to the on off cluster
---
--- @param driver Driver The current driver running containing necessary context for execution
--- @param device Device The device this message was received from containing identifying information
--- @param command table The capability command table
function switch_defaults.off(driver, device, command)
  device:send(zcl_clusters.OnOffCluster.commands.client.Off(device))
end

These functions will be one of the Zigbee handlers for messages from the device or capability handlers for capability commands. The number and types that are present are entirely dependent on the Zigbee to SmartThings mapping and thus will vary wildly depending on the capability.

zigbee_handlers

The zigbee_handlers defined on the defaults module will be the mapping that will describe how the handler functions get registered to handle the appropriate Zigbee messages generated from the device. Continuing the example of the switch capability defaults would be the following:

switch_defaults.zigbee_handlers = {
  global = {},
  cluster = {},
  attr = {
    [zcl_clusters.OnOffCluster] = {
      [zcl_clusters.OnOffCluster.attributes.OnOff] = switch_defaults.on_off_attr_handler
    }
  }
}

Here we can see that we register an attribute handler to convert the Zigbee attribute value into a capability event.

capability_handlers

The zigbee_handlers defined on the defaults module will be the mapping that will describe how the handler functions get registered to handle the appropriate Capability commands to be sent to the device. Continuing the example of the switch capability defaults would be the following:

switch_defaults.capability_handlers = {
  [capabilities.switch.commands.on] = switch_defaults.on,
  [capabilities.switch.commands.off] = switch_defaults.off
}

Here we can see that we register a handler for both the on and off command of the SmartThings switch capability. Because these files are specific to an individual capability, it does not need to be nested within a capability key like it would if you were defining it directly within the driver.

attribute_configurations

The attribute_configurations defined on the defaults module is used as a part of the configuration of devices using a driver they get pulled into. The list of values that can be included in the attribute configuration are roughly the same values that would be used in the ConfigureReporting command. They will be used co create those actual Zigbee network configure reporting commands to inform the physical device of how we want it to inform us of state changes. Here is an example from our switch defaults file:

switch_defaults.attribute_configurations = {
  {
    cluster = zcl_clusters.OnOffCluster,
    attribute = zcl_clusters.OnOffCluster.attributes.OnOff,
    minimum_interval = 0,
    maximum_interval = 300,
  }
}

So here we set a cluster, attribute, min and max interval for reporting, this will result in the cluster/attribute defined being reported any time it changes, but also at least once every 300 seconds even if there isn’t a change. The above example is for a “discrete” data type (boolean) as defined in the ZCL specification. However, for a non-discrete value, we can also include a reportable_change attribute that describes how much an attribute must change by in order for it to be reported. Following is an example from the switchLevel capability defaults.

switch_level_defaults.attribute_configurations = {
  {
    cluster = zcl_clusters.LevelControlCluster,
    attribute = zcl_clusters.LevelControlCluster.attributes.CurrentLevel,
    minimum_interval = 1,
    maximum_interval = 3600,
    reportable_change = 1
  }
}

Here we are saying we want to be notified any time the value changes by at least 1, but we could also change it to say 5 if we didn’t need to know immediately about every small change (the periodic reporting would still inform us of a 1 change, it just wouldn’t happen immediately).

You will notice that the examples used in the defaults are slightly different than the attribute config that is acutally used within the driver template. That is primarily for self documenting reasons. Here we can, and do, direclty use the lua generated cluster object and lua generated attribute object for the defaults as it is easier to read and understand than just using the numbers, and the data type, and raw IDs can be determined from these structures. However, it is still allowed to potentially use the raw numbers if there is some reason that the lua structures aren’t usable.