Mesh Mastery
ESPHome makes it easy to create your own smart-home devices that seamlessly integrate with Home Assistant. We show you how to use ESPHome with a Thread network.
With an ESP32 development board, you can create your own smart-home devices by connecting sensors, LEDs, buttons, and other electronic components. You can program the ESP32 using open source platforms such as Arduino, MicroPython, or ESPHome. ESPHome, which I’ve covered in an earlier Linux Magazine article and wrote a book about, is particularly interesting, as it supports the native API of Home Assistant. This allows for an easy and efficient integration with this popular open source smart-home gateway solution.
If you’re developing a smart-home device with an ESP32, this normally works over WiFi. However, your WiFi network at home might already be quite busy. Fortunately, alternatives to WiFi exist. Thread is one such option: Thread is a wireless mesh network optimized for battery-operated devices with low bandwidth requirements. This is perfect for temperature sensors, buttons, and more. See also Building Wireless Sensor Networks with OpenThread.
As of version 2025.6, ESPHome also supports communicating with Home Assistant over a Thread network. In this article, I’ll illustrate this from the ground up: You’ll set up your own Thread Border Router, connect it to Home Assistant, and create ESPHome devices with sensors, LEDs, and buttons operating over your Thread network.
I assume that you’ve already installed Home Assistant. If not, you can find setup instructions on the project’s website. I have used the Home Assistant Operating System (HA OS) installation type on a Raspberry Pi 4 for this article, and I haven’t tested other installation types; they might work, but probably require some minimal changes to the approach explained in this article.
Thread Border Router
First, you need a Thread Border Router. This device enables communication between your Thread network and the rest of your local (WiFi and/or Ethernet) network. You might already have a Border Router at home, such as an Apple HomePod mini or a Google Nest Wifi Pro. Alternatively, you can create an OpenThread Border Router with a Raspberry Pi and an nRF52840 Dongle, or an Espressif Thread Border Router using an Espressif development board with an ESP32-S3 (for WiFi) and an ESP32-H2 (for Thread).
For this test, I opted for the OpenThread Border Router add-on in Home Assistant, in combination with the Home Assistant Connect ZBT-1 dongle, formerly known as Home Assistant SkyConnect. It contains a radio chip that supports both Thread and Zigbee. At the time of writing, there was some talk about a second generation of this dongle coming out soon, which may have been released by the time you’re reading this. Connect the dongle via a USB extension cable to the computer running Home Assistant (Figure 1), preferably to a USB 2.0 port to minimize interference (see the “Interference with USB 3.0” box).

USB 3.0 ports generate radio noise in the 2.4GHz frequency band in which Thread operates. Plugging your Thread dongle directly into a USB 3.0 port (recognizable by the blue interior) of your Raspberry Pi or other computer may cause signal quality issues with your Thread network. Use a USB 2.0 port if possible, and keep the dongle away from USB 3.0 devices. By connecting the dongle via a USB extension cable, you can place it at a distance. USB 3.0 also impacts other radio technologies operating at 2.4GHz, such as WiFi, Bluetooth, and Zigbee. You can find more technical information in an Intel white paper.
OpenThread Border Router Add-On
Navigate to Home Assistant’s settings under Devices & services, and you will find your newly discovered dongle under the Integrations tab. Click on Add next to it. You’ll then be asked whether to set up a Zigbee or a Thread network with it. The dongle supports both wireless protocols, and your choice determines which firmware will be flashed onto the device. Choose Thread and wait a few minutes. Home Assistant will first install the OpenThread Border Router add-on and then flash the appropriate firmware onto your dongle. After this, you can assign a room to your border router. This is optional and not necessary for your Thread network.
Your configured integrations now have two new additions: Home Assistant Connect ZBT-1 and Open Thread Border Router. You’ll also see a new discovered integration: Thread. Click Add here and confirm you want to set up the integration. No extra choices are needed, as the integration automatically uses the installed border router. If you then click on Thread in the configured integrations and subsequently on the gear icon under the configured service, you’ll see a network with one border router. Click the info icon next to it to view the network properties, which you’ll use later to connect your ESPHome devices to this network.
ESP32 Boards with Thread
To communicate over a Thread network, you need a specific radio chip that implements the IEEE 802.15.4 link layer of the network. In the Home Assistant Connect ZBT-1, that chip is the Silicon Labs EFR32MG21. Typical ESP32 development boards do not support Thread, but the ESP32-C6 and ESP32-H2 do. The ESP32-C6 also supports WiFi 6. For battery-powered applications, the ESP32-H2 is more suitable because WiFi consumes more power. For this article, however, this makes little difference because ESPHome does not yet support Thread’s low-power functionality. I tested this setup with two different development boards, both with an ESP32-H2 (Figure 2):
- The ESP32-H2-DEV-KIT-N4 from Waveshare measures 51.6mm by 25.4mm, with two rows of 15 pins, a WS2812B RGB LED, and a USB-C port. You can purchase it with or without soldered pin headers.
- The Super Mini ESP32-H2 from Shenzhen Hongwei Microelectronics is a small board measuring 23.5mm by 18mm, with two rows of nine pins, a blue LED, a WS2812 RGB LED, and a USB-C port. It comes with pin headers you need to solder yourself.

Installing ESPHome
When your Thread network is ready and you have suitable ESP32 boards, it’s time to install ESPHome to program them. ESPHome consists of two components: the firmware that gets installed onto the ESP32 and the system that runs on a computer to build the firmware based on a device configuration. This second component can run on your own computer, but for this article I chose the easily installable add-on ESPHome Device Builder for Home Assistant.
In Home Assistant’s settings, click Add-ons and then the blue Add-on store button at the bottom right. Select ESPHome Device Builder in the ESPHome category and click Install. Once the installation is complete, enable Show in sidebar, click Start, and then Open web UI (Figure 3). ESPHome’s web interface is now accessible with a click on ESPHome Builder in Home Assistant’s left sidebar.

Creating a Board Configuration
Click New Device at the bottom right of the ESPHome web interface to create a new device configuration. You will first be instructed on how to install the ESPHome firmware on your board. Click Continue. Name your configuration and enter your WiFi network name and password. Even for an ESP32-H2 without WiFi, you must enter a WiFi network, as the ESPHome Web Builder has not yet been adapted for this case.
In the next step, select the device type. The ESP32-C6 is listed, but at the moment of writing the ESP32-H2 is not. Choose the first option then. In both cases, click Skip and then click Edit on the created configuration. You will now see the YAML code of your device’s ESPHome configuration. If you use an ESP32-H2, change the board type from esp32-c6-devkitc-1 to esp32-h2-devkitm-1 and remove the entire wifi section (including ssid and password, as well as ap with its ssid and password) and captive_portal, as the ESP32-H2 does not have WiFi. For the ESP32-C6, you can leave all settings as they are. Click Save.
Thread Configuration
Your ESPHome device currently has no network, which is indicated by red scribbles under some configuration items. You need to add the device to your Thread network. First, return to Settings | Devices & services, and click on Thread, the gear icon, and the info icon next to your preferred network. Behind Active dataset TLVs, you will see a long string of hexadecimal characters. Copy this string and make sure to include all the characters. Then return to ESPHome Builder in Home Assistant’s left sidebar and click Edit on your ESPHome device. Add the following YAML code where wifi was earlier:
network:
enable_ipv6: true
openthread:
tlv: LONG_TLV
Replace LONG_TLV with the long string of hexadecimal characters. These encode the network settings, such as the channel, network name, and encryption key, enabling the device to join the Thread network. Click Save and then Install. Now connect your ESP32 board to your computer running Home Assistant. See the “Manually Installing Firmware” box if this is difficult, such as when Home Assistant is running on a Raspberry Pi in your basement or attic.
If it’s inconvenient to connect your ESP32 board to your Home Assistant computer via USB because it’s in a hard-to-reach place, choose the Manual download installation option. The compiled firmware image will be offered to download. Select the Factory format version. Open ESPHome Web in Google Chrome or Microsoft Edge, as you need a web browser that supports WebSerial. Connect your ESP32 board to your computer, click Connect, choose the correct serial port from the list (in my case, USB JTAG/serial debug unit), and click Connect. Then click Install, choose the bin file downloaded from the ESPHome Builder, and click Install. This will show a progress bar, as shown in Figure 4.

As soon as the ESP32 board is connected to the computer running Home Assistant, choose Plug into the computer running ESPHome Device Builder in the offered list of installation options. Select a serial port. For the ESP32-H2-DEV-KIT-N4, there will be two ports, described as USB JTAG/serial debug unit and USB Single Serial: pick the first option.
ESPHome now translates the device’s YAML code to C++ and compiles it into a firmware image. This may take some time, particularly if this is your first ESPHome device, as the builder then needs to download and install all the necessary frameworks and software libraries. Compiling the firmware itself also takes a while the first time. If everything goes well, you will ultimately see a few green messages: INFO Successfully compiled program, followed by INFO Successfully uploaded program, and finally INFO Starting log output from /dev/ttyACM0 with baud rate 115200. Click Stop to abort the log output and close the edit window with the YAML code.
ESPHome Integration
Your ESPHome device should now show up as ONLINE in ESPHome Builder, indicating that the connection with Home Assistant using the Home Assistant API over the Thread network is functioning. From now on, you can also wirelessly update the device firmware over the Thread network which, due to its low bandwidth, can take a few minutes. To do this, choose Wirelessly under Install. You can also view the logs wirelessly (Figure 5), so the board no longer needs to remain connected via USB to your Home Assistant computer.

To use your Thread device in Home Assistant, go to Settings | Devices & services. In the Integrations tab, your ESPHome device should appear under the Discovered heading. Click Add and confirm with Submit, optionally assigning a room to the device, and click Finish. If everything goes well, you can now view device information such as the firmware version and MAC address. For now, the device only has one entity for firmware updates, which is disabled by default. But now you can further configure the board with ESPHome, and for each new functionality, additional entities will automatically appear in Home Assistant.
Controlling an LED
The ESP32 board is now ready for further configuration in ESPHome. Click Edit in ESPHome Builder under the device name to add code. You’ll need some documentation for your specific board to find out what components it has and which pins they are connected to. Note that the green LED on the Super Mini ESP32-H2 flashes constantly when no battery is attached, which is irritating and cannot be adjusted via software.
On the opposite side of the USB-C connector, the board has a blue LED that can be controlled through your code using pin GPIO13. To get this capability, add an output for pin 13 in the ESPHome configuration, along with a light referring to that output, as shown in Listing 1. The Waveshare ESP32-H2-DEV-KIT-N4 does not have a controllable LED, but you can attach one to a GPIO pin with a current-limiting resistor of 220ohms in series, and then use the same ESPHome code with the pin number correspondingly changed.
Listing 1: Configuring the Blue LED on the Super Mini ESP32-H2
01 output:
02 ‑ platform: gpio
03 pin: 13
04 id: blue_led
05
06 light:
07 ‑ platform: binary
08 name: "Blue LED"
09 output: blue_led
Save this configuration and install it on the ESP32 board by clicking Install in the top right and then Wirelessly. The code will be compiled and sent to the ESP32 as an OTA update over the Thread network.
Once the new firmware is installed on your ESP32, Home Assistant recognizes the LED. Click on Devices & services in the settings, then on ESPHome in the configured integrations, and subsequently your device. You’ll now see your Blue LED in the Controls section (Figure 6), which you can toggle on and off, with the board’s blue LED responding immediately.

Controlling an RGB LED
The Super Mini ESP32-H2 board has a WS2812 RGB LED between the BOOT and RESET buttons, connected to GPIO8. The Waveshare ESP32-H2-DEV-KIT-N4 also has such an RGB LED (in its WS2812B variant), located between the USB-C connector and the RESET button, connected to the same GPIO. You can configure these in ESPHome similarly as you did for the blue LED. This requires the code from Listing 2.
Listing 2: Configuring the RGB LED on both ESP32-H2 Development Boards
01 light:
02 ‑ platform: esp32_rmt_led_strip
03 rgb_order: GRB
04 pin: 8
05 num_leds: 1
06 chipset: ws2812
07 name: "RGB LED"
For the Waveshare ESP32-H2-DEV-KIT-N4, change rgb_order to RGB. If you also keep the configuration for the blue LED, ensure you don’t define light twice, but place both LEDs under one light key in the YAML file. Note that the commonly used neopixelbus platform doesn’t work here, because ESPHome’s OpenThread implementation currently only builds upon ESP-IDF, not upon the Arduino framework, and NeoPixelBus is only available for the latter.
Save your changes and update the board’s firmware. Once done, your device in Home Assistant will also include an entity for the RGB LED, where you can set it to display all possible colors (Figure 7).

Connecting a Button
Because ESPHome’s OpenThread support is still new, specific components that work on the regular ESP32s may cause problems. However, the technology is already quite usable. For example, you can connect a button and let Home Assistant know via the Thread network whether it is on or off. I’ll demonstrate how to do this with the Waveshare ESP32-H2-DEV-KIT-N4.
Place the development board onto a breadboard. If you look up the ESP32-H2-DEV-KIT-N4 pinout in Waveshare’s wiki, you will find the positions of GND, 3V3 and the GPIOs. Connect GND to the blue (-) rail of the breadboard and 3V3 to the red (+) rail. Place a button across the middle groove of the breadboard with its legs on either side. Connect one leg to the GND rail, and connect the other leg through a 10kOhm pull-up resistor to the 3.3V rail. Finally, connect GPIO4 to the button’s leg that is connected to the resistor (Figure 8).

Configuring the Button in ESPHome
Now that the hardware is ready, add the code from Listing 3 to your ESPHome configuration for the board. The filter is used for debouncing: Button contacts can open and close multiple times rapidly when pressed or released before staying in a stable position. To avoid multiple on and off signals, I’ve configured ESPHome to only pass on the state when the button remains pressed for more than 20ms.
Listing 3: ESPHome Configuration for a Button with Debouncing
01 binary_sensor:
02 ‑ platform: gpio
03 pin:
04 number: 4
05 inverted: true
06 name: "Button"
07 filters:
08 ‑ delayed_on: 20ms
Note also that the pin is configured as inverted. When the button is not pressed, there is no connection between its left and right legs. In that situation, GPIO4 is connected via the resistor to 3.3V. Once the button is pressed, GPIO4 connects to GND. By default, ESPHome considers 3.3V as on and GND as off, and the inverted: true addition inverts this behavior.
Save the configuration and install the updated firmware. Then, in Home Assistant, you’ll see the button state appear. Responses over the Thread network when pressing or releasing the button are immediate.
Adding a Motion Sensor
Similarly, you can connect a motion sensor, for example, a passive infrared (PIR) sensor. I’ll demonstrate this with the AM312, which has three pins: VIN connected to the 3.3V rail of the breadboard, GND to GND, and OUT to GPIO4 of the ESP32 (Figure 9). A PIR sensor measures the infrared light emitted by objects (such as people). When there’s a sudden change, the sensor puts a voltage of 3.3V on its output pin. Reading this voltage on the ESP32’s GPIO4 pin allows you to detect motion.

The ESPHome configuration (Listing 4) is almost identical to that for the button. The filter isn’t needed here as the sensor board already has a built-in delay. Some PIR sensors let you adjust this delay or sensitivity with a potentiometer. With device_class: motion, you inform Home Assistant that it’s a motion sensor, so it displays the sensor status with a walking person icon on the dashboard. After saving the configuration and installing the firmware, your ESP32-H2 board will send notifications to Home Assistant over the Thread network whenever it detects motion.
Listing 4: ESPHome Configuration for a PIR Sensor
01 binary_sensor:
02 ‑ platform: gpio
03 pin: 4
04 name: "Motion"
05 device_class: motion
Conclusion
Thanks to ESPHome’s recent support of OpenThread, you can now build your own Thread devices for your smart home without prior experience in embedded development. (For information on setting up a mesh network, see the “Achieving a Reliable Mesh Network” box.) The integration with Home Assistant is flawless, but it would be interesting if there was another method than the Home Assistant API to communicate with the devices. Also, be aware that OpenThread support in ESPHome is still experimental. For example, an I2C sensor (the BME280 temperature/pressure/humidity sensor) didn’t work during my initial test with ESPHome 2025.6, but when I revisited it two months later, the issue was fixed in ESPHome 2025.8. Other problems will likely be resolved as well as time progresses.
Thread is a mesh network, which means that Thread devices communicate with each other directly or mediated through another device in a peer-to-peer fashion (Figure 10). The Border Router isn’t a central gateway, but only serves for communication with the rest of your network. While the direct range of Thread is limited, Thread devices can communicate over longer distances as nearby Thread devices forward their network packets. Devices that do so are called Routers and are powered on continuously. Battery-operated devices that sleep do not forward packets and are called End Devices. The Thread network automatically decides which devices become Routers based on what is needed. Devices with this capability are called Full Thread Devices (FTD). ESPHome defaults your board to the FTD device type. Set
device_type: MTD (Minimum Thread Device) in the OpenThread configuration of your device’s YAML file to disable this. To ensure a reliable network, place enough FTDs around your home.