Device
In order for a driver to do its job it will need to know information about the devices that it is responsible for.
This information is held in a Device
object that provides many utility functions and
abstractions that will simplify many normal use cases. It will also provide relevant caching and updating on changes
that originate outside the driver. In addition a driver can provide a infoChanged
lifecycle handler that can do
additional processing after the provided processing. The Device
object is provided to
event handlers handling events for a specific device. A full list of all of these objects for every device the driver is
responsible for can be fetched with the Driver:get_devices
method.
Below is an example of a Device
object.
device = {
driver = {
id = "9fbc3680-b9a9-4bd8-a574-9b03517032b2", name = "smartthings/Lua Zigbee Water", type = "DATAMGMT" },
components = {
main = {
capabilities = {
{ id = "temperatureMeasurement", version = 1 },
{ id = "battery", version = 1 },
{ id = "waterSensor", version = 1 },
{ id = "sensor", version = 1 },
},
emit_event = function(capability_event, event_metadata) end,
id = "main"
}
},
preferences = {},
zigbee_endpoints = {
1 = {
client_clusters = { 25 },
device_id = 1026,
id = 1,
manufacturer = "CentraLite",
model = "3315-S",
profile_id = 260,
server_clusters = { 0, 1, 3, 32, 1026, 1280, 2821 }
}
},
id = "02703834-4ab9-46e0-80ed-789fbd481f63",
fingerprinted_endpoint_id = 1,
zigbee_eui = "\x00\x0D\x6F\x00\x03\x26\x8A\x5C",
network_type = "DEVICE_ZIGBEE",
label = "Water Leak Sensor",
data = {
deviceEUI = "000D6F0003268A5C",
firmwareChecked = "2020-01-15T00:41:46.213Z",
initialJoinTime = "2019-12-05T15:54:31.563Z",
initialJoinType = "Unsecure Join",
lastJoinTime = "2020-01-08T18:33:57.480Z",
lastJoinType = "Secure Rejoin",
parent = "0000",
targetFirmwareVersion = "520573712",
zigbeeNodeType = "SLEEPY_END_DEVICE"
},
profile = {
components = {
{
capabilities = {
{ id = "temperatureMeasurement", version = 1 },
{ id = "battery", version = 1 },
{ id = "waterSensor", version = 1 },
{ id = "configuration", version = 1 },
{ id = "sensor", version = 1 },
{ id = "healthCheck", version = 1 }
},
id = "main"
}
},
id = "b648f97a-ab00-4a92-a1f5-2d10bf9a5c7d"
},
device_network_id = "D836"
}
Device Class
The device class is the wrapper on top of the raw data provided by the device_api
.
The device class table will store information in a variety of different locations, and
these locations will be protected with metatables. Following are the main pieces to the
device object.
- st_store:
This is used to store the above shown representation of the SmartThings device model. It is read only, and will be updated automatically if there are changes in the model from an external source (e.g. a change in the cloud). The top level values of this table are also “mirrored” onto the device object itself. That is
device.st_store.id
will give you the device’s UUID to refer to the device in the SmartThings platform, but you can also access this value simply throughdevice.id
. This is done for simplicity of access.- transient_store:
The transient_store is used for storing driver/device specific information. This information however, will only exist as long as the driver is running, and will need to be re-populated where necessary on restart of the hub. A good example of this would be storing the timestamp of the last time you read a given attribute. It’s something that is only useful within the context of the specific driver, but is easily re-constructed after a restart. It is suggested that most of your data can/should be stored this way. It is also recommended that most user/driver stored data be accessed/set using the
device:set_field
anddevice:get_field
methods documented below.- persistent_store:
Similar to the transient_store, this is for use for driver specific information, however, unlike the transient_store, information written here will be stored and persisted through restarts. This carries with it a cost in wear, as well as time delays associated with the writing and reading. This should also be accessed through the
device:set_field
anddevice:get_field
methods. A good example of a target for the persistent store would be something like the number of lock codes a lock can support. This is something that only needs to be read once when the device is first joined, and won’t change for the lifetime of the device. This could be read every time the driver restarts, but it is reasonable to read once and store for the lifetime of the device. In order to protect the longevity of your hub device, we limit how frequently values are actually written to flash. This does, however, come with a potential loss of information. When the persistent store for your driver is “written” it is cached in memory and will actually be written to flash on a schedule and on graceful shutdown. This means there is potential information loss in the case of a power loss.- state_cache:
The state cache is a persistent data cache that will store for each component, capability, attribute, the most recently generated state by the driver. For example
device.state_cache.main.switch
would contain{ value = "on" }
.
The set_field
and get_field
functions can be used to write and read from the persistent
and transient stores. It is enforced that top level keys cannot be repeated between the two
stores, as such get_field
will always return the single value with the matching key.
Consequently set_field
will delete the value in the other store if it is written to the
other.
There are also a variety of other utility methods documented below.
Device Class Documentation
- class st.Device
A device object contains all of the information we have about a given device that is set to be managed by this driver. It also provides a number of utility functions that make normal operations for dealing with devices simpler.
- transient_store: table
Used to store driver specific data about a device that will not persist through driver restart.
- persistent_store: table
Used to store driver specific data about a device that will be persisted through restart. The actual flash writes are on a schedule so some data loss is possible if the hub experiences a power loss
- st_store: table
Contains the SmartThings device model. Read only and can be updated as a result of changes made elsewhere in the system.
- state_cache: table
Caches the most recent event state generated for each component/capability/attribute this is per run session, and is persisted through restart.
- thread: st.thread.Thread
The handle to the cosock thread that executes events for this device. This can also be used directly to schedule your own events or use its register_socket function to handle a device-specific socket.
- emit_event(capability_event)
Emit a capability event for this devices main component. Will log a warning and do nothing if there is no “main” component on the device
- Parameters
capability_event (
table
) – the capability event to emit
- emit_component_event(component, capability_event)
Generate a capability event for this device and component
Usage:
device:emit_component_event(device.profile.components.main, capabilities.switch.switch.on())
- set_field(field, value, addtional_params)
Set a device specific value to be stored and retrieved when needed. The key names are unique across both persistent and transient stores.
- Parameters
field (
str
) – The field name for this valuevalue (
value
) – The value to set the field to. If setting to persistent store it must be serializableaddtional_params (
table
) – Optional: contains additional description of the field. Currently only usage is the persist field which, if true, will store the field to the persistent store instead of transient
- get_parent_device()
Get the st.Device object that is the parent of this device. This _can_ result in a blocking request for the
parents device data, and can be subject to race conditions based on order of data sync. This should _NOT_ be used within an added or init lifecycle event to avoid race conditions and deadlocks.
- Returns
the parent device object of this device
- Return type
- set_find_child(find_child_fn)
Set a function used to find a child given an “endpoint” input specific to each protocol
- Parameters
find_child_fn (
function
) – A function that takes a protocol specific endpoint identifier to find a child from
- get_child_list()
Get a list of all the children of this device
- Returns
a list of the child devices of this device. The type will be specific to the protocol
- Return type
list[st.Device]
- get_child_by_parent_assigned_key(parent_assigned_key)
Find a child of this device by the parent assigned child key given at creation
- Parameters
parent_assigned_key (
str
) – the key assigned by the parent to identify a child at creation- Returns
the child device with this key
- Return type
st.Device or st.zigbee.ChildDevice or st.zwave.ChildDevice or st.matter.ChildDevice or nil
- get_field(field)
Retrieve the value a previously set field. nil if non-existent
- Parameters
field (
str
) – The field name for this value- Returns
value The value the field was set to.
- Return type
value
- supports_capability(capability, component)
Check if this device has a capability in its profile
- Parameters
capability (
Capability
) – The capability to check for existencecomponent (
str
) – Optional: The component id to check for capability support. If nil, any component match will return true
- Returns
true if the capability is present in this devices profile
- Return type
boolean
- component_exists(component_id)
Check if this device has a component_id in its profile
- Parameters
component_id (
str
) –- Returns
true if the component is present in this devices profile
- Return type
boolean
- get_latest_state(component_id, capability_id, attribute_name, default_value, default_state_table)
Get the latest state of this device for a given component, capability, attribute
table (e.g. it would include both the value and unit keys if both are present)
- Parameters
component_id (
str
) – the component ID to get the state forcapability_id (
str
) – the capability ID to get the state forattribute_name (
str
) – the capability attribute name to get the state fordefault_value (
any
) – Optional value to return if the state_cache for the lookup is nildefault_state_table (
any
) – Optional value to return if the state_cache for the lookup is nil
- Returns
The first return value is the state.value present for the attribute, the second return is the state
- Return type
any or any
- component_count()
- Returns
count of components in device profile
- Return type
number
- supports_capability_by_id(capability_id, component)
Check if this device has a capability_id in its profile
- Parameters
capability_id (
str
) – The capability ID to check for existencecomponent (
str
) – Optional: The component id to check for capability support. If nil, any component match will return true
- Returns
true if the capability is present in this devices profile
- Return type
boolean
- try_update_metadata(metadata)
Send a request to update the metadata of a device.
Example usage:
device:try_update_metadata({profile = "bulb.rgb.v1", vendor_provided_label = "My RGB Bulb"})
All metadata fields are type string. Valid metadata fields are:
For all network types (LAN/ZIGBEE/ZWAVE/MATTER): profile - profile name defined in the profile .yaml file. provisioning_state - the provisioning state of the device (TYPED/PROVISIONED)
LAN specific: manufacturer - device manufacturer model - model name of the device vendor_provided_label - device label provided by the manufacturer/vendor
- Parameters
metadata (
table
) – A table of device metadata
- static build(cls, driver, raw_device)
Build a device object from a raw st_store of the SmartThings device model
helper event generation functions
- load_updated_data(new_device_data)
Update the st_store data with newly provided data from the cloud.
- Parameters
new_device_data (
any
) –
- extend_device(func_name, func)
Add a function to this device object, or override an existing function
- Parameters
func_name (
str
) – the name of the function to add/overwritefunc (
function
) – the function to add to the device object
- deleted()
This will do any necessary cleanup if the device is removed. The device object will not
be functional after this call.
- pretty_print()
Get a string with the ID and label of the device
- Returns
a short string representation of the device
- Return type
str
- online()
Mark device as being online
Only useable on LAN type devices and children of LAN type devices. Calls to this API for ZIGBEE, ZWAVE, or MATTER type devices are ignored as their online/offline status are automatically determined at the radio level. When a parent device is marked online, the online state of its children will be determined independently (i.e. they can be either online or offline).
- Returns
boolean Status of whether the call was successful or not
- Return type
status
- Returns
string The error that occured if status was falsey
- Return type
- offline()
Mark device as being offline and unavailable
Only useable on LAN type devices and children of LAN type devices. Calls to this API for ZIGBEE, ZWAVE, or MATTER type devices are ignored as their online/offline status are automatically determined at the radio level. When a parent device is marked offline, its children will also be marked offline.
- Returns
boolean Status of whether the call was successful or not
- Return type
status
- Returns
string The error that occured if status was falsey
- Return type
- register_native_capability_cmd_handler(capability_id, capability_cmd_id)
Register a capability command to be handled natively by the hub.
Starting with API version 11, the hub can run the Zigbee/Z-Wave/Matter default handler implementations for some capability commands outside of the driver’s Lua environment. A driver can opt-in to using these handlers for capability commands which will provide substantial latency improvements over the handlers defined in the driver.
When handled natively, a command will not be forwarded to the driver; however, all protocol messages received from the device will still be handled by the driver.
If a particular command cannot be supported for a device, this API will return an error message. Only single component Matter, Z-Wave, and Zigbee devices currently support having commands handled natively. And only some capability commands (i.e.
switch
on
/off
andswitchLevel
setLevel
) are available for those devices.It is expected that even if a driver is opting into this functionality, that the driver provides a handler for all the capability commands it supports. This functionality is a latency optimization and there are no guarantees that it will always be available to a driver on all hub platforms.
- Parameters
capability_id (
str
) – The ID of the capability to be handled nativelycapability_cmd_id (
str
) – The ID of the command to be handled natively
- Returns
userdata if success, or nil if there was an error
- Return type
status or nil
- Returns
string error message if an any
- Return type
nil or error