/

LUMA-6CH / Open HTTP API

HTTP API documentation

Technical reference for integrating LUMA-6CH with applications, automation systems and tools running on the local network.

Minimum firmware 0.9.63Revision 26 August 2026HTTP / JSON / LAN

1 / Base URL and access

The API uses HTTP/1.1 on the local network and is available at http://luma.local or the device IP address. Never expose the device's port 80 directly to the Internet.

Static documentation

This page provides copyable examples but never communicates with the device. This avoids mixed-content, CORS and Private Network Access problems and accidental token exposure.

  • Requests and responses use JSON with Content-Type: application/json.
  • API responses use Cache-Control: no-store.
  • Successful commands return {"ok":true}; errors use an HTTP 4xx/5xx status and, where applicable, {"ok":false,"error":"..."}.

2 / Local authentication

When api.auth_required is true, protected routes require Authorization: Bearer <token>. Only unlock assets, GET /api/auth/status and POST /api/auth/login remain public.

MethodRouteDescription
GET/api/auth/statusPublic: reports only whether unlock is required.
POST/api/auth/loginPublic, 512 B maximum. Exchanges the password for a revocable RAM session.
POST/api/auth/passwordSets, changes or removes the local password and revokes existing sessions.
POST/api/tokensCreates a persistent integration token; its secret is shown once.
DELETE/api/tokens/<id>Revokes an integration token.

The local password must contain at least 8 characters; an empty string removes it. Interactive sessions live in RAM for 12 hours and are revoked after a password change or reboot. After five failed logins the device returns 429 try_later for 30 seconds. The persistent verifier uses PBKDF2-HMAC-SHA256 with a random salt and versioned cost.

Interactive session

read -s LUMA_PASSWORD
LUMA_TOKEN=$(curl -fsS -H 'Content-Type: application/json' \
  -d "{\"password\":\"$LUMA_PASSWORD\"}" \
  http://luma.local/api/auth/login | jq -er .token)

curl -fsS -H "Authorization: Bearer $LUMA_TOKEN" \
  http://luma.local/api/state

Persistent integration token

For Home Assistant, Node-RED, backends and automations, create a separate credential using an administrative session. Store the secret field in a secret store, never in a repository.

INTEGRATION=$(curl -fsS -X POST \
  -H "Authorization: Bearer $LUMA_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"label":"Home Assistant"}' \
  http://luma.local/api/tokens)

LUMA_API_TOKEN=$(printf '%s' "$INTEGRATION" | jq -er .secret)
LUMA_TOKEN_ID=$(printf '%s' "$INTEGRATION" | jq -er .id)

3 / State and data model

  • Six wired channels 0..5 for PWM mono LEDs, with per-channel INA219 measurement.
  • RGB/RGBW/CCT groups with base 0 or 3, depending on layout.
  • Addressable S1/S2 strips as virtual groups 6 and 7; they use an external supply and have no power measurement.
  • Scenes scenarios, wall switches 1..2, and zones/sensors.
MethodRouteResult
GET/api/stateComplete state: channels, groups, strips, scenes, switches, Wi-Fi, OTA, temperature, power and api.auth_required.
GET/api/devicesOther LUMA devices discovered on the network.
GET/api/channels/mapLogical-channel to physical-LEDC map.
GET/api/wifi/scanAsynchronous scan: {scanning, networks[]} or array.
GET/api/config/exportSchema 2 backup without passwords, tokens, cloud identity or energy history.

/api/state.system exposes nvs_queue_overflows, nvs_queue_pending and nvs_flush_failures. A non-zero error counter indicates an asynchronous commit that did not reach flash.

/api/state.inputEvents keeps the latest 32 SW1/SW2 events in RAM, in order, with sequence, timestamp, switchId and type. The sequence restarts after reboot and the queue is not persistent.

4 / Wired channels 0–5

MethodRouteBody
POST/api/channel/<n>{state?, pwm?, name?, effect?, gamma_active?, restore_after_power_loss?, dimming_ms?, max_voltage_v?, max_current_a?, max_power_w?}
POST/api/channel/<n>/pwm{"value": 0..100}
POST/api/channel/<n>/effect{"effect":"static|breathe|blink|strobe|fade|tube"}
POST/api/channel/<n>/name{"name":"..."}
POST/api/channel/<n>/identify{}

pwm:0 is not off: use {"state":false} so the previous level is retained. dimming_ms is the full 0→100% transition time, integer 0..10000; zero is immediate.

Electrical limits

User limits cannot exceed 25.5 V, 7.5 A and 180 W per channel. The effective limit is 90 W at 12 V and 180 W at 24 V; the independent fast trip remains 9 A. The aggregate governor uses min(20.8333 A, 500 W / Vbus): 250 W at 12 V and 500 W at 24 V.

curl -fS -X POST -H "Authorization: Bearer $LUMA_TOKEN" \
  -H 'Content-Type: application/json' \
  http://luma.local/api/channel/0 -d '{"state":true,"pwm":60}'

5 / RGB, RGBW, CCT groups and strips

Analogue groups use base 0 or 3; S1/S2 strips use base 6 and 7. In analogue groups, channel positive terminals must be bridged while PWM returns remain separate. Displayed power is the sum of the INA readings and the most restrictive branch governs group derating.

MethodRouteBody
POST/api/group/<base>{state?, brightness?, white?, color?, effect?, name?, restore_after_power_loss?}
POST/api/group/<base>/color{"color":"#rrggbb"}
POST/api/group/<base>/brightness{"value":0..100}
POST/api/group/<base>/white0..100: RGBW W intensity or CCT position, from 2700 K to 6500 K.
POST/api/group/<base>/effectstatic, breathe, rainbow, cycle, chase, strobe, warm-mix, blink, fade, tube, cct-cycle
POST/api/group/<base>/name{"name":"..."}
POST/api/strip/<port>/config{enabled?, chip? (0..3), led_count? (1..1024), gamma?}
POST/api/all{"state":true|false}

For strip configuration, port 0 = S1 and 1 = S2. Chip 0: WS2812/13/15/SK6812 RGB (GRB); 1: WS2811/UCS1903 RGB 800 kHz; 2: SK6812 RGBW; 3: APA102/SK9822. Chip 3 uses S1 for data and S2 for clock, therefore excluding the second strip.

curl -fS -X POST -H "Authorization: Bearer $LUMA_TOKEN" \
  -H 'Content-Type: application/json' \
  http://luma.local/api/group/6 \
  -d '{"state":true,"brightness":40,"color":"#ff0000","effect":"rainbow"}'

6 / Scenes and wall switches

MethodRoutePurpose
GET/api/scenariosComplete list; stable IDs 0..15.
POST/api/scenariosCreates a scene using the /api/state → scenarios[] schema.
POST/api/scenarios/<id>Updates the scene.
POST/api/scenarios/<id>/runRuns the scene.
DELETE/api/scenarios/<id>Deletes the scene.
POST/api/switch/<id>{label?, input_type?, long_press_ms?, binding?, long_press_binding?}

Scene actions are {type:"channel"|"group"|"all", target, state, value, color?}. For switches, channel_mask uses bits 0–5 for channels and 6/7 for S1/S2; zero means all.

7 / Network, zones and configuration

MethodRouteBody / result
POST/api/device/name{"name":"..."}
POST/api/setup/completeAtomic wizard commit; requires a valid name and layout.
GET/api/zonesComplete snapshot, excluded from /api/state polling.
POST/api/zonesCreates a lux zone with a complete payload.
POST/api/zones/<id>Updates the zone; its ID is immutable.
POST/api/zones/<id>/calibrateStarts calibration when channels and sensors are available.
POST/api/wifi/connect{"ssid":"...","password":"..."}
POST/api/wifi/disconnect{}
POST/api/channels/map[0,1,2,3,4,5]
POST/api/config/importComplete JSON backup.
GET/api/config/exportSanitised schema 2 backup.
POST/api/config/factory-resetWipes NVS and reboots; 409 during OTA.

/api/config/layout accepts: mono6, rgb_mono, mono_rgb, rgb2, rgbw_mono, cct_mono4, m_cct_m3, m2_cct_m2, m3_cct_m, mono4_cct, cct2_mono2, mono2_cct2, rgb_cct_m, cct_m_rgb, rgbw_cct.

8 / Energy and pricing

MethodRouteDescription
GET/api/energy/historyToday, month, 366 completed days, 12 completed months, tariff and unrounded costs.
POST/api/prefs/kwh-price{"value":0..1000}
POST/api/prefs/currency{"currency":"EUR","symbol":"€"}
POST/api/prefs/reset-energyResets only the current daily counter.
curl -fsS -H "Authorization: Bearer $LUMA_TOKEN" \
  http://luma.local/api/energy/history | jq '.today, .month'

curl -fS -X POST -H "Authorization: Bearer $LUMA_TOKEN" \
  -H 'Content-Type: application/json' -d '{"value":0.2845}' \
  http://luma.local/api/prefs/kwh-price

9 / Local schedules

MethodRoutePurpose
GET/api/schedulesList with ID, configuration and next execution.
POST/api/schedulesCreates and returns the firmware ID with 201.
POST/api/schedules/<id>Replaces a schedule.
DELETE/api/schedules/<id>Deletes a schedule.
GET/POST/api/prefs/locationPrivate location for sunrise and sunset.
POST/api/prefs/timezonePOSIX timezone from the firmware whitelist.
POST/api/prefs/locale{"locale":"en|it"}

Maximum 16 schedules. Channel masks 1..0x3f, weekdays 1..0x7f (bit 0 = Monday), minutes 0..1439, event 0=fixed, 1=sunrise, 2=sunset, solar offset -180..180. Impossible payloads return 422 invalid_schedule.

10 / OTA

MethodRoutePurpose
GET/api/ota/info · /api/ota/logPartition state and non-sensitive log.
POST/api/ota/check · /api/ota/rollbackChecks for updates and rolls back. Updates are signed and delivered by ota.objex.cloud.

11 / KNXnet/IP

The current build includes the KNXnet/IP tunnelling client. Configuration and mappings are persistent and every route requires authentication.

MethodRouteBody
POST/api/knx/enabled{"enabled":true|false}
POST/api/knx/mode{"mode":"tunnel"}
POST/api/knx/gateway{"gateway":"192.168.1.53"}
POST/api/knx/port{"port":3671}
POST/api/knx/physical{"physical":"1.1.250"}
POST/api/knx/mappingsArray of up to 6 channel and switch/dim/feedback GA mappings.

Group addresses are main/middle/sub (0..31/0..7/0..255). KNX Secure secrets are never returned.

12 / MQTT

The user-configurable MQTT client is separate from the private OBJEX Cloud connection. Routes require local authentication; passwords and CAs are never returned.

MethodRouteBody / result
GET/api/mqtt/userNon-secret configuration, connection, base topic and diagnostics.
POST/api/mqtt/user{enabled, transport, host, port, clientId, username, password, prefix, caPem}
POST/api/mqtt/user/clear-passwordClears the stored password.
POST/api/mqtt/user/clear-caClears the custom CA certificate.
POST/api/mqtt/user/publish-nowPublishes state and telemetry now.
POST/api/mqtt/user/testTests the session: 409 if disabled, 503 if disconnected.

Empty secret fields retain the existing value; use the dedicated routes to clear them. The mqtt transport requires allowPlaintext:true. MQTT commands always pass through canonical state and cannot bypass electrical or thermal protection.

13 / Home Assistant

The direct integration is independent from MQTT: it uses Zeroconf and HTTP REST on the LAN. Inventory follows Channel setup and exposes mono, RGB, RGBW, CCT and strips as logical entities.

MethodRouteBody / result
GET/api/home-assistantOpt-in, local_http transport, API version, stable identity and inventory.
POST/api/home-assistant{"enabled":true|false}

Do not manually create REST switches in YAML. Enable Settings → Protocols → Home Assistant, install the luma component and complete pairing under Settings → Devices & services. The password is used once; the component stores only its dedicated token.

14 / Limits, errors and concurrency

  • Ordinary bodies: maximum 8 KB and 4 s; login: 512 B; authenticated import: 64 KB and 10 s.
  • 400 invalid JSON/type/URL; 401 missing or expired authentication; 404 missing resource; 409 conflict; 422 impossible configuration; 500 persistence failure; 503 subsystem not ready.
  • Import, channel map, scenes, schedules and zones restore the previous snapshot after an error.
  • Do not send concurrent commands to the same field expecting a merge: the last valid command wins and firmware state remains the source of truth.

15 / Feature availability

  • DALI endpoints /api/dali/* are feature-gated and absent from the current build.
  • KNX is enabled. A build that excludes it returns 404 from /api/knx/* without changing configuration.
  • Cloud MQTT is managed automatically and exposes no manual HTTP commands. The public MQTT client uses independent credentials and namespace.
  • The API can grow with firmware; when in doubt, /api/state is the authoritative reflection of available features.

16 / Destructive actions

These operations can erase data, interrupt service or revoke access. Export the configuration and verify the target before running them.

Factory reset

POST /api/config/factory-reset wipes NVS and reboots the device.

Configuration import

POST /api/config/import replaces current configuration with the validated backup.

OTA rollback

POST /api/ota/rollback changes the active firmware partition.

Scene and schedule deletion

DELETE /api/scenarios/<id> / DELETE /api/schedules/<id>

Token revocation

DELETE /api/tokens/<id> immediately stops the integration using that token.

No section matches your search.