Skip to main content

Tutorial: Building a Multi-Device Adapter

Extend your adapter to manage multiple devices using device_id routing.

Concept

A single adapter process can manage many devices. The device_id query parameter routes requests to the correct device handler.

Implementation Pattern

// Device registry
const devices = {
'lock-001': { name: 'Front Door', type: 'lock', state: { locked: true } },
'lock-002': { name: 'Back Door', type: 'lock', state: { locked: true } },
'wifi-001': { name: 'Guest Wi-Fi', type: 'wifi', state: { active: true } },
};

// Route to correct device
app.get('/status', auth, (req, res) => {
const device = devices[req.query.device_id];
if (!device) return res.status(404).json({ error: 'Device not found' });
res.json({ device_id: req.query.device_id, online: true, state: device.state });
});

// Capabilities lists all devices
app.get('/capabilities', auth, (req, res) => {
res.json({
adapter: { name: 'Multi-Device Adapter', version: '1.0.0', vendor: 'Tutorial', protocol: '2.0' },
devices: Object.entries(devices).map(([id, d]) => ({
device_id: id, name: d.name, type: d.type,
criticality: d.type === 'lock' ? 'CRITICAL' : 'STANDARD',
actions: d.type === 'lock' ? ['unlock', 'lock'] : ['enable', 'disable', 'generate_voucher'],
webhook_capable: false, html_embed: true
}))
});
});

Vendor SDK Pattern

When integrating with a vendor SDK (e.g., UniFi), use a factory pattern:

class DeviceHandler {
constructor(vendorClient, deviceConfig) {
this.client = vendorClient;
this.config = deviceConfig;
}
async getStatus() { /* vendor-specific */ }
async executeAction(action, params) { /* vendor-specific */ }
}

// Registry maps device_id to handler
const handlers = new Map();

Next Steps