Skip to main content

The Key Innovation

Traditional IoT platforms require you to define device capabilities on the server, then write matching firmware, then keep both in sync. With Lua devices, the device itself declares what it can do. There is no server-side schema to maintain.

Think of it as:

Each device carries its own resume. When it connects, the agent reads the resume and knows exactly what the device can do.
When a device connects, it sends an array of DeviceCommandDefinition objects. The gateway stores these alongside the connection. The agent runtime reads them and creates tools automatically. When the device disconnects, the tools disappear.

DeviceCommandDefinition Fields

Each command definition has the following fields:
interface DeviceCommandDefinition {
  /** Command name (used by agent to invoke) */
  name: string;

  /** Human-readable description (shown to the AI agent as tool description) */
  description: string;

  /** JSON Schema for command input parameters */
  inputSchema?: Record<string, any>;

  /** Command timeout in milliseconds (default: 30000) */
  timeoutMs?: number;

  /** Retry configuration for failed commands */
  retry?: { maxAttempts: number; backoffMs: number };
}
name
string
required
The command name. This becomes part of the tool name the agent sees (device:{deviceName}:{name}). Use lowercase with underscores (e.g., read_temperature, set_brightness).
description
string
required
A natural-language description of what the command does. The AI agent reads this to decide when to use the tool. Write it as if explaining to a person: “Read the current room temperature in celsius” is better than “temp read”.
inputSchema
Record<string, any>
A JSON Schema object describing the parameters the command accepts. The agent uses this to construct the correct payload.
timeoutMs
number
default:"30000"
How long to wait for the device to respond before the command fails. Increase for slow operations like printing or scanning.
retry
{ maxAttempts: number; backoffMs: number }
Automatic retry on failure. The gateway retries with exponential backoff starting at backoffMs.

JSON Schema Examples

No Parameters

{
  name: 'get_status',
  description: 'Get the current status of the printer including paper level and ink',
}

Simple Parameters

{
  name: 'set_brightness',
  description: 'Set the display brightness level',
  inputSchema: {
    type: 'object',
    properties: {
      level: {
        type: 'number',
        minimum: 0,
        maximum: 100,
        description: 'Brightness percentage (0-100)',
      },
    },
    required: ['level'],
  },
}

Enum Parameters

{
  name: 'set_mode',
  description: 'Switch the device operating mode',
  inputSchema: {
    type: 'object',
    properties: {
      mode: {
        type: 'string',
        enum: ['idle', 'active', 'maintenance', 'sleep'],
        description: 'Target operating mode',
      },
    },
    required: ['mode'],
  },
}

Complex Parameters

{
  name: 'print_label',
  description: 'Print a shipping label with the given details',
  inputSchema: {
    type: 'object',
    properties: {
      recipient: {
        type: 'object',
        properties: {
          name: { type: 'string' },
          address: { type: 'string' },
          city: { type: 'string' },
          postalCode: { type: 'string' },
        },
        required: ['name', 'address', 'city', 'postalCode'],
      },
      copies: {
        type: 'number',
        minimum: 1,
        maximum: 10,
        default: 1,
      },
    },
    required: ['recipient'],
  },
  timeoutMs: 60000,
  retry: { maxAttempts: 2, backoffMs: 1000 },
}

Validation Rules

  • name must be unique within a single device. Two devices can have commands with the same name.
  • description should be a complete sentence. The agent treats it as a tool description.
  • inputSchema must be valid JSON Schema draft-07. The type at the top level should be 'object'.
  • timeoutMs minimum is 1000 (1 second). The default of 30000 (30 seconds) works for most commands.

Dynamic Updates

Commands are sent at connect time. To change the command list, update the commands array in your DeviceClientConfig and restart the device (or disconnect and reconnect).
// Version 1: basic sensor
const device = new DeviceClient({
  deviceName: 'env-sensor',
  commands: [
    { name: 'read_temperature', description: 'Read temperature' },
  ],
  // ...
});

// Version 2: added humidity and calibration
const device = new DeviceClient({
  deviceName: 'env-sensor',
  commands: [
    { name: 'read_temperature', description: 'Read temperature in celsius' },
    { name: 'read_humidity', description: 'Read relative humidity percentage' },
    { name: 'calibrate', description: 'Run sensor calibration routine', timeoutMs: 60000 },
  ],
  // ...
});
No lua push or lua deploy needed. Just restart the device.
When a device goes offline, its tools disappear from the agent. If a user asks the agent to use a device tool and the device is not connected, the agent will not have that tool available. Design your agent persona to handle this gracefully (e.g., “The sensor is currently offline”).

Next Steps

Agent Tools

How device commands become tools the agent can use

Node.js Client

Complete DeviceClientConfig reference

Triggers

The other direction — device events sent to the agent

Quickstart

See self-describing commands in action