Setting up Thread on a ZBT-1 with HA Container

Intro

If you run Home Assistant in Docker (not HAOS or Supervised), setting up a Thread border router is significantly less documented than the add-on based approach. I figured these steps out via a lot of trial and error, so I hope this helps someone!

I got a SONOFF Zigbee Dongle Plus MG24 with the intent to use it as my thread router and keep my ZBT-1 for zigbee. In the end, I migrated my zigbee network over to the SONOFF dongle and converted the ZBT-1 to thread, so this guide will be specific to the ZBT-1.


Step 0: Migrate Zigbee network

Before setting up my ZBT-1 as my thread router, I had to migrate my ZHA network over to my SONOFF dongle. There are plenty of good official guides on how to do that, just bears noting. It's important that the HA docker container no longer claims the ZBT-1 device, so it can be used by our thread router container.


Step 1: Flash SkyConnect to OpenThread RCP firmware

The SkyConnect ships with Zigbee firmware. You need to reflash it to OpenThread RCP. The easiest way is the NabuCasa web flasher (The addon/in HA options will not work for HA Container). Plug the SkyConnect directly into a computer with a Chrome-based browser and visit:

https://skyconnect.home-assistant.io/firmware-update

Select the Thread / OpenThread RCP option and flash.


Step 2: Identify your device paths

With your ZBT-1 plugged in, find it's device path:

ls -la /dev/serial/by-id/

The SkyConnect shows up as a Silicon_Labs_CP2102N device (not with a NabuCasa name).
Something like:
usb-Silicon_Labs_CP2102N_xxxx-if00-port0

Also identify your host's primary network interface:

ip link show

You'll need the interface name, probably something like: eth0, enp60s0 or eno1


Step 3: Add your user to the dialout group

Required for serial port access:

sudo usermod -a -G dialout $USER

Log out and back in for it to take effect.


Step 4: Docker Compose configuration

Add this neat container that runs the HA Open Thread Border Router (OTBR) addon as a standalone docker container (I never got the official OTBR container to work):

otbr:
  image: denniswitt/homeassistant-otbr:latest
  container_name: otbr
  restart: unless-stopped
  privileged: true
  network_mode: host
  environment:
    - DEVICE=/dev/ttyUSB0
    - BAUDRATE=460800        # OpenThread RCP firmware uses 460800
    - BACKBONE_IF=eth0       # Replace with your actual interface name
    - FLOW_CONTROL=1         # Required for SkyConnect
  devices:
    - /dev/serial/by-id/usb-Silicon_Labs_CP2102N_xxxx-if00-port0:/dev/ttyUSB0
  volumes:
    - /var/lib/thread:/var/lib/thread  # Persist Thread network data across restarts

Important notes:

  • BAUDRATE=460800 — the NabuCasa web flasher installs firmware at this baud rate, not 115200
  • FLOW_CONTROL=1 — the SkyConnect requires hardware flow control
  • BACKBONE_IF must match your actual host interface name, not eth0
  • The AUTOFLASH_FIRMWARE variable shown in some documentation does not exist in this image despite appearing on Docker Hub — flash the firmware manually as described in Step 1
  • Port 8081 must be free on your host — this is what the OTBR agent binds to internally regardless of OTBR_REST_PORT. If something else is using 8081, move it
  • The migration script that runs on container startup will always show a TimeoutError — this is harmless and can be ignored. The agent starts successfully afterward

Step 5: Add integrations in HA

Once the container is running, in HA go to Settings → Devices & Services → Add Integration:

  1. If the Thread integration shows up automatically, ignore it for now
  2. Add OpenThread Border Router first, pointing at http://localhost:8081

Step 6: Android — sync Thread credentials

This step was a tricky one. On Android, Matter commissioning routes Thread credentials through Google Play Services. Your phone needs to know about your Thread network before it can commission Thread devices.

After setting up the OTBR and Thread integrations, open the HA companion app and go to:

Settings → Companion App → TroubleShooting → Sync Thread Credentials

Sync the credentials to your phone. You can verify it worked by going to your phone's
Settings → Search 'thread' → Thread Networks
Your network should appear without a crossed-out key icon.

On iOS this step is not required as the HA app handles credential sharing differently.


Step 7: Commission your Thread devices

With credentials synced, go to Settings → Devices & Services → Add Integration → Matter in the HA companion app and scan your device's QR code. BLE must be enabled on your phone and you should be within ~1 metre of the device during commissioning.


Troubleshooting

  • Container crashes with "No such device" for eth0 → your BACKBONE_IF is wrong, check ip link show
  • Migration script TimeoutError on every start → harmless, ignore it
  • "Your device requires a Thread border router" on Android → you haven't synced credentials to your phone yet (Step 6)
  • "Unavailable" with crossed-out key in Android Thread settings → same as above
  • Port 8081 conflict → something else on your host is using 8081, move it

Great tutorial, thanks! I had to run step 3 first, reboot, and then go on.

Interesting! I didn't have to reboot but I'll add that in :slightly_smiling_face:
Oh, nevermind, I can't actually update it because the post is a wiki, and I don't yet have permissions to edit those haha