Build a Thread network with nRF52840-MDK¶
Introduction¶
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-update
version 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:
-
Install pyOCD:
-
Follow the wpantund Installation Guide to install wpantund.
-
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 make clean
.
cd ~/openthread
make -f examples/Makefile-nrf52840 clean
make -f examples/Makefile-nrf52840 JOINER=1
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.
Configure wpantund¶
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:
sudo /usr/local/sbin/wpantund -o Config:NCP:SocketPath /dev/cu.usbmodem14112 \
-o Config:TUN:InterfaceName utun7 \
-o Daemon:SyslogMask " -info"
Output similar to the following is generated upon success:
Jun 9 01:29:49 wpantund[12257] <Notice>: Starting wpantund 0.08.00d (Jun 9 2018 00:31:51) . . .
Jun 9 01:29:49 wpantund[12257] <Notice>: SOURCE_VERSION = 0.07.01-217-g86d29d6
Jun 9 01:29:49 wpantund[12257] <Notice>: BUILD_VERSION = 0.07.01-217-g86d29d6
Jun 9 01:29:49 wpantund[12257] <Notice>: Configuration file "/etc/wpantund.conf" read.
Jun 9 01:29:49 wpantund[12257] <Notice>: Ready. Using DBUS bus ":1.2"
Jun 9 01:29:49 wpantund[12257] <Notice>: Running as root without dropping privileges!
Jun 9 01:29:49 wpantund[12257] <Notice>: State change: "uninitialized" -> "offline"
Jun 9 01:29:49 wpantund[12257] <Notice>: NCP is running "OPENTHREAD/20170716-00584-ge4f5f240-dirty; NRF52840; Jun 8 2018 23:36:19"
Jun 9 01:29:49 wpantund[12257] <Notice>: Driver is running "0.08.00d (0.07.01-217-g86d29d6; Jun 9 2018 00:31:51)"
1:29:49 wpantund[12257] <Notice>: Network is not joinable
Jun 9 01:29:49 wpantund[12257] <Notice>: Resetting interface(s). . .
Jun 9 01:29:49 wpantund[12257] <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:
cd ~/openthread
make -f examples/Makefile-nrf52840 clean
make -f examples/Makefile-nrf52840 COMMISSIONER=1 JOINER=1
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 build¶
Verify a successful build by accessing the OpenThread CLI using a terminal application. The nRF52840-MDK boards use a baud rate of 115200
.
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:
## FTD Commissioner ##
----------------------
> networkname makerdiary
Done
> extpanid 1122334455667788
Done
> panid 0x1122
Done
> masterkey 11223344556677881122334455667788
Done
> ifconfig up
Done
> thread start
Done
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
The makerdiary
network is now visible when scanned from other Thread devices.
From wpanctl
on the NCP Joiner:
## NCP Joiner ##
----------------
wpanctl:utun7> scan
| Joinable | NetworkName | PAN ID | Ch | XPanID | HWAddr | RSSI
---+----------+--------------------+--------+----+------------------+------------------+------
1 | NO | "makerdiary" | 0x1122 | 11 | 1122334455667788 | 2203A240810F1598 | -59
From the OpenThread CLI on the FTD Joiner:
## FTD Joiner ##
----------------
> scan
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |
+---+------------------+------------------+------+------------------+----+-----+-----+
> | 0 | makerdiary | 1122334455667788 | 1122 | 2203a240810f1598 | 11 | -32 | 244 |
Done
If the 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:
## NCP Joiner ##
----------------
wpanctl:utun7> scan
| Joinable | NetworkName | PAN ID | Ch | XPanID | HWAddr | RSSI
---+----------+--------------------+--------+----+------------------+------------------+------
1 | NO | "makerdiary" | 0x1122 | 11 | 1122334455667788 | EE7A6D71FB28C60D | -68
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):
## NCP Joiner ##
----------------
wpanctl:utun7> setprop Network:Key 11223344556677881122334455667788
wpanctl:utun7> join 1
Joining "makerdiary" 1122334455667788 as node type "end-device"
Successfully Joined!
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 RLOC16
:
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:
## FTD Commissioner ##
----------------------
> ping fd11:2233:4455::f:b5e:169b:b875
> 8 bytes from fd11:2233:4455:0:f:b5e:169b:b875: icmp_seq=2 hlim=64 time=35ms
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:
## FTD Joiner ##
----------------
> scan
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |
+---+------------------+------------------+------+------------------+----+-----+-----+
> | 0 | makerdiary | 1122334455667788 | 1122 | 2203a240810f1598 | 11 | -32 | 244 |
Done
A 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.
## FTD Commissioner ##
----------------------
> commissioner start
Done
> commissioner joiner add 31ae3e8e7b87cfd6 J01NME
Done
Switch to the FTD Joiner, and rescan:
## FTD Joiner ##
----------------
> scan
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |
+---+------------------+------------------+------+------------------+----+-----+-----+
> | 1 | makerdiary | 1122334455667788 | 1122 | 2203a240810f1598 | 11 | -32 | 244 |
Done
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 RLOC16
:
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.
## FTD Joiner ##
----------------
> ipaddr
fd11:2233:4455:0:0:ff:fe00:3404
fe80:0:0:0:7827:55cf:47e4:5907
fd11:2233:4455:0:e839:eb52:f7ec:74e3
Done
Immediately switch to the FTD Commissioner and check the router and child tables to confirm that three devices exist in the makerdiary
network:
## 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.
## FTD Joiner ##
----------------
> ipaddr
fd11:2233:4455:0:0:ff:fe00:fc00 # Leader Anycast Locator (ALOC)
fd11:2233:4455:0:0:ff:fe00:f400 # Routing Locator (RLOC)
fe80:0:0:0:7827:55cf:47e4:5907 # Link-Local Address (LLA)
fd11:2233:4455:0:e839:eb52:f7ec:74e3 # Mesh-Local EID (ML-EID)
Done
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:
## FTD Commissioner ##
----------------------
> udp open
Done
> udp connect fd11:2233:4455:0:e839:eb52:f7ec:74e3 1212
Done
The UDP connection should be live between the two nodes. Send a message from the FTD Commissioner:
On the FTD Joiner, the UDP message has been received!## FTD Joiner ##
----------------
> 16 bytes from fd11:2233:4455:0:0:ff:fe00:3400 49153 hello-openthread
Congratulations!¶
You've created a physical Thread network with nRF52840-MDK!
Reference¶
- Build a Thread network with nRF52840 boards and OpenThread - covers all the steps in this post
- openthread.io
- github.com/openthread
- Thread Primer — covers all the Thread concepts in this post
- OpenThread CLI reference
- OpenThread UDP CLI reference