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

cap

Capability calls — invoke any registered C-layer Capability from within a script via cap.call("id", json)

file

Filesystem — read and write files under vfs:/ and rolfs:/, text and binary modes

sys

System utilities — monotonic millisecond counter (sys.millis()), uptime in seconds (sys.uptime()), blocking sleep (sys.sleep_ms(n))

cjson

JSON parsing and serialization — decode LLM-supplied JSON arguments, encode return values

timer

Timers — create one-shot or repeating software timers with Lua callbacks

udp

UDP networking — send and receive UDP datagrams for LAN device communication

event

Event bus — publish and subscribe to internal system events; use with gpio.on() to replace busy-polling

Hardware Driver Modules

Module

Description

gpio

Pin control — configure input/output, read/write levels; gpio.on(pin, edge, fn) for interrupt-driven callbacks

button

Button events — event-driven key detection with press/release callbacks (wrapper over gpio)

i2c

I2C bus — communicate as master with sensors, displays, and other I2C devices

spi

SPI bus — master-mode byte-level read/write

rtc

Real-time clock — read and set the hardware RTC

display

Display output — unified API for SPI and LCDC-connected screens

audio

Audio — record audio, obtain PCM streams, audio playback

usb_msc

USB storage — access files on a USB Mass Storage Class device (USB drive)

usb_uvc

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 management

  • uart — UART serial send/receive

  • pwm — PWM waveform output

  • ir — Infrared transmit/receive

  • lcdc — LCD controller display output

  • adc — Analog-to-digital conversion

  • thermal — On-chip temperature sensor

  • touch — Capacitive touch detection

  • basictimer — 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

vfs:/tmp/<name>.lua

Throwaway — cleared on every reboot; use for quick tests

vfs:/scripts/<name>.lua

Persistent user scripts — survive reboots, not managed by the skill catalog

vfs:/skills/<name>/scripts/main.lua

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

a & b

bit.band(a, b)

Bitwise OR

a | b

bit.bor(a, b)

Bitwise XOR

a ~ b

bit.bxor(a, b)

Right shift

a >> n

bit.rshift(a, n)

Left shift

a << n

bit.lshift(a, n)

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