Skip to content

Node.js SDK

The Node.js SDK is for TypeScript or JavaScript device programs, gateways, edge services, and integrations with existing Node.js services or business APIs. The generated package uses @device-agent/device-sdk and BaseDevice; add real device behavior in src/device.ts.

Start withPurpose
src/device.tsImplement command handling, state updates, and event logic
device-spec.jsonCheck command, property, and event definitions
.env.exampleConfigure the MQTT endpoint and device identity
package.json / README.mdCheck dependencies, scripts, and run commands

Install and Start

  1. Download and extract the package, then open its root directory.
  2. Copy .env.example to .env and fill in the connection settings.
  3. Install the package dependencies with npm.
  4. Connect the real device or business service in src/device.ts.
  5. Start the program and verify it in the Device Agent workspace.

The minimum install and start commands are:

bash
cp .env.example .env
npm install
npm run start

src/index.ts loads .env and creates the device instance, while src/device.ts owns commands, state, and events. packages/device-sdk and packages/shared are local dependencies included in the package. Keep command names, parameter names, property fields, and event names aligned with device-spec.json.

Implement Commands, State, and Events

The device class in src/device.ts extends BaseDevice. Commands enter handleCommand(); after the real action completes, update state and publish a snapshot:

ts
protected override async handleCommand(command: DeviceCommandMessage) {
  if (command.cmd === "set_temperature") {
    const target = Number(command.params?.target_temperature);

    await thermostatClient.setTargetTemperature(target);
    this.patchState({ target_temperature: target });
    await this.publishStateSnapshot();

    return { code: 0, msg: "ok", data: { target_temperature: target } };
  }

  return { code: 404, msg: `Unknown command: ${command.cmd}` };
}

BaseDevice handles MQTT connection, command subscription, and response publishing. The three data types serve different purposes:

TypePurposeNode.js API
Current stateUpdate the latest device property valuespatchState()
State snapshotReport online status and the latest propertiespublishStateSnapshot()
EventReport a discrete occurrence such as an alert or button presssendEvent()

Event names and data fields must be defined in device-spec.json:

ts
await this.sendEvent("temperature_alarm", {
  current_temperature: 32.5,
  level: "warning",
});

Add Voice and Vision

Voice

Import VoiceClient from @device-agent/device-sdk, pass wsUrl explicitly, and connect microphone capture, speaker playback, and event listeners. VoiceClient requires a global WebSocket, available in Node.js 21 or later and Bun. The included example can read VOICE_WS_URL:

ts
import { VoiceClient } from "@device-agent/device-sdk";

const voice = new VoiceClient({
  wsUrl: process.env.VOICE_WS_URL ?? "ws://127.0.0.1:3001/ws/voice",
  deviceId: process.env.DEVICE_ID ?? "device-001",
  productId: process.env.PRODUCT_ID ?? "agent-001",
});

voice.on("agentReply", (text) => console.log(text));

await voice.connect();
voice.startListening("manual");
voice.sendAudio(pcmChunk);
voice.stopListening();

The complete example is in packages/device-sdk/examples/voice-chat.ts.

Vision

VOICE_CHAT_HOST configures vision upload and chat for the generated device. src/device.ts includes the generated package's preset single-photo recognition flow; see the package README for its trigger commands. Override captureLocalVisionImage() to return one image from a camera, screenshot, or image file:

ts
protected override async captureLocalVisionImage() {
  return {
    mimeType: "image/jpeg",
    imageBase64: await readCameraFrameAsBase64(),
    source: "sdk-camera",
  };
}

The generated code returns the recognition result as the command response.

See Voice Interaction and Camera and Vision for complete media settings. After startup, use the checks in SDK Access to verify online state, commands, state reports, and events.