Bedroom lights over Thread, on an ESP32-C6
All my ESPHome lights so far have been on Wi-Fi. That works, but it means every light depends on the Wi-Fi router. Thread is the alternative that has been creeping into smart-home kit. It’s a low-power mesh network built on the same 802.15.4 radio as Zigbee, except that it speaks IPv6. Each device gets a proper IP address, and mains-powered devices relay traffic for their neighbours.
The ESP32-C6 has an 802.15.4 radio built in, and ESPHome 2025.6 added an openthread component. So in June it became possible to build an ESPHome light that never touches the Wi-Fi at all, and I wanted to see how it did.
What appealed was getting the lights off the Wi-Fi. I don’t want restarting the router to stop the lights responding to their sensors, and the mesh is a bonus on top. Battery power wasn’t the draw: ESP32s are too power-hungry for batteries to be practical anyway. What it promises is all the benefits of Zigbee without Zigbee’s protocol limits, so anything ESPHome supports should just work.
Joining the network
There’s no SSID and password. Instead, you give the device the Thread network’s operational dataset, a blob of TLV (type–length–value) bytes that holds the channel, the network name and the network key. You get it from the border router: the box that bridges the Thread mesh to the rest of the home network. The dataset includes the network key, so treat it exactly like a Wi-Fi password. I won’t be putting mine here.
Once it’s on the mesh, the ESPHome API talks to Home Assistant as usual, just over IPv6, which is why the config has to switch IPv6 on.
My border router is the Home Assistant Green, with my old ConBee II stick reflashed to speak Thread. It’s a perfect second life for the stick, which had become unreliable as a Zigbee coordinator once my Zigbee network grew to fifty-odd devices.
The lights
The C6 dev board drives three tunable-white lights from six PWM outputs, one cold and one warm channel per light:
- the left bedside light;
- the right bedside light;
- the bed light.
Between the C6 and the strips sits my own DIY MOSFET board, built around AO3400 MOSFETs. They’re surface-mount, which makes them very tricky to solder by hand. I chose them because they’re on JLCPCB’s basic parts list, so one day I might get a proper board made. They’re also rather good: their gate threshold voltage is so low that the C6’s 3.3 V pins can drive them directly, with no driver stage in between.
The PWM runs at about 19.5 kHz. The ESP8266 controllers elsewhere in the house run at 500 Hz, and they give off a faint whine at that frequency. So this time I pushed it up out of audible range.
The logic is the same shape as the rest of the house, now split into small include files. The sun still decides the colour. It’s 3,700 K by day and 2,800 K in the evening, with a 30-second fade at sunset and sunrise if the lights are on. Two wall switches toggle all three lights together, and a one-second “settle” filter swallows contact bounce.
What’s new is a night mode. Flick the switch between midnight and 7 am and you don’t get the evening’s 90%. You get 20% brightness at 2,700 K, the warmest the strips will go. The idea is that you can find your way without being blinded. The clock comes from Home Assistant, but if that isn’t available the device falls back to SNTP, so the night mode still works when Home Assistant is down.
The C6 dev board’s own RGB LED is exposed too. It serves no purpose whatsoever, and I’ve left it in anyway.
Teething troubles
The first problem was a ghostly glow from the bedside lamp with the longest wire, which stayed faintly lit even when it was meant to be off. A resistor across the LEDs sorted that out.
The second was more stubborn. One of the MOSFETs died and failed short, so the warm white LEDs on one lamp were stuck permanently on. I suspected voltage spikes, so I added zener diodes to shunt anything over 24 V to ground, and some small ceramic capacitors to ground for good measure. A few weeks later the replacement MOSFET failed in exactly the same way. This time, when I fitted a new one, I made sure to clean off every trace of flux. I think the leftover flux was bridging the contacts and slowly killing them. Fingers crossed that’s finally fixed it.
Where it stands
The config reached its current shape this month: three bedroom lights on Thread, controlled from the wall switches and from Home Assistant. Thread itself has been perfect. It’s really neat that ESPHome over Thread just works, with no fuss at all.