TapHome

Nanoleaf RGB light

Packet Parser → HTTP
Submitted by
Last updated: 04. 2026
Nanoleaf RGB light

Nanoleaf is a family of Wi-Fi LED lighting products — modular wall panels, LED strips, bulbs, floor lamps and holiday string lights — that all speak the same local REST API on TCP port 16021. A single TapHome template covers every WiFi-reachable Nanoleaf product: TapHome polls the controller over HTTP on the LAN and exposes the whole layout as a single HSB light with colour temperature.

Supported models

ProductModel codeNotes
Light Panels (formerly Aurora)NL22No touch
Shapes HexagonsNL42Touch-enabled
Shapes TrianglesNL47Touch-enabled
Shapes Mini TrianglesNL48Touch-enabled
Canvas (Squares)NL29Touch-enabled
Elements Hexagons (Wood Look)NL52Narrower CCT range (1500–4000 K)
LinesNL59Touch-enabled
Matter WiFi Essentials (Bulbs, Lightstrips, Holiday String Lights, Floor Lamp, A19)Firmware 3.0.10+ only; stricter brightness floor and narrower CCT (2127–6535 K)

Thread-only Nanoleaf Essentials and the Nanoleaf Skylight are not supported — the template requires a WiFi-reachable controller speaking the Open API on port 16021.

Device capabilities

Light (HSB + colour temperature)

The template exposes a single HSB light with on/off, brightness, hue, saturation and colour temperature. On every poll cycle (500 ms) the module sends

1
GET /api/v1/{authToken}/

and caches the full device JSON in the StatusJson custom variable. Per-property readscripts then parse fields from that cached blob:

  • On/offstate.on.value
  • Brightnessstate.brightness.value (0–100), normalized to TapHome’s 0.0–1.0 range
  • Huestate.hue.value (0–360°) — only read when state.colorMode == "hs"
  • Saturationstate.sat.value (0–100) — only read when state.colorMode == "hs"
  • Colour temperaturestate.ct.value (Kelvin) — only read when state.colorMode == "ct"

All writes go to PUT /api/v1/{authToken}/state with a per-property JSON body:

1
2
3
4
{ "brightness": { "value": 75 } }
{ "hue":        { "value": 212 } }
{ "sat":        { "value": 100 } }
{ "ct":         { "value": 4000 } }

The template declares 1800–6500 K as the colour-temperature range — a practical subset of what the hardware actually supports. Values outside the device’s physical band are silently clamped by Nanoleaf firmware (see Notes and limitations).

Colour mode gating

Nanoleaf controllers are always in exactly one of three colour modes:

colorModeMeaning
hsHue / saturation mode — hue and saturation values are live
ctColour-temperature mode — CCT value is live
effectA dynamic scene is running

The TapHome readscripts respect this: hue and saturation reads return NULL when the controller is in ct or effect mode, and the colour-temperature read returns NaN when it is in hs or effect mode. This prevents stale cross-mode values from being fed into the dashboard. Writing any hue / saturation value switches the controller to hs, and writing a CCT value switches it to ct — both stop any running effect.

Configuration

1. Pair the controller on the Nanoleaf app

Mount the panels / bulb / strip, install the Nanoleaf mobile app and connect the controller to the local Wi-Fi network through the app’s pairing flow. Note the controller’s IPv4 address — the app shows it under device settings → Info, or it can be read from the router’s DHCP lease table.

Assign a DHCP reservation (or static IP) to the Nanoleaf controller so the address does not change after a lease renewal. The TapHome template stores the IP in its import parameters and does not auto-discover.

2. Generate the Open API token

The Nanoleaf Open API requires a one-time pairing between TapHome and the controller. The pairing produces a permanent 32-character auth_token that survives reboots and firmware upgrades.

  1. On the Nanoleaf controller (the small inline unit for panels, or the device itself for bulbs / strips), hold the on-off button for 5–7 seconds until the white LED starts flashing in a pattern. The device is now in pairing mode for 30 seconds.

  2. Within the 30-second window, send an empty POST to the pairing endpoint — for example with curl, PowerShell or Postman:

    1
    
    curl -X POST http://{controller-ip}:16021/api/v1/new
    

    The controller responds with:

    1
    
    { "auth_token": "xxxKJISJCjY2hfAyilpyIOfGixxxx" }
    
  3. Copy the 32-character auth_token string.

If the window expires before the POST arrives, the endpoint returns 403 Forbidden — hold the on-off button again and retry.

Some Essentials form factors (bulbs, strips) do not have a physical button. In that case, start pairing from the Nanoleaf app’s device settings — the app arms the 30-second window for you.

3. Import the template in TapHome
  1. In TapHome, create a new PacketParser device from the Nanoleaf RGB light template.
  2. Enter the controller’s IPv4 address as the ipAddress import parameter. The port is fixed to 16021 and does not need to be changed.
  3. Open the device properties, find the authToken custom variable and paste the 32-character token generated in step 2.
  4. Save. The module will poll /api/v1/{authToken}/ every 500 ms and populate the HSB light with the current state.

If the token is wrong or expired, every read fails with 401 Unauthorized in the TapHome log.

Network requirements
  • Only outbound TCP 16021 from the TapHome CCU to the Nanoleaf controller. No cloud calls, no MQTT broker, no HTTPS certificates.
  • The CCU and the controller must be on the same LAN / VLAN. If the Wi-Fi and wired networks are segregated, add a firewall rule allowing TCP 16021 between them.
  • Nanoleaf controllers advertise the service _nanoleafapi._tcp over mDNS. The template requires a direct IP, but mDNS can be used for discovery with avahi-browse -r _nanoleafapi._tcp (Linux) or dns-sd -B _nanoleafapi._tcp (macOS).

The Nanoleaf Open API is HTTP only — there is no HTTPS and no transport encryption. It is safe inside the LAN but must never be exposed to the public internet. Do not forward port 16021 through the router.

Notes and limitations

Colour-temperature range depends on model family

The TapHome template declares 1800–6500 K as the writable CCT range. The underlying hardware band differs per family:

FamilyHardware CCT rangeBehaviour outside range
Light Panels, Shapes, Canvas, Lines1200–6500 KClamped by firmware
Elements Hexagons1500–4000 KClamped by firmware
Matter WiFi Essentials2127–6535 KClamped by firmware; 1800 K is below the 2127 K floor, so Essentials will clamp to 2127 K

Writing a value outside the device’s physical band does not raise an error — the controller silently uses its own limit. When designing dashboards that target Essentials, prefer CCT values in the common 2127–6500 K window.

Essentials reject brightness = 0

Classic controllers (Light Panels, Shapes, Canvas, Elements, Lines) accept brightness: 0. Matter WiFi Essentials enforce a minimum of 1 and reject 0 with HTTP 400. To power down an Essentials bulb or strip, use the on/off channel instead of driving brightness to zero.

Hue / saturation / CCT reads can return NULL or NaN

Because hs and ct are mutually exclusive, and both are inactive during a running effect, the wrong-mode reads deliberately return NULL (hue / sat) or NaN (ct). This is expected behaviour, not a fault. A hue / sat / ct write brings the controller back to hs or ct mode and the reads resume.

One token per controller, not per panel

A multi-panel Shapes or Canvas layout is a single TapHome device. The auth token is issued at controller level and covers every panel connected to it.

IPv6 mDNS instability on firmware 8.5.2+

The openHAB community has reported that IPv6 mDNS records alternate between ONLINE and OFFLINE on some firmware 8.5.2+ controllers. If mDNS discovery is unstable, set a fixed IPv4 DHCP reservation and use the IP directly — the TapHome template does not rely on mDNS anyway.

Troubleshooting

401 Unauthorized on every read

The authToken is wrong, expired or has been revoked. Generate a new token (hold the on-off button for 5–7 s and POST /api/v1/new) and paste it into the authToken custom variable.

403 Forbidden when generating a token

The 30-second pairing window has closed. Hold the on-off button again until the LED flashes in a pattern, then immediately send POST /api/v1/new.

Hue / saturation show NULL in the dashboard

The controller is in ct mode or running an effect. Write any hue or saturation value to switch the controller back to hs mode, or set a colour with the HSB picker. The template cannot infer a hue / sat reading when the device is not producing one.

Colour temperature reads as NaN

The controller is in hs mode or running an effect. Write a CCT value to switch to ct mode, or set a colour temperature from the dashboard. If an effect is running, stop it from the Nanoleaf app (or write any HSB / CCT value — this also stops the effect).

Brightness write fails on Essentials

Matter WiFi Essentials reject brightness: 0. Drive the on/off channel to power down instead of writing 0 to brightness. Values 1–100 are accepted on all models.

Controller drops offline on firmware 8.5.2+

If the TapHome CCU repeatedly loses the controller, assign a static IPv4 DHCP reservation and use the IP in the ipAddress import parameter — the IPv6 mDNS layer can be unstable on this firmware branch.

Available devices

Nanoleaf Module
Custom Variables
authToken (string) = xxxKJISJCjY2hfAyilpyIOfGixxxx32-character Nanoleaf Open API pairing token. Generate it once by holding the controller's on-off button for 5–7 seconds and sending POST http://{ip}:16021/api/v1/new within 30 seconds — paste the returned auth_token here. The token survives reboots and firmware upgrades.
1) Hold the controller's on-off button for 5–7 seconds until the LED flashes in a pattern. 2) Within 30 seconds, send an empty POST request to http://{ip}:16021/api/v1/new (curl, Postman, or any HTTP client). 3) Copy the 32-character auth_token from the response and paste it into this variable.

Nanoleaf

Read (module)
#Generate an authorization token
# 1. On the Nanoleaf controller, hold the on-off button for 5-7 seconds until the LED starts flashing in a pattern.

# 2. Send a POST request to the authorization endpoint within 30 seconds of activating pairing, like this (substituting the IP address and port for your central controller):
#http://$[IpAddress]:16021/api/v1/new


VAR response := SENDHTTPREQUEST("/api/v1/"+authToken+"/", "GET");
IF response.IsSuccess
 StatusJson := response.Content;
ELSE
 ADDERROR(response.StatusCode + " (" + response.ReasonPhrase + ")");
END
Nanoleaf RGB light HSB Light

HSB light with dual colour mode — hue and saturation (0–360° / 0–100 %) or colour temperature (1800–6500 K declared, hardware range depends on model). Brightness 0–100 %. Hue / saturation reads are active only in hs mode; CCT reads are active only in ct mode; both are inactive during a running effect.

HSBLight json

Nanoleaf RGB light

Read (module)
var value := PARSEJSON(StatusJson, "state.on.value");
IF(ISNULL(value), NaN, IF(value, 1, 0));
Read brightness
var value := PARSEJSON(StatusJson, "state.brightness.value")/100;
IF(ISNULL(value), NaN, value);
Write brightness
var content:="{\"brightness\" : {\"value\":"+ROUND(Hb*100)+"}}";
var response := SENDHTTPREQUEST("/api/v1/"+authToken+"/state", "PUT", content);
Read hue
var colorMode := PARSEJSON(StatusJson, "state.colorMode",1);
IF colorMode = "hs"
  var value := PARSEJSON(StatusJson, "state.hue.value",1);
  RETURN(IF(ISNULL(value), NaN, value));
ELSE
  RETURN(NULL);
END
Write hue
var content:="{\"hue\" : {\"value\":"+ROUND(Hd)+"}}";
var response := SENDHTTPREQUEST("/api/v1/"+authToken+"/state", "PUT", content);
Read saturation
var colorMode := PARSEJSON(StatusJson, "state.colorMode",1);
IF colorMode = "hs"
  var value := PARSEJSON(StatusJson, "state.sat.value",1);
  RETURN(IF(ISNULL(value), NaN, value/100));
ELSE
  RETURN(NULL);
END
Write saturation
var content:="{\"sat\" : {\"value\":"+ROUND(Sa*100)+"}}";
var response := SENDHTTPREQUEST("/api/v1/"+authToken+"/state", "PUT", content);
Read color temperature
var colorMode := PARSEJSON(StatusJson, "state.colorMode",1);
IF colorMode = "ct"
  var value := PARSEJSON(StatusJson, "state.ct.value",1);
  RETURN(IF(ISNULL(value), NaN, value));
ELSE
  RETURN(NaN);
END
Write color temperature
var content:="{\"ct\" : {\"value\":"+ROUND(Ct)+"}}";
var response := SENDHTTPREQUEST("/api/v1/"+authToken+"/state", "PUT", content);
Connection: Packet Parser → HTTP
Possible improvements (10)
  • Effects / Scenes — PacketParserHSBLight ignores the /effects endpoint — dynamic scenes (Color Burst, Cyan Sky, user plugins, etc.) can only be started from the Nanoleaf app. Once an effect is running, TapHome can still drive on/off and brightness over it.
  • Custom effect creation — Plugin-based and static custom effects (animType = plugin / static / custom) are not supported by the template.
  • Identify — Flashes the panels for 2–3 seconds so the installer can confirm which controller they are addressing. Not exposed as a service action.
  • Panel layout — Per-panel positions, shapes, and global rotation are available from the API but not surfaced — TapHome treats the whole controller as a single HSB light.
  • Rhythm module — Audio-reactive Rhythm add-on status (connected, active, mode, aux availability) not exposed.
  • External UDP streaming — Real-time per-panel RGBW streaming for music visualizers / screen mirror is outside the scope of PacketParserHSBLight.
  • Server-Sent Events push — Push notifications for state / layout / effect / touch changes. Template uses 500 ms polling instead — adequate for HS/CT/brightness/on-off.
  • Touch / gesture input — Single tap, double tap, long press, swipe gestures on Canvas and touch-enabled Shapes are not exposed.
  • Fade transitions — The brightness PUT accepts an optional `duration` field for hardware-level fades — template writes bare value without transition.
  • Revoke auth token — Tokens can be explicitly revoked via DELETE. Not exposed as a service action — removal must be done manually with curl.

Sources