Adding Matter support to my homelab

Recently, Ikea switched from using Zigbee to using Matter Over Thread for their smart home devices. I only realised this when I bought a smart sensor only to find out it wouldn't work with my current setup.

I could've just decided to no longer use Ikea devices and stick to Zigbee, but Ikea's smart home devices are relatively cheap and easily accessible so instead I decided to just add Matter Over Thread to my Homelab.

Zigbee VS Matter Over Thread

I've done some research into this and honestly it mostly boils down to business. Generally Zigbee and Matter Over Thread work the same. It's mainly that where Zigbee is a complete stack (Protocol and Application), Matter Over Thread uses two layers: Thread as the Protocol and Matter as the Application.

This is just something big brands like Apple, Google and Amazon have agreed upon to all use the same way, meaning products like the Nest Hub or HomePod already use Thread.

I didn't have any device that already has Thread, and fuck big tech? So I DIY-ed my own Thread Border Router.

Hardware installation

Since I didn't want to depend on 3rd parties again, like I used to with Philips Hue, I decided to make my own Thread Border Router to get Matter Over Thread working.

This guide was pretty useful for me to figure out the parts I needed:

  • An ESP32-C6 or ESP32-H2 board. I went with the Seeed Studio XIAO ESP32-C6.
  • An external U.FL antenna on the 2.4 GHz band. I got this one.
  • A USB-C to USB-A cable that can transfer data, which I already had laying around.

I decided to 3d print a little case for it, mainly so I had something to screw the antenna into.

The guide gave me the OpenThread RCP firmware to flash onto the esp32, which was easy to do using the esphome web interface.

From then on I had to deviate from the guide as I have a barebones install of HomeAssistant on my homelab which works a little differently.

Software installation

After plugging in the flashed esp32 into my homelab I had to install some additional software.

OpenThread Border Router (OTBR)

OTBR is what connects a Thread network to other IP-based networks, like Wi-Fi and Ethernet. This is what uses the ESP32 which acts as a radio.

To get this going I had some AI help, which is why I am documenting all this.

The docker-compose piece:

otbr:
image: ghcr.io/ownbee/hass-otbr-docker:latest
container_name: otbr
network_mode: host # Needed because OTBR needs to interact with LAN
privileged: true # OTBR needs to control router and firewall rules
restart: unless-stopped
devices: # Points to the ESP32 device and controls it
- source: /dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_XX:XX:XX:XX:XX:XX-if00
target: /dev/ttyOTBR
permissions: rwm
- source: /dev/net/tun
target: /dev/net/tun
permissions: rwm
volumes:
- ./otbr:/data/thread
environment:
DEVICE: /dev/ttyOTBR # Points to device
BAUDRATE: 460800 # Sets serial speed
FLOW_CONTROL: 0 # Hardware flow control?
AUTOFLASH_FIRMWARE: 0 # Auto flashes firmware, not needed so off
BACKBONE_IF: enp1s0 # The LAN interface used
OTBR_REST_PORT: 8082 # The REST API used for HA, originally 8081 which was already in use by another service.
OTBR_WEB_PORT: 8099 # The port for the webUI
FIREWALL: 1 # OTBR creates its own rules for what can enter the Thread network from the outside.
NAT64: 1 # Thread devices only speak IPv6, NAT64 translates it so they can reach IPv4-only services.

And then I had to turn my server into a router of sorts, which uses the ESP32 as the antenna. With the following command I made it so my server passes along packets from the Thread network to my LAN and vice versa:

echo -e "net.ipv6.conf.all.forwarding=1\nnet.ipv4.conf.all.forwarding=1\nnet.ipv6.conf.enp1s0.accept_ra=2" | sudo tee /etc/sysctl.d/60-otbr.conf
sudo sysctl --system

which writes:

net.ipv6.conf.all.forwarding=1     # Lets the server pass IPv6 packets bewteen the Thread network and LAN network.
net.ipv4.conf.all.forwarding=1 # Needed for NAT64.
net.ipv6.conf.enp1s0.accept_ra=2 # Work around side effects of forwarding

to /etc/sysctl.d/60-otbr.conf and then applies it right away using sudo sysctl --system without needing a reboot.

Then I started the service using docker compose up -d otbr.

In HomeAssistant I then added the Open Thread Border Router integration, where I entered the URL to the REST API for OTBR: http://127.0.0.1:8082

Then I also installed the Thread integration, which found the correct network right away.

On my phone, I opened the HomeAssistant Companion app and navigated to Settings > Companion app > Troubleshooting > Sync Thread credentials

Matter-server

With OTBR the Protocol layer is taken care of. The following is for Matter, the Application layer.

In docker compose:

matter-server:
image: ghcr.io/matter-js/matterjs-server:stable
container_name: matter-server
network_mode: host
restart: unless-stopped
environment:
PRIMARY_INTERFACE: enp1s0 # Prevent it from picking up docker bridges or tailscale
volumes:
- ./matter-server:/data

And then another sysctl command:

echo "net.ipv6.conf.enp1s0.accept_ra_rt_info_max_plen=64" | sudo tee -a /etc/sysctl.d/60-otbr.conf
sudo sysctl --system | grep max_plen

Which lets the host accept IPv6 route announcements for the Thread network's address range. Currently not essential but useful when adding more border routers such as Apple TV or Nest Hub.

Then I ran the service using docker compose up -d matter-server.

In HomeAssistant I added the Matter integration, where I entered the URL for the matter server: ws://localhost:5580/ws

Linking devices

Once everything was installed and ready, linking devices was pretty easy. I used my phone to navigate to Settings > Devices & Services > Add device > Add Matter device. It gave me the option to scan a QR code but this didn't work in my case. Instead I used the link code on the Matter device which worked instantly.

How the pairing works:

  1. My phone talks to the new device over Bluetooth
  2. My phone gives the device the Thread credentials (Which is why I had to sync credentials earlier) so it can join the mesh through the ESP32.
  3. When the device is on the network, HA's Matter Server takes over the controls and the Bluetooth connection is no longer needed.

And that's it! I am now able to use Matter devices in my home without trouble.

I really didn't need to do this but YOLO.