Appearance
Getting Started
Build your first Haptique OS driver in about 10 minutes. No prior knowledge of the HOS codebase required.
Prerequisites
- Node.js 20 or later installed (nodejs.org)
- A running HOS server — see Dev Setup if you need to spin one up locally, or point at any existing HOS instance on your network
Set the server WebSocket URL before running any driver:
bash
export HOS_WS_URL=ws://localhost:8080/driver8080 is the default port. Adjust if your server uses a different DRIVER_WS_PORT.
1. Install the SDK
bash
npm install @haptique/driver-sdkThis installs HosDriver — the TypeScript client class that wraps the WebSocket protocol for you.
2. Run the Sample Driver
Create a file my-driver.ts and paste the minimal driver below (or see the full sample in Driver Lifecycle):
typescript
import { HosDriver } from '@haptique/driver-sdk';
const driver = new HosDriver({
driverKey: 'SIMULATED',
instanceId: 'simulated-001',
wsUrl: process.env.HOS_WS_URL ?? 'ws://localhost:8080/driver',
});
driver.on('registered', () => {
driver.sendEvent('DEVICE_DISCOVERED', {
device_id: 'sim-light-001',
data: {
name: 'Simulated Light',
deviceType: 'light',
properties: {
commandCatalog: [
{ key: 'turn_on', label: 'Turn On' },
{ key: 'turn_off', label: 'Turn Off' },
],
},
},
});
driver.sendEvent('STATE_UPDATE', {
device_id: 'sim-light-001',
data: { power: false, brightness: 0 },
});
});
driver.connect();Run it:
bash
npx ts-node my-driver.tsYou should see:
[simulated] Starting simulated device driver...
[simulated] Connected to HOS server
[simulated] Registered with HOS server
[simulated] Discovered sim-light-001, initial state: power=falseThe driver is now live. Open the HOS mobile app or admin panel — you'll see a device named "Simulated Light" appear.
3. Understand the Four Calls
Every HOS driver is built on the same four operations:
Construct the driver
typescript
import { HosDriver } from '@haptique/driver-sdk';
const driver = new HosDriver({
driverKey: 'MY_DRIVER', // Unique identifier: [A-Z0-9_], 2-64 chars
instanceId: 'my-driver-001', // Runtime instance ID: [a-zA-Z0-9:_-], 1-128 chars
wsUrl: process.env.HOS_WS_URL ?? 'ws://localhost:8080/driver',
name: 'My First Driver', // Display name shown in HOS UI
});
driver.connect();Announce devices after registration
typescript
driver.on('registered', () => {
driver.sendEvent('DEVICE_DISCOVERED', {
device_id: 'my-light-001',
data: {
name: 'Living Room Light',
deviceType: 'light',
properties: {
commandCatalog: [
{ key: 'turn_on', label: 'Turn On' },
{ key: 'turn_off', label: 'Turn Off' },
],
},
},
});
driver.sendEvent('STATE_UPDATE', {
device_id: 'my-light-001',
data: { power: false, brightness: 0 },
});
});Handle commands
typescript
driver.onAction((msg) => {
const action = msg.data.action;
driver.sendEvent('ACTION_RESULT', {
device_id: msg.device_id,
data: { success: true, requestId: msg.data.requestId as string | undefined },
});
if (action === 'turn_on') {
driver.sendEvent('STATE_UPDATE', {
device_id: msg.device_id,
data: { power: true, brightness: 100 },
});
} else if (action === 'turn_off') {
driver.sendEvent('STATE_UPDATE', {
device_id: msg.device_id,
data: { power: false, brightness: 0 },
});
}
});Shut down cleanly
typescript
process.on('SIGTERM', () => driver.disconnect());
process.on('SIGINT', () => driver.disconnect());4. Want to Upload a Driver Package?
If you want to ship a driver as an uploadable OS-local package (ZIP file) rather than running an external WebSocket process, see Driver Manifest — it covers the package format for Python, Lua, and JavaScript local drivers.
What's Next
- Driver Lifecycle — Full walkthrough of every phase: startup, registration, discovery, commands, reconnection, and shutdown
- Driver Architecture — How commands flow from mobile app → HOS → your driver and back
- Domain Reference — Device types, state fields, and command names for Lighting, AV/Media, Climate, Security, and Robot Vacuums
- Driver Manifest — Building an uploadable OS-local driver package