Lua Module Reference
What Are Lua Modules
Lua modules are C-implemented Lua extension libraries loaded inside scripts via require("module_name"). They are distinct from Skills (filesystem packages) and Capabilities (C-layer tools callable by the LLM). Modules are the toolbox available inside a running Lua script.
Two execution environments exist:
Skill sandbox (
lua_run/lua_run_async): a restricted set of modules is available. Dangerous standard libraries (io,os,debug) and dynamic loading (load,loadfile) are stripped.REPL (
AT+CLAW=lua): the full module set is available for interactive testing.
Modules Available in Skill Scripts
Software Modules
Module |
Description |
|---|---|
|
Capability calls — invoke any registered C-layer Capability from within a script via |
|
Filesystem — read and write files under |
|
System utilities — monotonic millisecond counter ( |
|
JSON parsing and serialization — decode LLM-supplied JSON arguments, encode return values |
|
Timers — create one-shot or repeating software timers with Lua callbacks |
|
UDP networking — send and receive UDP datagrams for LAN device communication |
|
Event bus — publish and subscribe to internal system events; use with |
Hardware Driver Modules
Module |
Description |
|---|---|
|
Pin control — configure input/output, read/write levels; |
|
Button events — event-driven key detection with press/release callbacks (wrapper over |
|
I2C bus — communicate as master with sensors, displays, and other I2C devices |
|
SPI bus — master-mode byte-level read/write |
|
Real-time clock — read and set the hardware RTC |
|
Display output — unified API for SPI and LCDC-connected screens |
|
Audio — record audio, obtain PCM streams, audio playback |
|
USB storage — access files on a USB Mass Storage Class device (USB drive) |
|
USB camera — control a USB Video Class camera and capture image frames |
REPL-Only Modules
Warning
The modules below are available only in the interactive REPL environment (AT+CLAW=lua). Calling them from a Skill script causes a runtime error because they are not loaded into the Skill sandbox. If you need related functionality inside a Skill, call the corresponding Capability via cap.call(), or validate logic in the REPL first.
REPL-exclusive modules (do not use in Skill scripts):
wifi— Wi-Fi scanning and connection managementuart— UART serial send/receivepwm— PWM waveform outputir— Infrared transmit/receivelcdc— LCD controller display outputadc— Analog-to-digital conversionthermal— On-chip temperature sensortouch— Capacitive touch detectionbasictimer— Hardware basic timer (precision timing)led_strip— WS2812 programmable LED strip control
Writing Skill Scripts
Entry Function
Every Skill script must define a run function. The Lua VM calls it after loading the script, passing the decoded argument table:
-- Top-level code runs first (helpers, constants)
function run(args)
-- args is already a decoded Lua table — do NOT call cjson.decode(args)
local pin = args.pin or "PA_22"
return '{"status":"ok","pin":"' .. pin .. '"}'
end
Scripts without a run function cannot be invoked by the Agent or via AT+CLAW=skill.
File Path Conventions
Path |
Purpose |
|---|---|
|
Throwaway — cleared on every reboot; use for quick tests |
|
Persistent user scripts — survive reboots, not managed by the skill catalog |
|
Agent-invokable Skills — must be at this exact path to be registered |
Lua 5.4 Bitwise Operators
Ameba-Claw runs Lua 5.4. There is no bit module. Use the native operators:
Operation |
Correct |
Incorrect (Lua 5.1 style) |
|---|---|---|
Bitwise AND |
|
|
Bitwise OR |
|
|
Bitwise XOR |
|
|
Right shift |
|
|
Left shift |
|
|
System Time and Sleep
The os module is not available. Use sys instead. Note that sys provides elapsed time since boot, not a Unix wall-clock timestamp:
local sys = require("sys")
local ms = sys.millis() -- monotonic ms since boot (wraps after ~49 days; NOT Unix time)
local up = sys.uptime() -- seconds since boot as a float (NOT Unix time)
sys.sleep_ms(500) -- block for 500 ms (safe in run() body; never call inside a timer callback)
To get the current wall-clock time, use cap.call("get_current_time", "{}") instead.
Correct Usage of cap.call
cap.call always returns two values. Capture both or the JSON payload is silently discarded:
local cap = require("cap")
-- Correct: capture ok (boolean) and result_json (string)
local ok, result_json = cap.call("file_read", '{"path":"vfs:/tmp/data.json"}')
if not ok then
return '{"error":' .. (result_json or '"unknown"') .. '}'
end
local t = require("cjson").decode(result_json)
-- Incorrect: captures only ok (the boolean), discards result_json
-- local result = cap.call("file_read", ...) -- do not do this
Complete Example: GPIO Blink LED
A complete Skill script that blinks an LED on a configurable pin:
local gpio = require("gpio")
local sys = require("sys")
function run(args)
local pin = args.pin or "PA_22"
local times = args.times or 6
gpio.open(pin, gpio.OUTPUT)
for i = 1, times do
gpio.write(pin, i % 2)
sys.sleep_ms(500)
end
gpio.close(pin)
return '{"status":"ok"}'
end
Save to vfs:/skills/blink_led/scripts/main.lua. The Agent can invoke it through conversation, or directly:
AT+CLAW=skill,blink_led
AT+CLAW=skill,blink_led,{"pin":"PA_22","times":10}