Home Assistant integration for Nanoleaf Essentials bulbs that adds scene activation support — the one thing the standard Matter integration cannot do. Basic controls (power, brightness, color) are available too, but if you only need those, the built-in Matter integration is sufficient.
Communicates directly over Thread using Nanoleaf's proprietary LTPDU protocol. Nanoleaf cloud is only used to resolve scene names from palette data (if needed), but the integration works without internet access and does not require a cloud account.
| Model | Name | Status |
|---|---|---|
| NL67 | Essentials A19 / A60 (Matter) | Tested |
| NL45 | Essentials A19 (legacy) | Tested |
| NL55 | Essentials Bulb (legacy) | Should work |
| NL58 | Essentials Candle (legacy) | Should work |
| NL62 | Essentials BR30 (legacy) | Should work |
NL55/NL58/NL62 use the same protocol variant as NL45 and are expected to work but have not been verified on hardware.
| Feature | HA Integration |
|---|---|
| Scenes / effects | yes — primary feature |
| Power on/off | yes |
| Brightness | yes |
| Hue / saturation | yes |
| Color temperature | yes |
| Identify (blink) | yes |
| Thread diagnostics | yes (sensor entities) |
| Device info | yes (device page) |
Scenes are stored on the device as palette data and resolved to cloud scene names via scenes.json. See SCENES.md.
HACS is the Home Assistant Community Store. If you don't have it installed yet, follow the HACS installation guide first.
This integration is not (yet) in the default HACS repository, so it must be added as a custom repository:
- Open HACS in Home Assistant.
- Click the ⋮ menu (top right) -> Custom repositories.
- Add the repository:
- Repository:
https://github.com/Jaano/nanoleaf_lights - Type:
Integration
- Repository:
- Click Add, then find Enhanced Nanoleaf Lights in the HACS integrations list and click Download.
- Restart Home Assistant (Settings -> System -> Restart).
- Continue with Adding a Device.
Updates will appear in HACS like any other integration; click Update and restart HA.
- Copy (or symlink) the
custom_components/nanoleaf_lights/directory from this repository into your Home Assistantconfig/custom_components/directory. The final path should beconfig/custom_components/nanoleaf_lights/. - Restart Home Assistant.
- Continue with Adding a Device.
The integration requires aiocoap and cryptography; Home Assistant installs them automatically on first load.
Prerequisite: The bulb must already be joined to your Thread network via Matter (e.g. using the Nanoleaf app or Apple Home). Matter is not used by this integration — only for the initial network join.
- Go to Settings -> Devices & Services -> Add Integration and search for Enhanced Nanoleaf Lights.
- Devices on the local Thread network are auto-discovered via mDNS. Alternatively enter the address manually (IPv6, IPv4, or hostname).
- Enter the Pairing Code printed on the bulb.
If a bulb is unpaired and re-paired in your Matter environment (e.g. re-added in the Nanoleaf or Apple Home app, or after a factory reset), it will rejoin Thread with a new IPv6 address and a new pairing code. The existing Home Assistant device entry will stop working until it is pointed at the new address.
To recover without removing and re-adding the integration:
- Go to Settings -> Devices & Services -> Enhanced Nanoleaf Lights and open the affected device.
- Click the ⋮ menu -> Reconfigure.
- Confirm the new address (auto-discovered or entered manually) and, if the bulb was factory-reset, enter the new Pairing Code.
The device's existing entities, history, and automations are preserved.
By default, Enhanced Nanoleaf Lights automatically shows its entities on the matching Matter/HomeKit device page when it finds exactly one native Nanoleaf device with the same serial number. If you want to change that behavior:
- Go to Settings -> Devices & Services -> Enhanced Nanoleaf Lights and open the device.
- Click Configure.
- Choose automatic matching, standalone mode, or the matching Matter/HomeKit device page.
The Enhanced light entity stays separate from the Matter/HomeKit light entity, so scenes/effects remain available through the Enhanced light. If no verified serial match is available, the Enhanced entities stay on their standalone device page.
Scenes are automatically resolved to their cloud names. Use the Refresh Scene Database button entity to download the latest scene data from the Nanoleaf cloud. This download can take several minutes to complete. See SCENES.md for how palette matching works.
The integration polls every 5 seconds. Device info, scene list, and scene names are fetched once on first connect and cached until the integration is reloaded. Session expiry triggers automatic re-authentication.
Devices are controlled via LTPDU — a CoAP/UDP protocol with X25519 key exchange and AES-128-CTR encryption. Separate from Matter and no cloud required.
- Transport: CoAP over UDP via Thread border router
- Discovery: mDNS
_ltpdu._udp.local. - Addressing: IPv6 natively; IPv4 and hostname also work when NAT64 is enabled on the border router
See LTPDU.md for the full protocol reference.
cli.py provides direct device control without Home Assistant.
Discover devices on your Thread network and write a config file for each one:
python cli.py discover --save
# writes e.g. bulb.json, bulb_nl45.json — one file per discovered deviceDownload the Nanoleaf cloud scene database before using scene commands:
python cli.py scene --downloadThis writes scenes.json (~6000 scenes). Re-run any time to update.
# Browse device scenes
python cli.py scene --list --conf bulb.json
# Identify currently active scene
python cli.py scene --current --conf bulb.json
# Preview a scene (temporary, not stored)
python cli.py scene --preview "Police 1" --conf bulb.json
# Add a scene to the device
python cli.py scene --add "Police 1" --conf bulb.json
python cli.py scene --add "Police 1" --effect flow --conf bulb.json
python cli.py scene --add "Halloween 2026" --effect fade --transition 10 --conf bulb.json
# Activate a stored scene by name or slot ID
python cli.py scene --play "Police 1" --conf bulb.json
python cli.py scene --play 12 --conf bulb.json
# Replace a stored scene
python cli.py scene --replace 12 "Halloween 2026" --conf bulb.json
# Delete a scene
python cli.py scene --delete "Police 1" --conf bulb.json
# Dry-run: show payload info without sending to device
python cli.py scene --add "Police 1" --dry-run --conf bulb.json| Option | Default | Applies to |
|---|---|---|
--effect TYPE |
fade |
all add/preview |
--transition N |
24 | all effects except stream |
--wait N |
0 | fade, random, highlight, flow |
--loop / --no-loop |
loop on | fade, flow |
--main-probability N |
80 | highlight |
--direction N |
0 | flow, stripes |
--segment N |
50 | stripes |
--max-colors N |
7 | all |
--compact-repeats |
off | all (experimental) |
Effect types: fade, random, highlight, stream, flow, stripes.
See LTPDU.md and SCENES.md for protocol and palette details.
pip install pytest # or: pip install -e ".[dev]"
python -m pytestMIT License — Copyright (c) 2026 @Jaano. See LICENSE for full text.