Skip to main content
lua-device-client connects a Python 3.8+ process to an agent as a device over MQTT, runs async command handlers, sends triggers, and uploads files. Version 1.3.0 on PyPI; it depends on paho-mqtt 2.0 or later and httpx. Verified against lua-device-client 1.3.0.

Quick example

device.py

DeviceClient

DeviceClient(config=None, **kwargs) accepts a DeviceClientConfig or the same fields as keyword arguments. Construction doesn’t connect.
str
required
The agent the device connects to. Must equal the agent in the credential’s binding.
str
required
The credential: a device credential or a legacy API key. 1.3.0 sends it as the MQTT password and repeats it in the non-retained status message, where the platform validates it again; a device credential’s operations are enforced by the broker.
str
required
The device name. Must equal the name in the credential’s binding.
list[DeviceCommandDefinition]
default:"[]"
Commands sent at connect time; each becomes a tool.
str
default:"wss://mqtt.heylua.ai/mqtt"
Broker URL. ws/wss use the WebSocket transport (path from the URL, /mqtt by default); mqtts and ssl use TLS over TCP. The port defaults to 443 for wss, 8083 for ws, 8883 for mqtts, and 1883 otherwise.
str
default:"https://cdn.heylua.ai"
Base URL for cdn.
str
Group name reported at connect.
DeviceCommandDefinition
str
required
Command name; must match ^[a-z][a-z0-9_]{0,63}$ or the platform drops it.
str
required
The tool description the model reads.
dict
JSON Schema for the payload; sent as inputSchema. At most 4 KB serialized.
int
default:30000
How long the platform waits for the response. Sent only when changed.
dict
{"max_attempts": int, "backoff_ms": int}; missing keys default to 3 and 1000. Sent as retry.maxAttempts and retry.backoffMs.

Methods

connect()

Connects, subscribes, publishes the status and command list, and starts the heartbeat. paho-mqtt’s network loop runs in a background thread; handlers run on the asyncio loop that called connect().
ErrorsConnectionError("MQTT connect failed: rc=<code>") when the broker refuses the connection, for example a rejected credential.

on_command()

Registers the async handler for one command. There is no decorator form.
Returns — nothing. The handler’s return value is sent as data; an exception is sent as success: false with str(exc); an unregistered command answers Unknown command: <name>.

trigger()

Publishes a trigger and waits for the acknowledgment. Concurrent calls are serialized.
ReturnsTriggerAckMessage(trigger_id, received, error). ErrorsRuntimeError("Not connected to MQTT broker") before connect(); TimeoutError("Trigger '<name>' ACK timeout (10s)") when no acknowledgment arrives within 10 seconds. The platform publishes a rejected trigger on trigger_error, which 1.3.0 doesn’t subscribe to, so the call times out instead.

on_trigger_result()

Registers a handler for a trigger_result message. The platform doesn’t send that message, so the handler never runs.

on()

Registers a plain function for a connection event.

disconnect()

Publishes a retained offline status, stops the heartbeat, and closes the connection without reconnecting.

is_connected()

Connection behavior

  • Client ID lua-<agent_id>-<device_name>, username <agent_id>:<device_name>, MQTT 3.1.1, keep-alive 60 seconds, persistent session, retained last-will offline status.
  • TLS verifies the broker certificate (CERT_REQUIRED).
  • Heartbeat every 30 seconds.
  • Reconnection is paho-mqtt’s: a delay that doubles from 1 second to 120 seconds. The status message and command list are published again on every reconnect.
  • Command IDs are cached for 5 minutes (1,000 entries); a redelivered command gets the cached response.

CDN

client.cdn is a CDN instance authenticated with the credential, which must grant assets.upload.

upload()

ReturnsCdnUploadResult(file_id, media_type, extension, url); url is <cdn_url>/<file_id>. Files are limited to 100 MB. ErrorsRuntimeError with the platform’s message, or CDN upload failed: <status>.

download() and get_url()

Types

Exported from lua_device.
dataclass
agent_id, api_key, device_name, commands, mqtt_url, cdn_url, group.
dataclass
name, description, input_schema, timeout_ms, retry; to_dict() gives the wire form.
dataclass
command_id, command, payload, timeout.
dataclass
command_id, success, data, error.
dataclass
trigger_id, received, error.
class
Standalone CDN(api_key, cdn_url=None) with the methods above.

See also