Build a Thread network with nRF52840-MDK¶
OpenThread is an open-source implementation of the Thread® networking protocol. Nest has released OpenThread to make the networking technology used in Nest products more broadly available to developers, in order to accelerate the development of products for the connected home.
The Thread specification defines an IPv6-based reliable, secure and low-power wireless device-to-device communication protocol for home applications. OpenThread implements all Thread networking layers (IPv6, 6LoWPAN, IEEE 802.15.4 with MAC security, Mesh Link Establishment, Mesh Routing) and device roles, as well as Border Router support.
What'll you need¶
- 3x nRF52840-MDK boards
- 3x USB-C cables
- A Linux/macOS machine with at least 3 USB ports
Set up your development environment¶
The following section provides detailed information about the required software toolchains. Skip any step where a compatible tool already exists.
Download and install the ARM GNU Toolchain. The
6-2017-q2-updateversion is recommended. Then ensure the path is added to your OS PATH environment variable.
Type the following in your terminal to verify if the path is set correctly:
Clone and install OpenThread:
Set up the NCP Joiner¶
Build and flash¶
Build the OpenThread nRF52840 example with Joiner functionality. A device uses the Joiner role to be securely authenticated and commissioned onto a Thread network. Always clean the repo of previous builds first by running
Navigate to the directory with the OpenThread FTD NCP binary, and convert it to hex format:
Connect nRF52840-MDK to your computer with a USB cable. Flash the OpenThread NCP FTD hex file onto the nRF52840-MDK and label the board NCP so that later you don't confuse the board roles.
In the NCP design, use wpantund to communicate with and manage the Thread device.
In a terminal window, start
wpantund on the serial port with the NCP, creating the interface
utun7 and enabling info logs:
Output similar to the following is generated upon success:
Jun 9 01:29:49 wpantund <Notice>: Starting wpantund 0.08.00d (Jun 9 2018 00:31:51) . . . Jun 9 01:29:49 wpantund <Notice>: SOURCE_VERSION = 0.07.01-217-g86d29d6 Jun 9 01:29:49 wpantund <Notice>: BUILD_VERSION = 0.07.01-217-g86d29d6 Jun 9 01:29:49 wpantund <Notice>: Configuration file "/etc/wpantund.conf" read. Jun 9 01:29:49 wpantund <Notice>: Ready. Using DBUS bus ":1.2" Jun 9 01:29:49 wpantund <Notice>: Running as root without dropping privileges! Jun 9 01:29:49 wpantund <Notice>: State change: "uninitialized" -> "offline" Jun 9 01:29:49 wpantund <Notice>: NCP is running "OPENTHREAD/20170716-00584-ge4f5f240-dirty; NRF52840; Jun 8 2018 23:36:19" Jun 9 01:29:49 wpantund <Notice>: Driver is running "0.08.00d (0.07.01-217-g86d29d6; Jun 9 2018 00:31:51)" 1:29:49 wpantund <Notice>: Network is not joinable Jun 9 01:29:49 wpantund <Notice>: Resetting interface(s). . . Jun 9 01:29:49 wpantund <Notice>: Finished initializing NCP
Leave this terminal window open so that logs from wpantund can be viewed.
A user-defined interface is required to communicate with the NCP using
wpanctl. Open a new terminal window and using
wpanctl, connect to the interface you just set up:
Set up the FTDs¶
The other two Thread nodes used in this section are Full Thread Devices (FTDs) on the standard System-on-Chip (SoC) design. They do not use
wpantund, and the user manually manages them with the OpenThread CLI.
One device functions as the Commissioner, to securely authenticate and commission devices onto that network. The other device functions as a Joiner that the Commissioner can authenticate to the Thread network.
Build and flash¶
Build the OpenThread FTD example for the nRF52840-MDK, with the Commissioner and Joiner roles enabled:
Navigate to the directory with the OpenThread Full Thread Device (FTD) CLI binary, and convert it to hex format:
Connect another nRF52840-MDK to your computer with a USB cable. Flash the OpenThread CLI FTD hex file and label the board Commissioner:
Verify a successful build by accessing the OpenThread CLI using a terminal application. The nRF52840-MDK boards use a baud rate of
In the terminal window, press Enter on the keyboard a few times to bring up the OpenThread CLI
> prompt. Check for IPv6 addresses:
Set up the FTD Joiner¶
Repeat the above process to flash the third nRF52840-MDK board, using the existing
ot-cli-ftd.hex build. Then label the board Joiner. Check for IPv6 addresses in the terminal window:
Create the Thread network¶
Now that you have all your terminal windows and screens configured, let's create our Thread network. On the Commissioner, configure the network and bring up Thread:
After a moment, check the device state. It should be the Leader. Also get the
RLOC16 for future reference.
Check the device's IPv6 addresses:
## FTD Commissioner ## ---------------------- > ipaddr fd11:2233:4455:0:0:ff:fe00:fc00 # Leader Anycast Locator (ALOC) fd11:2233:4455:0:0:ff:fe00:3400 # Routing Locator (RLOC) fd11:2233:4455:0:99ea:1fe9:acd6:d384 # Mesh-Local EID (ML-EID) fe80:0:0:0:2003:a240:810f:1598 # Link-Local Address (LLA) Done
makerdiary network is now visible when scanned from other Thread devices.
wpanctl on the NCP Joiner:
From the OpenThread CLI on the FTD Joiner:
makerdiary network doesn't appear in the list, try scanning again.
You may note that in both scans, the network seems to be not joinable (Joinable column on the NCP Joiner, J column on the FTD Joiner). This only means that Thread Commissioning is not active on the network. It can still be joined out-of-band, by entering the network master key in the joiner device manually.
Add the NCP Joiner¶
Let's add the NCP Joiner to the Thread network we just created, using an out-of-band process. Scan for networks on the NCP Joiner:
To join, set the network master key on the NCP Joiner and join network
1 (the ID in the first column of the scan output):
Check the status of the NCP Joiner to verify. It might take a few seconds for all IPv6 addresses to appear in the output.
## NCP Joiner ## ---------------- wpanctl:utun7> status utun7 => [ "NCP:State" => "associated" "Daemon:Enabled" => true "NCP:Version" => "OPENTHREAD/20170716-00650-g631557e8-dirty; NRF52840; Jun 9 2018 15:45:03" "Daemon:Version" => "0.08.00d (0.07.01-217-g86d29d6; Jun 9 2018 00:31:51)" "Config:NCP:DriverName" => "spinel" "NCP:HardwareAddress" => [9019EC5D617D7AAB] "NCP:Channel" => 11 "Network:NodeType" => "end-device" "Network:Name" => "makerdiary" "Network:XPANID" => 0x1122334455667788 "Network:PANID" => 0x1122 "IPv6:LinkLocalAddress" => "fe80::60bd:ff84:2121:344d" "IPv6:MeshLocalAddress" => "fd11:2233:4455::f:b5e:169b:b875" "IPv6:MeshLocalPrefix" => "fd11:2233:4455::/64" "com.nestlabs.internal:Network:AllowingJoin" => false ]
Make note of the
IPv6:MeshLocalAddress, you'll use it later.
Get the NCP Joiner's
Back on the FTD Commissioner, check the router and child tables to confirm both devices are part of the same network. Use the
RLOC16 to identify the NCP Joiner.
## FTD Commissioner ## ---------------------- > router table | ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC | +----+--------+----------+-----------+-------+--------+-----+------------------+ | 13 | 0x3400 | 63 | 0 | 0 | 0 | 0 | 2203a240810f1598 | Done > child table | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|S|D|N| Extended MAC | +-----+--------+------------+------------+-------+------+-+-+-+-+------------------+ | 3 | 0x3403 | 240 | 66 | 3 | 86 |1|1|1|1| 62bdff842121344d | Done
Ping the mesh-local address of the NCP Joiner (the
IPv6:MeshLocalAddress attribute from the NCP Joiner's
status output) to verify connectivity:
Commission the FTD Joiner¶
Now let's add the third Thread device to the
makerdiary network. This time we're going to use the more secure in-band commissioning process. On the FTD Joiner, scan for the network:
0 in the
J column indicates that Thread Commissioning is not active on the device.
Let's be specific when commissioning on this next device, and only allow the FTD Joiner to join. Still on the FTD Joiner, get the
eui64, so the FTD Commissioner can identify it:
On the FTD Commissioner, start the commissioner and specify the eui64 of the device that can join, along with the Joiner Credential. The Joiner Credential is a device-specific passphrase.
Switch to the FTD Joiner, and rescan:
As indicated by the
1 in the
J column, Thread Commissioning is now active on the network. Start the joiner role with the Joiner Credential you just set up on the FTD Commissioner:
Within a minute or so, you get a confirmation of a successful authentication.
Bring up Thread so the FTD Joiner joins the
makerdiary network, and immediately check the state and
Check the device's IPv6 addresses. Notice that there is no ALOC. That's because this device is not the Leader, nor does it hold an Anycast-specific role that requires an ALOC.
Immediately switch to the FTD Commissioner and check the router and child tables to confirm that three devices exist in the
## FTD Commissioner ## ---------------------- > router table | ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC | +----+--------+----------+-----------+-------+--------+-----+------------------+ | 13 | 0x3400 | 63 | 0 | 0 | 0 | 0 | 2203a240810f1598 | Done > child table | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|S|D|N| Extended MAC | +-----+--------+------------+------------+-------+------+-+-+-+-+------------------+ | 3 | 0x3403 | 240 | 231 | 3 | 86 |1|1|1|1| 62bdff842121344d | | 4 | 0x3404 | 240 | 49 | 3 | 88 |1|1|1|1| 7a2755cf47e45907 | Done
Based on the
RLOC16, the FTD Joiner has attached to the network as an End Device (child). Here is our updated topology:
Send messages with UDP¶
One of the application services that OpenThread provides is User Datagram Protocol (UDP), a Transport Layer protocol. An application built on OpenThread could use the UDP API to pass messages between nodes in a Thread network, or to other devices in an external network (like the internet, if the Thread network features a Border Router).
UDP sockets are exposed through the OpenThread CLI. Let's use it to pass messages between the two FTDs.
Get the Mesh-Local EID address for the FTD Joiner. We're using this address because it's reachable from anywhere within the Thread network.
Start UDP and bind it to a socket for any IPv6 address:
Switch to the FTD Commissioner, start UDP, and connect to the socket you set up on the FTD Joiner, using its ML-EID:
The UDP connection should be live between the two nodes. Send a message from the FTD Commissioner:
You've created a physical Thread network with nRF52840-MDK!