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 with | Purpose |
|---|---|
src/device.ts | Implement command handling, state updates, and event logic |
device-spec.json | Check command, property, and event definitions |
.env.example | Configure the MQTT endpoint and device identity |
package.json / README.md | Check dependencies, scripts, and run commands |
Install and Start
- Download and extract the package, then open its root directory.
- Copy
.env.exampleto.envand fill in the connection settings. - Install the package dependencies with npm.
- Connect the real device or business service in
src/device.ts. - Start the program and verify it in the Device Agent workspace.
The minimum install and start commands are:
cp .env.example .env
npm install
npm run startsrc/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:
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:
| Type | Purpose | Node.js API |
|---|---|---|
| Current state | Update the latest device property values | patchState() |
| State snapshot | Report online status and the latest properties | publishStateSnapshot() |
| Event | Report a discrete occurrence such as an alert or button press | sendEvent() |
Event names and data fields must be defined in device-spec.json:
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:
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:
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.