Thread is a mesh networking stack running on 6LoWPAN (IPv6 over Low-Power Wireless Personal Area Networks) over IEEE 802.15.4 radios. To connect to the broader network, a Thread Border Router is required, which acts as a gateway between the Thread mesh radio network and upstream networks.

Thread, especially when used with Matter, is an important development for home automation, however the technologies also have commercial applications. The initial commercial focus of Thread is for smart buildings.

The networking layer sits between the underlying physical network, and the application layers on top.

Thread layers: UDP, IP Routing, 6LowPAN, and cross-cutting Security/Commissioning, with non-Thread layers beow IEEE 802.15.4 MAC and IEEE 802.15.4 PHY, and non-Thread applications layer above

Matter is an application protocol for device automation that runs on top of Thread (and also WiFi), with Bluetooth used for device commissioning. Matter 1.0 was also released in October 2022 and is supported by major home automation vendors (Google, Amazon, Apple, and Samsung), but can also be used in commerical deployments.

When provisioning a Matter device to a Thread mesh, Bluetooth is used for the initial provisioning and sets up both the connection the the Thread mesh and registration in the Matter Hub. One important aspect of Matter is multi-admin, allowing one device to be controlled by multiple hubs.

The layered approach means Thread can be used by itself, providing mesh networking for smart buildings using other protocols, or in conjunction with Matter.

The article also looks at setting up a OpenThread Border Router for testing, and shows provisions a Matter test device to the Thread mesh.

Thread for smart buildings

Thread can be used as the core network for smart building management.

A typical smart building topology includes long life battery end devices, powered mesh extenders (such as smart lighting), and border routers for network connectivity, all running IPv6 and able to interoperate with other IP-based WiFi and network systems, including building management.

Thread Smart Building topology, complex diagram showing possible deployment of Thread border routers, mesh extenders, and battery devices, connected to other network devices

The benefits of using Thread for a smart building include great support for low powered devices, easier installation and wireless technology, as self-configuring and self-healing mesh network, and end-to-end connectivity with broader IP based networks.

Thread is used as the IP network mesh technology for several smart building protocols such as OCF / Cascoda, KNX IoT, DALI+, and BACnet.

In particular the Open Connectivity Foundation (OCF) has published specifications and an open-source reference implementation, including mappings to LwM2M (Lightweight M2M), OneM2M, and other platforms.

There are also providers, such as WideSky, that use Thread as the underlying network for some of their commerical products.

For more information on Thread in commercial environments see the whitepapers at https://www.threadgroup.org/support

Thread testing hardware

You can set up a test Thread Border Router on a Raspberry Pi, with a Thread radio dongle, using the OpenThread software, and then commission a Matter application device on top of it.

The hardware I used included:

  • Raspberry Pi (I used a RPi 4).
  • SD Card writer (to generate the RPi image).
  • nRF52840 USB Dongle from MakerDiary (the Thread radio co-processor we plug into the RPi)
  • Nordic Thingy:53 (Thread device to connect to the mesh)
  • Laptop, to build and load the firmware onto the Thread radio dongle and Thingy:53.
  • Android phone, to run the the Matter commissioning app

Thread hardware, showing packaging boxes for the Nordic Thingy:53 and nRF52840 MDK USB Dongle

The OpenThread source code is available at https://github.com/openthread — although sometimes the examples might be old or for a slightly different device (e.g. the MakerDiary dongle has a different flashing process than the Nordic Semiconductor dongle).

Preparing the Thread radio dongle

The OpenThread Border Router users a Radio Co-Processor (RCP) design, where the majority of the Thread networking stack is running on the Raspberry Pi (which has more computing power, and is easier to change), and the USB dongle is running just the radio (similar to plugging in a WiFi dongle).

Another architecture used in earlier versions of OpenThread was a Network Co-Processor (NCP) design, where most of the network stack runs on the nRF52840 chip. This design is useful for end devices to offload most of the network processing, where the main system is also low-powered, but no longer used for the border router.

Update the Radio Co-Processor firmware

In this example we are using the MakerDiary nRF52840 USB Dongle

The MakerDiary dongle came pre-loaded with the older NCP firmware, so first I needed to update it to the latest version with the RCP firmware. This required fetching the source and building on a laptop, then flashing the dongle.

The dongle uses the UF2 bootloader, so you first need to get the conversion tool from the MakerDiary repository:

git clone https://github.com/makerdiary/nrf52840-mdk-usb-dongle.git

Then clone the latest nRF52840 firmware from the OpenThread repository, build it, and convert to a HEX file.

git clone --recursive https://github.com/openthread/ot-nrf528xx
cd ot-nrf528xx
git submodule update --init

./script/bootstrap
./script/build nrf52840 USB_trans -DOT_BOOTLOADER=USB CFLAGS+=-UCONFIG_GPIO_AS_PINRESET

cd build/bin
arm-none-eabi-objcopy -O ihex ot-rcp ot-rcp.hex

The MakerDiary tool can then convert the HEX file to UF2 format.

python ../../../nrf52840-mdk-usb-dongle/tools/uf2conv.py ot-rcp.hex -c -f 0xADA52840 -o ot-rcp-flash.uf2

Flashing with UF2 is very easy, as the dongle just appears as a regular USB drive, and you simply copy the UF2 file into the drive.

To put the dongle into flash mode double-tap the reset button. (For the initial version of the firmware you could also hold down the reset button whilst plugging in the drive, but that stopped working after the first update and I could not update until I discovered the double-tap method).

Once the nRF52840 Radio Co-Processor is ready, you can prepare the Raspberry Pi.

Note on the Nordic Semiconductor tools

Nordic Semiconductor have a newer SDK and toolset, which I used for the Thingy:53 (see below), but could not get working with the MakerDiary dongle.

For consistency with the OpenThread border router, I suggest using the base OpenThread version of the RCP, to ensure the protocol versions are synchronised.

Nordic Semiconductor does have their own branch of the OpenThread code in their SDK, with some optimisations for their hardware, but I just ended up with what appeared to be version issues, and went back to the base OpenThread source.

Prepare the Raspberry Pi with OpenThread Border Router

You will need an operating system installed on the RPi, and can use the base Pi OS:

  • Use the RPi burner tool
  • Select Lite 64-bit
  • Advanced configuration set the server name (default is 'raspberrypi') and SSH username (default 'pi') and password, allowing headless setup of the RPi (no keyboard or monitor required)
  • Write to SD card

Using ethernet for the upstream connection is recommended, but if you are using WiFi for the upstream connection, you also need to configure Wifi.

Insert the SD Card, connect the network cable, and power on the RPi.

Once booted you can use SSH to connect to the RPi, e.g. ssh pi@raspberrypi. If the name is not resolved, you may need to check your router or use a tool like nmap to find the IP address and then connect to that, e.g. ssh pi@fd7c:e25e:67e8:40::7

I also used my router to configure static DHCP lease addresses for the RPi, for convenience.

Install OpenThread Border Router

On the Raspberry Pi, you need to install git to fetch the code (I also installed dnsutils for troubleshooting):

sudo apt install git dnsutils

Follow the instructions to download the code and the run the bootstrap, which will download all the necessary dependencies, packages and tools (may take a while).

git clone https://github.com/openthread/ot-br-posix.git --depth 1
cd ot-br-posix
./script/bootstrap

Finally, run the OTBR setup (eth0 is my LAN connection; you can also use WiFi). I also enabled the Web GUI for evaluation, although it has no security authentication so I would not recommend running it on a real system.

INFRA_IF_NAME=eth0 WEB_GUI=1 ./script/setup

After setup you can check no errors were reported on the screen, plug in the Radio Co-Processor dongle, and then reboot with sudo shutdown -r now

MakerDiary Thread Dongle in Raspberry Pi, the red and white Pi on a desk, showing the various ports, with USB-C power and RJ-45 ethernet connections, and a USB dongle sticking out the front

For additional details you can see the OpenThread examples: https://openthread.io/codelabs/openthread-border-router

Setting up an IPv6 prefix delegation request

My home router is running OpenWRT, and I get an IPv6 /56 allocation from my ISP, which I split into several /60 subnets, with downstream prefix delegation enabled.

This allows me to configure the Raspberry Pi to request a prefix delegation, which it can then assign to the Thread network, to provision global addresses to devices.

When setting this up, we turn off global IPv6 router solicitation, but for some reason the OTBR setup had also turned off IPv6 on the Raspberry Pi. I turned back on IPv6 and set up the ethernet interface to request one non-temporary address, plus one prefix delegation with 2 bits of subnet identifier to be used to assigned to wpan0.

At the end of /etc/dhcpcd.conf:

...
#noipv6
noipv6rs

# Set prefix delegation request and assign to wpan0
interface eth0
  ipv6rs
  ia_na 1
  ia_pd 2 wpan0/2

Restart the DHCP client with:

sudo service dhcpcd restart

This will request a /62 prefix delegation (from the /60 assigned to the LAN), and then assign /64 to the Thread network.

You can check the service logs to see the address and prefix assignments:

journalctl -u dhcpcd -S "5 minutes ago"

NOTE 1: On reboot the wpan0 interface is not yet available when DHCP requests addresses, so can't assign the prefix. To fix this I have to SSH to the RPi and restart the service after Thread has started, with sudo service dhcpcd restart.

Using OpenWRT as a Thread Border Router

OpenWRT itself can be enabled as a Thread Border Router, with a build of OpenThread configured to run in OpenWRT. Currently you need to build the package yourself, although an update is in progress to add it to the OpenWRT repository.

It includes a web interface for configuration, within the OpenWRT console, which has authentication and is much safer than the OpenThread Web GUI.

Testing the Thread border router

Checking the logs

You can check the logs of the OTBR Agent to see if it is working correctly.

journalctl -u otbr-agent -S "5 minutes ago"

Note that at this point a Thread network is not yet configured, so all we are checking is that the otbr-agent service running on the Raspberry Pi can connect to the Radio Co-Processor on the dongle.

Running OTBR in multiple windows for testing

If there are issues, you can test by stopping the service and then running it manually. To run manually first install something like tmux so that you can split your SSH shell and run both otbr-agent and ot-ctl.

sudo apt install tmux
tmux

In the first tmux pane:

/usr/sbin/otbr-agent -I wpan0 -B eth0 spinel+hdlc+uart:///dev/ttyACM0 trel://eth0 -v

Type CTRL+B then " to split the terminal, and in the bottom half you can use ot-ctl to check the status.

sudo ot-ctl state

Use CTRL+B then O to switch panes, and CTRL+B then X to exit.

Troubleshooting

  • Originally I had issues because the dongle was running a network co-processor (NCP), which is no longer supported in the Border Router (it was previously).
  • I also had issues with what appeared to be incompatible versions of Thread between the co-processor and router.

Errors included messages such as "Init() at radio_spinel_impl.hpp:268: RadioSpinelIncompatible" and "HandleRcpTimeout() at radio_spinel_impl.hpp:2243".

Preparing a Matter test device

For a test device I used the Nordic Thingy:53 running the Matter Weather Station application: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/applications/matter_weather_station/README.html

Nordic Semiconductor Thingy:53, 6cm grey box with Nordic logo, button, and light, with an open red flag and USB-C cord inserted

Install the Nordic SDK

This was built and deployed using the new Nordic nRF Connect SDK, following the installation guidelines https://nrfconnect.github.io/vscode-nrf-connect/connect/install.html:

  1. Download the command line tools (scroll down to find the download section), then right click and use installer to install. (or from command line)

  2. Download nRF Connect for Desktop, mark it executable to run it

Troubleshooting:

On Ubuntu 22.04 error missing libfuse2.so, so install it: https://techpiezo.com/linux/error-appimages-require-fuse-to-run-in-ubuntu-22-04/

Official documentation on this fix is here: https://docs.appimage.org/user-guide/troubleshooting/fuse.html#setting-up-fuse-2-x-alongside-of-fuse-3-x-on-recent-ubuntu-22-04-debian-and-their-derivatives

After the fix, nRF Connect for Desktop then runs.

  1. Use nRF Connect for Desktop to install Toolchain Manager

You can then click Open to run the Toolchain Manager. (Note that the VSCode installation page mentions libnettle (install worked) and libhogweed (didn't), https://nrfconnect.github.io/vscode-nrf-connect/connect/install.html)

  1. Use Toolchain Manager to install the latest version of the nRF Connect SDK, which was v2.1.0

This may take a while. Once installed, the button will change to 'Open VS Code'. Note: v2.1.1 came out while working on the sample.

  1. Use Toolchain Manager to open VS Code (I already had it installed), and add any missing extensions.

Troubleshooting

On the new project screen, the "nRF Connect Toolchain" was set to the ~/ncs/toolchains/v2.1.0 folder but underneath there was an error "Invalid toolchain installation. nrfjprog is required but not found. Make sure the "nrfjprog" executable is in your PATH."

Changing the value to "PATH (nRF Connect)" made even more errors (west, ninja, gperf, etc) appear.

Also, underneath Connected Devices was the error "nRF Command Line Tools are not installed".

The command line tools were installed. Doing a whereis nrfjprog returned /usr/local/bin/nrfjprog /opt/nrf-command-line-tools/bin/nrfjprog (with the first being an alias to the second).

Running nrfjprog worked, but nrfjprog --version gave an error for dlopen: libjlinkarm.so, and to reinstall JLinkARM from Segger.

To fix, I used the Segger download page, https://www.segger.com/downloads/jlink/, to download the "J-Link Software and Documentation Pack" and install with sudo dpkg -i JLink_Linux_<version>.deb

Building the weather station app

I created a new project, based on the Thingy:53 Matter Weatherstation, used the existing configuration files (rather than a new one), as build and build_release, and build them.

Based on the precompiled app ZIP file, the debug file to deploy is matter_weather_station/build/zephyr/dfu_application.zip

Loading the firmware uses the Programmer, launched from nRF Connect for Desktop. To put the Thingy:53 into programming mode you have to take off the cover and press button 2 (next to the main button) while turning the device on. I used a small Phillips head screwdriver, which has a kind of rounded tip -- there is a small click sound when the button is pressed.

Once restarted you can use screen /dev/ttyACM0 -b 115200 to monitor the debug output (CTRL+a then k to exit).

You can use screen -L /dev/ttyACM0 -b 115200 to also log the output, which will conains something similar to the following, including the device configuration (use the test parameters set in the source code), and the commissioning setup code. The log includes a URL that will display a QR Code you can use to provision the device.

[00:00:00.208,618] <inf> chip: [SVR]Server Listening...
[00:00:00.208,679] <inf> chip: [DL]Device Configuration:
[00:00:00.208,892] <inf> chip: [DL]  Serial Number: 11223344556677889900
[00:00:00.208,984] <inf> chip: [DL]  Vendor Id: 65521 (0xFFF1)
[00:00:00.209,075] <inf> chip: [DL]  Product Id: 32781 (0x800D)
[00:00:00.209,289] <inf> chip: [DL]  Hardware Version: 0
[00:00:00.209,533] <inf> chip: [DL]  Setup Pin Code (0 for UNKNOWN/ERROR): 20202021
[00:00:00.209,808] <inf> chip: [DL]  Setup Discriminator (0xFFFF for UNKNOWN/ERROR): 3840 (0xF00)
[00:00:00.210,021] <inf> chip: [DL]  Manufacturing Date: (not set)
[00:00:00.210,113] <inf> chip: [DL]  Device Type: 65535 (0xFFFF)
[00:00:00.210,510] <inf> chip: [SVR]SetupQRCode: [MT:M1TJ342C00KA0648G00]
[00:00:00.210,632] <inf> chip: [SVR]Copy/paste the below URL in a browser to see the QR Code:
[00:00:00.210,754] <inf> chip: [SVR]https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3AM1TJ342C00KA0648G00
[00:00:00.210,906] <inf> chip: [SVR]Manual pairing code: [34970112332]
[00:00:00.211,761] <inf> chip: [DL]CHIP task running
[00:00:00.215,515] <inf> chip: [DL]CHIPoBLE advertising started

Configuring the Thread Border Router

OpenThread has an optional web interface you can use, although it has no security so should only be installed for testing. If running, it can be accessed on the host device http://[your-rasperry-pi-name]/, e.g. http://[fd7c:e25e:67e8:40::7]/

You can use the OTBR web interface to Form a new network, enter the network name, Extended PAN ID, PAN ID, Passphrase, Network Key, and Channel. The current version also has a field called "On-Mesh Prefix", but it actually sets the Off-Mesh Routing (OMR) prefix. This field can also be set from the Settings page.

OpenThread Border Router web interface, showing the device status and IPv6 addresses

Command line configuration

To configure from the command line, SSH into the Raspberry Pi, then:

sudo ot-ctl dataset init new

Will initialise a new network with random values. To recreate the same network, set all of the values before committing (the same as setting them in the web UI, plus the meshlocalprefix). Example random values (you should use your own values):

sudo ot-ctl dataset networkname OpenThread-7ada
sudo ot-ctl dataset extpanid c4bbcca137abeb1c
sudo ot-ctl dataset panid 0x7ada
sudo ot-ctl dataset pskc 2dbd9144952331e489af173813e54d93
sudo ot-ctl dataset networkkey 2e1cd56f139a89be3d8f2fb66d4aee21
sudo ot-ctl dataset channel 19
sudo ot-ctl dataset meshlocalprefix fdc3:a988:d7fd:633::/64
sudo ot-ctl dataset commit active

For example, you could set up the meshlocalprefix to be a known ULA from your organisation. Do not use the actual values above.

Note: Setting networkname or extpanid invalidates the commissioning credential, and you need to reset pskc after changing these values.

You can also output the configuration as hex values, as a quick way to set the parameters:

sudo ot-ctl dataset active -x

i.e. the following with generate the same parameters as above

sudo ot-ctl dataset set active 0e080000000000010000000300001a35060004001fffe00208c994dad6571db3060708fd7ce25e67e8700105101022ecaa09c1a114f4b76863c4cdeb82030f4f70656e5468726561642d36386164010268ad0410f3b1dec3b980839c7c474c04a3caf84f0c0402a0f7f8

For more details on the command line interface see https://github.com/openthread/openthread/blob/main/src/cli/README.md

Setting the Off-Mesh Routing (OMR) prefix

The Off-Mesh Routing (OMR) prefix is the range that is exposed to the outside world (as opposed to the mesh local prefix, which is only used inside the mesh). These are the addresses that you can communicate with, e.g. ping. The default is a random ULA, which can only be used on the local network.

If you have a global address range which is routed (e.g. prefix delegation) to the border router, you can configure to use that. This should be automatic, but I found in practice it was not set up to trigger automatically.

i.e. When the prefix delegation is obtained, the regular networking side works (i.e. it is assigned to the wpan0 interface, and the upstream router knows about the route), however the Thread network Off-Mesh Routing address is not updated (it has the default random value), so end devices do not have corresponding global addresses.

To fix this, assign the relevant prefix to the Thread network, e.g.:

sudo ot-ctl prefix add 2407:8800:bc61:1346::/64 paros med
sudo ot-ctl netdata register
sudo ot-ctl netdata show

Starting the network

Start the OTBR interface, and then start Thread:

sudo ot-ctl ifconfig up
sudo ot-ctl thread start
sudo ot-ctl state

Checking with the Thread commissioning tool

The Thread 1.1 Commissioning App on Android, from the Thread Group, can be used to scan for Thread networks and detect if you border router is up and running.

OpenThread Border Router in Android Thread tool, showing the available border routers

Commissioning the Matter device over the Thread network

With the Thread network setup, and the Matter device prepared you need to commission the device using CHIPTool (or another commissioning service). This will configure the device for both Matter and join it to the Thread network.

CHIP is based on the old name of Thread, "Connected Home over IP".

You can build the Android app yourself, or there is a pre-built version you can download from earlier versions of the Nordic nRF Connect SDK (but not the latest version).

Run CHIPTool and select Provision CHIP Device with Thread, scan the QR Code (from the device logs), and enter the corresponding network information. Note that you don't need to enter the example colons, but the codes do need to be in upper case.

Make sure the device is on (and in Bluetooth commissioning mode with a blue flashing light) and click Save. After the device is commissioned the light will start to flash purple.

You can use the Sensor Clusters function to read values from the device, such as using Watch to graph the current temperature.

CHIPTool on Android for commissioning, showing three screens: the CHIPTool menu, the Thread provisioning form where you enter the network details, and the sensor cluster watch screen showing a graph of temperature values from the sensor over time

There is also a command line version of CHIPTool that you can run on either Windows or Linux. It has more features as it can control arbitrary clusters (the Android version is limited to just a few).

World-wide connectivity

On the OpenThread Border Router, you can also check the status of the connected client (and the web UI can show a nice node graph).

With a global prefix assigned via Prefix Delegation, you can examine the IP address of the child device, and then, if your firewall is configured to allow ping, connect to it from around the world.

sudo ot-ctl child table
sudo ot-ctl childip

Viewing tracepath from an IPv6 only server hosted by Mythic Beasts in the UK, all the way back to a battery powered Thread device running in Brisbane, Australia.

Ping a Thread device from the global Internet, screen shot showing a terminal connected to the border router to output the device IPv6 address, and a second terminal showing a successful ping and tracepath from a server in the UK to the device in Australia

Next steps

Thread is being adopted by many building automation standards, as the low-power, IP-compatible, mesh wireless network of choice.

On top of that Matter, or one of the other standards, such as OCF or LwM2M can then be used, for global connectivity and integrated smart building management.

If you need help with your Smart Building project, get in touch with Telstra Purple IoT