Skip to main content

Writing Your First Lua Driver

tip

Looking for a step-by-step, real-world tutorial? Visit the SmartThings Community tutorials!

Startup#

The Lua sandbox will initially start the file init.lua from the base directory of your src folder. All the other folders and files in the src directory will be collected, added to the package, and sent to the hub on package install.

Adding Required Libraries#

Every init.lua file should begin with require statements to import the libraries the driver will use.

local capabilities = require "st.capabilities"
local Driver = require "st.driver"

These two statements will load the SmartThings-provided libraries for capability support and for driver utility functions. In unison, they provide the core functionality all drivers need.

Basic Driver Initialization#

local example_driver = Driver("example driver", {
discovery = discovery.handle_discovery,
lifecycle_handlers = {
added = device_added,
init = device_init,
removed = device_removed
},
capability_handlers = {
[capabilities.switch.ID] = {
[capabilities.switch.commands.on.NAME] = command_handlers.switch_on,
[capabilities.switch.commands.off.NAME] = command_handlers.switch_off,
},
}
})

The code above creates a driver object called example_driver. Upon initialization, it passes a name and a template.

Capabilities#

As part of driver initialization, a Lua table is populated with the SmartThings Capabilities and their corresponding commands and the command handlers to call when a command is sent to a device.

Through properly implemented command handlers, this structure is all that is needed to allow SmartThings commands to be received by a driver, routed to a command handler, and then to the appropriate device communication to control a device. The device control will differ based upon the type of device being controlled.

local function handle_on(driver, device, command)
-- Send command to device
end
local function handle_off(driver, device, command)
-- Send command to device
end

All of this handles how SmartThings can control a device. Now let's look at how to report a device's status back to SmartThings.

A different API is required to generate device statuses (also known as attributes). Device attributes use the Capability library.

In the example below an attribute event is generated from the device object, resulting in a switch.on status for the device.

device:emit_event(capabilities.switch.switch.on())

Getting raw data from devices will differ based on the type of device. For ZigBee and Z-Wave devices, libraries provided by SmartThings will facilitate receiving these messages. For LAN devices, a socket will be necessary to communicate with the device.

For more information regarding Capabilities, visit the Capabilities documentation.

Running the Driver#

The driver library has a run function which never returns and runs the driver in a pseudo event-driven model. Where the handlers connected in prior lines get called when events are sent to the driver for handling. Any code after the run call to the driver library will not be executed since run() never returns. Once run() is called, your code is only called when events occur.

example_driver:run()

Putting It All Together#

Here's an example of a completed basic driver:

-- init.lua
local log = require "log"
local capabilities = require "st.capabilities"
local Driver = require "st.driver"
local function handle_on(driver, device, command)
log.info("Send on command to device")
-- for real devices you should make a request to a device and wait for the
-- response confirming the device was switched on before emitting this
device:emit_event(capabilities.switch.switch.on())
end
local function handle_off(driver, device, command)
log.info("Send off command to device")
-- for real devices you should make a request to a device and wait for the
-- response confirming the device was switched off before emitting this
device:emit_event(capabilities.switch.switch.off())
end
-- Driver library initialization
local example_driver =
Driver("example_driver",
{
capability_handlers = {
[capabilities.switch.ID] =
{
[capabilities.switch.commands.on.NAME] = handle_on,
[capabilities.switch.commands.off.NAME] = handle_off
}
}
}
)
-- Put other setup code here
example_driver:run()