This page documents the local Gateway REST / WebSocket API — device, scene, group, energy, and system control on the gateway itself. For connecting third-party lighting, BMS, or AV/control systems, see Third-Party Lighting Integration instead.
All endpoints require a Bearer JWT in the Authorization header — see Authentication. Base URL: http://<gateway-ip>:5000/api.
WebSocket — Real-Time Events
The gateway pushes live device and health updates over a WebSocket. The published gateway reference shows this connection example. Confirm WebSocket authentication requirements for your installed release and use only an authorized local network or VPN:
const ws = new WebSocket("ws://<gateway-ip>:5000");
ws.onmessage = (e) => console.log(JSON.parse(e.data));
On connection you immediately receive a welcome event, followed by a continuous stream of state and health events.
Event types
type | Payload |
|---|---|
welcome | { type, message, time } — sent once on connect |
bridge_health | { type, serialConnected, casambiPaired, casambiStatus, lastPacketAt, timestamp } |
deviceState | { type, deviceId, state } — pushed whenever a light or sensor changes. The state object carries only what changed: dimmer, power, brightness, cct, color, white, motion, presence, lux, daylight |
Scene, alert, and activity actions also emit events on this socket.
Example event
{
"type": "deviceState",
"deviceId": "ea298ea5-dd07-48a1-becb-620b6fecc669",
"state": { "power": true, "brightness": 30, "dimmer": 254, "timestamp": 1786143137911 }
}
Devices
List devices
GET /api/devices → { success, devices[], source }
Filter the list with ?category=light or ?subtype=<subtype>.
Get a device
GET /api/devices/:id → { success, device }
The device.state object holds the live state of the fixture:
{
"state": {
"dimmer": 254,
"cct": 3000,
"white": 81,
"color": { "hue": 0, "saturation": 255 },
"xy": { "x": 0, "y": 0 }
}
}
Control a device
PUT /api/devices/:id/control — control uses PUT (not POST).
{ "power": true, "brightness": 60, "colorTemp": 3000 }
RGB colour is also accepted: { "r": 255, "g": 100, "b": 0 }.
A successful command returns the confirmed state:
{
"success": true,
"message": "Device controlled successfully",
"serialControl": "succeeded",
"deviceId": "...",
"state": { "cct": 3000, "white": 81, "color": { "hue": 0, "saturation": 255 } }
}
Commands are delivered to the fixture over the serial / Casambi link. If a device does not acknowledge, the call returns 500 with "Failed to send control command via serial". Subscribe to the WebSocket deviceState event to confirm a change actually landed on the hardware.
Sensors
- GET
/api/sensors— all sensors →{ success, sensors[] } - GET
/api/sensors/live— latest values →{ success, sensors, count, timestamp, source } - GET
/api/sensors/history/:nodeId— history for a sensor node.nodeIdis the numeric node id (e.g.5) →{ success, nodeId, total, page, limit, totalPages, history[] } - GET
/api/devices/sensors/motion— motion sensors - GET
/api/devices/sensors/daylight— daylight/lux sensors
Lighting States
Capture and recall the exact state of a device or a whole area.
- GET
/api/light-states/device/:deviceId→{ success, state } - GET
/api/light-states/area/:areaId→{ success, states[] } - POST
/api/light-states/device/:deviceId— save the device's current state - POST
/api/light-states/bulk— save states for multiple devices in one call
Scenes
- GET
/api/scenes→{ success, scenes[] } - POST
/api/scenes— create a scene:{ "name": "Evening", "description": "..." } - PUT
/api/scenes/:id— update - DELETE
/api/scenes/:id - POST
/api/scenes/:id/activate— recall the scene
Groups
Control multiple devices at once.
- GET
/api/groups→{ success, groups[] } - POST
/api/groups— create a group - PUT
/api/groups/:id/control— same body as device control, applied to every member
Energy
- GET
/api/energy-logs— raw log entries - GET
/api/energy-logs/stats— aggregated statistics - GET
/api/energy-logs/carbon→{ totalEmissions, bySource, totalKwh, emissionFactor } - GET
/api/energy-logs/cost— cost breakdown →{ byArea[] } - GET
/api/energy-logs/device/:deviceId— per-device energy history
Spaces (Areas & Floors)
- GET
/api/spaces→{ success, spaces[] } - POST
/api/spaces— create a space - GET
/api/spaces/:id/devices— devices in a space - GET
/api/spaces/:id/stats→{ success, childSpaces, deviceCount, sceneCount } - GET
/api/floorplans
Alerts
- GET
/api/alerts· POST/api/alerts· PUT/api/alerts/:id· DELETE/api/alerts/:id
Example create body:
{ "name": "High Energy Usage", "type": "energy", "threshold": 5.0, "zone": "Lobby" }
Activities
Live system activity feed.
- GET
/api/activities— the activity feed (returns an array) - GET
/api/activities/stats→{ total, unread, byType, byArea } - PUT
/api/activities/mark-all-read
Schedules
Time-based automation.
- GET
/api/schedule-events→{ success, events[] } - POST
/api/schedule-events· PUT/api/schedule-events/:id· DELETE/api/schedule-events/:id
System
- GET
/api/health→{ overall, timestamp, version, components: { api, database, serial, firestore } } - GET
/api/system/info→{ success, data: { hostname, os, uptime, cpuTemp, memory, disk } } - GET
/api/system/network→{ success, data: { interfaces, wifi } } - POST
/api/system/reboot— ⚠️ reboots the gateway; all control and API access drops until it restarts. Use with care.
Quick Start & Testing
# 1. List devices
curl -s http://<gateway-ip>:5000/api/devices \
-H "Authorization: Bearer <token>"
# 2. Read one device's live state
curl -s http://<gateway-ip>:5000/api/devices/<id> \
-H "Authorization: Bearer <token>"
# 3. Turn a light on at 60%
curl -s -X PUT http://<gateway-ip>:5000/api/devices/<id>/control \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"power": true, "brightness": 60}'
Watch the effect live:
const ws = new WebSocket("ws://<gateway-ip>:5000");
ws.onmessage = (e) => console.log(JSON.parse(e.data));
// → a "welcome" event, then "deviceState" events as lights and sensors change
Response shapes
Successful responses wrap their payload in a top-level key that varies by endpoint — for example devices, sensors, scenes, state, events, or data, and a few (such as /api/activities) return a bare array. Read the key named for the resource; most responses also include success: true.
Error Handling
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request — check body or parameters |
| 401 | Unauthorized — missing or expired token |
| 403 | Forbidden — valid token, insufficient permission |
| 404 | Not found |
| 429 | Rate limit exceeded |
| 500 | Server error (includes a fixture that did not acknowledge a control command) |
Error format:
{ "error": "Unauthorized", "message": "Token expired", "statusCode": 401 }