Skip to main content

Nanoleaf Panels

Local-LAN control for Nanoleaf Shapes, Canvas, Lines, Elements, and Light Panels via the documented OpenAPI v1.7 on port 16021. Pairing is on-device (hold the power button until the LED flashes), then GEM stores a bearer token on the device row. No cloud account required.

Prerequisites

  • Firmware 1.5.0 or newer. Older controllers running 1.4 firmware do not expose the OpenAPI. Update via the Nanoleaf mobile app first.
  • Static DHCP reservation on the controller is strongly recommended. Nanoleaf does not advertise mDNS reliably after a Wi-Fi drop, and the controller does not push state — GEM polls.
  • Same Layer 2 segment as the GEM server. The Nanoleaf mobile app discovers via mDNS; if you cannot find the controller from a desktop on the same VLAN, neither will GEM.

Setup

  1. Add a device with driver nanoleaf and the controller IP.
    • Find the IP in the Nanoleaf mobile app: Layout → ... → Controller Info, or in your router's DHCP table (the MAC starts with 00:55:DA).
  2. Put the controller into pairing mode. Hold the power button on the controller for 5–7 seconds until the LED begins flashing. You have ~30 seconds.
  3. Run pair_token from the device command panel. On success the returned token is written to the device's auth_token attribute automatically and stored encrypted.
  4. Run get_info to confirm the panel set is reachable and to see the firmware / panel layout.
  5. The device is now a single-zone light. on, off, set_level, set_color, set_ct, and set_effect are immediately available.

Attribute reference

AttributeRequiredDefaultNotes
ipyesController LAN IP.
portno16021OpenAPI port. Only change for proxied deployments.
auth_tokenpopulatedBearer token issued by pair_token. Stored encrypted; do not edit by hand.
status_intervalno10000 msPolling cadence. The controller pushes nothing; polling is the only state path.
default_transition_msno500 msDefault fade duration for set_level / set_color / set_ct.

Zone address

The Nanoleaf controller is treated as a single-zone device — one panel set = one logical light. Per-panel addressing requires the External Control (UDP streaming) extension, which is not implemented in this driver.

Commands

CommandArgumentsNotes
on / off / togglePower. toggle flips based on the last cached state.
set_levellevel (0–100), optional duration_msSends brightness.duration as integer tenths of a second; duration_ms < 100 becomes an instant change.
set_ctct (Kelvin, clamped 1200–6500)Color temperature.
set_colorcolor ("FF8800" or {h,s,v})Solid color; brightness is the value channel.
set_hsvhue (0–360), saturation (0–100), value (0–100)Lower-level color set.
set_effecteffect (name)Activates an installed effect. List via get_effects.
identifyBriefly flashes the panels white, then restores.
pair_tokenIssue a new auth token. Controller must be in pairing mode.
get_infoFull controller payload (firmware, panel layout).
get_statePower, brightness, CT, color state.
get_effectsList of installed effect names.

Known limitations

  • Effects ("scenes") are user-installed. The list returned by get_effects is per-device and will differ between deployments. GEM does not enumerate them at boot — call get_effects from the admin UI when needed.
  • External Control UDP streaming is out of scope. Per-panel pixel control (touch effects, music sync, individual-tile animation) requires switching the controller into extControl v2 mode and sending UDP packets at ~25 Hz. Use the Nanoleaf mobile app for those features.
  • The controller drops idle TCP sockets aggressively. Expect 1–2s of latency on the first request after a long pause; subsequent requests reuse the socket.

Troubleshooting

  • controller not in pairing mode (403 on pair_token) — Hold the controller power button 5–7 seconds until the LED flashes white, then retry within 30 seconds.
  • unauthorized (401) on any command — The stored auth_token is no longer valid (factory reset, firmware downgrade, or user revoked it in the Nanoleaf app). Re-run pair_token.
  • ECONNREFUSED on poll — Controller is offline or the IP changed. Verify the DHCP lease and reachability with ping.
  • State changes from the Nanoleaf app are not visible for up to status_interval ms — The controller does not push, GEM polls. Reduce status_interval if you need faster reflection, but the controller may rate-limit polling below ~2 seconds.