1. Introduction
OpenThread, released by the Google Nest team, is an open-source implementation of the Thread® networking protocol designed 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 and commercial building applications.
Espressif has ported the OpenThread stack based on FreeRTOS and LwIP, enabling developers to rapidly build Thread networks. The related source code can be obtained from GitHub. At the same time, Espressif has also implemented a Thread Border Router based on RTOS.
In this Codelab, you'll program OpenThread on real hardware, create and manage a Thread network, and pass messages between nodes.
What you'll learn
- Building and flashing OpenThread CLI binaries to ESP boards.
- Building and flashing border router to ESP Thread Border Router board.
- Manually managing Thread nodes with ESP Monitor and the OpenThread CLI.
- Forming a Thread network on the Thread Border Router.
- Securing commissioning of devices onto a Thread network.
- Pinging IPv6 address between Thread nodes.
- Passing messages between Thread nodes with UDP.
What you'll need
Hardware:
Software:
2. Getting started
- ESP-IDF Installation.
Please follow the ESP-IDF Programming Guide to install the software development environment.
- Clone the ESP Thread Border Router SDK.
ESP-THREAD-BR is the official ESP Thread Border Router SDK. It supports all fundamental network features to build a Thread Border Router and integrates rich product level features for quick productization.
$ cd <your-local-workspace> $ git clone --recursive https://github.com/espressif/esp-thread-br.git
3. Build and flash
For building and flashing the ot-cli-ftd binary file on ESP boards with IEEE 802.15.4 modules, you can refer to ESP-IDF example ot_cli for more details:
$ cd <your-idf-path>/examples/openthread/ot_cli $ idf.py set-target <your-board-type>
Enable the joiner feature via menuconfig:
$ idf.py menuconfig
Component config > OpenThread > Enable Joiner, then build and flash.
$ idf.py -p <your-local-port> build flash monitor
For building and flashing the ot-br binary file on ESP Thread Border Router Board, you need to build the RCP binary file first. This RCP binary file doesn't need to be explicitly flashed to the device on the ESP Thread Border Router Board. It will be included in the Border Router binary file and flashed to the ESP32-H2 chip upon first boot (or the RCP firmware changed). You can refer to ESP Thread BR docs for more details:
$ cd <your-idf-path>/examples/openthread/ot_rcp $ idf.py set-target esp32h2 $ idf.py build $ cd <your-esp-thread-br-path>/examples/basic_thread_border_router $ idf.py set-target esp32s3
Enable the commissioner feature via menuconfig:
$ idf.py menuconfig
Component config > OpenThread > Enable Commissioner, then build and flash.
$ idf.py -p <your-local-port> build flash monitor
4. Forming a Thread network on the Thread Border Router
Now you can form a Thread network using the OpenThread command line on ESP Thread Border Router Board (BR Commissioner):
## BR Commissioner ## ---------------------- > dataset init new Done > dataset Active Timestamp: 1 Channel: 21 Channel Mask: 0x07fff800 Ext PAN ID: 151975d11bea97b5 Mesh Local Prefix: fd6a:b54b:d6a3:b05a::/64 Network Key: 731ab6a60a64a0a0b14b259b86b2be01 Network Name: OpenThread-1444 PAN ID: 0x1444 PSKc: 54e7f18d2575014da94db09df29c5df0 Security Policy: 672 onrc 0 Done
Commit this dataset as the active one:
> dataset commit active Done
Bring up the IPv6 interface:
> ifconfig up I (59329) OPENTHREAD: Platform UDP bound to port 49153 Done I (59329) OT_STATE: netif up
Start Thread protocol operation:
> thread start I(61709) OPENTHREAD:[N] Mle-----------: Role disabled -> detached Done > I(62469) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset I(69079) OPENTHREAD:[N] RouterTable---: Allocate router id 11 I(69079) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 2c00 I(69089) OPENTHREAD:[N] Mle-----------: Role detached -> leader I(69089) OPENTHREAD:[N] Mle-----------: Partition ID 0x28b518c6 I (69099) OPENTHREAD: Platform UDP bound to port 49154
After a moment, check the device state. It should be the Leader.
> state leader Done >
5. Join the Thread network via networkkey
In this codelab, two ESP boards with IEEE 802.15.4 modules are prepared for joining the BR formed network. In this session, we will add Board1 to the network.
Get the networkkey from BR:
## BR Commissioner ## ---------------------- > networkkey 731ab6a60a64a0a0b14b259b86b2be01 Done >
Set this networkkey to one ESP board (Board1 Joiner) with IEEE 802.15.4 modules:
## Board1 Joiner ## ---------------------- > dataset networkkey 731ab6a60a64a0a0b14b259b86b2be01 Done
Commit this dataset as the active one:
> dataset commit active Done
Bring up the IPv6 interface:
> ifconfig up Done I (20308) OT_STATE: netif up
Start Thread protocol operation:
> thread start I(23058) OPENTHREAD:[N] Mle-----------: Role disabled -> detached Done > I(23408) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset I(30028) OPENTHREAD:[N] Mle-----------: Attach attempt 1 unsuccessful, will try again in 0.288 seconds I(30328) OPENTHREAD:[N] Mle-----------: Attach attempt 2, AnyPartition I(33498) OPENTHREAD:[N] Mle-----------: Delay processing Announce - channel 21, panid 0x1444 I(33758) OPENTHREAD:[N] Mle-----------: Processing Announce - channel 21, panid 0x1444 I(33758) OPENTHREAD:[N] Mle-----------: Role detached -> disabled I(33758) OPENTHREAD:[N] Mle-----------: Role disabled -> detached I(34178) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition I(35068) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 2c01 I(35068) OPENTHREAD:[N] Mle-----------: Role detached -> child
After a moment, check the device state. It should be the Child.
> state child Done
Set the role to Router.
> state router Done I(51028) OPENTHREAD:[N] Mle-----------: RLOC16 2c01 -> 2800 I(51028) OPENTHREAD:[N] Mle-----------: Role child -> router I(51028) OPENTHREAD:[N] Mle-----------: Partition ID 0x28b518c6 >
6. Join the Thread network via secure commissioning
In this session, we will add Board2 to the network via security commissioning:
Get the PSKc and panid from BR Commissioner:
## BR Commissioner ## ---------------------- > pskc 54e7f18d2575014da94db09df29c5df0 Done > panid 0x1444 Done
Configure the network information to Board2:
## Board2 Joiner ## ---------------------- > dataset pskc 54e7f18d2575014da94db09df29c5df0 Done > dataset panid 0x1444 Done
Commit this dataset as the active one:
## Board2 Joiner ## ---------------------- > dataset commit active Done
Bring up the IPv6 interface:
## Board2 Joiner ## ---------------------- > ifconfig up Done I (29146) OT_STATE: netif up
Get the eui64 from Board2:
## Board2 Joiner ## ---------------------- > eui64 4831b7fffec02be1 Done
On the BR Commissioner, start the commissioner and specify the eui64
of the device that can join, along with the Joiner Credential, for example J01NME
. The Joiner Credential is a device-specific string of all uppercase alphanumeric characters (0-9 and A-Y, excluding I, O, Q and Z for readability), with a length between 6 and 32 characters.
## BR Commissioner ## ---------------------- > commissioner start Commissioner: petitioning Done Commissioner: active > commissioner joiner add 4831b7fffec02be1 J01NME Done
Switch to the Board2 Joiner. Start the joiner role with the Joiner Credential that you just set up on the BR Commissioner:
## Board2 Joiner ## ---------------------- > ifconfig up Done > joiner start J01NME Done
Within a minute or so, you get a confirmation of a successful authentication:
## Board2 Joiner ## ---------------------- > Join success
After that, you can start and join the Thread network formed by the BR Commissioner.
Start Thread protocol operation:
> thread start I(35727) OPENTHREAD:[N] Mle-----------: Role disabled -> detached Done > I(36197) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset I(37007) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 2801 I(37007) OPENTHREAD:[N] Mle-----------: Role detached -> child
Set the role to Router.
> state router Done I(46057) OPENTHREAD:[N] Mle-----------: RLOC16 2801 -> 4400 I(46057) OPENTHREAD:[N] Mle-----------: Role child -> router I(46057) OPENTHREAD:[N] Mle-----------: Partition ID 0x28b518c6 >
Now you get a Thread network with the topology shown below:
7. Pinging IPv6 address between Thread nodes
You can use the ping command to communicate between any two boards. Use the command ipaddr
to print the IPv6 address of each board:
## BR Commissioner ## ---------------------- > ipaddr fd6a:b54b:d6a3:b05a:0:ff:fe00:fc00 # Leader Anycast Locator (ALOC) fd6a:b54b:d6a3:b05a:0:ff:fe00:2c00 # Routing Locator (RLOC) fd6a:b54b:d6a3:b05a:a8df:eb43:63d8:bda0 # Mesh-Local EID (ML-EID) fe80:0:0:0:687c:7248:cc14:9c4d # Link-Local Address (LLA) Done >
## Board1 Joiner ## ---------------------- > ipaddr fd6a:b54b:d6a3:b05a:0:ff:fe00:2800 # Routing Locator (RLOC) fd6a:b54b:d6a3:b05a:e461:db08:c833:1248 # Mesh-Local EID (ML-EID) fe80:0:0:0:18ac:df04:4671:6a45 # Link-Local Address (LLA) Done
## Board2 Joiner ## ---------------------- > ipaddr fd6a:b54b:d6a3:b05a:0:ff:fe00:4400 # Routing Locator (RLOC) fd6a:b54b:d6a3:b05a:d7dc:8e90:9bc9:ecbc # Mesh-Local EID (ML-EID) fe80:0:0:0:a8cc:1483:f696:91a2 # Link-Local Address (LLA) Done
For example, to ping Board2 MLE-ID from BR Commissioner, you can run this command on BR Commissioner:
## BR Commissioner ## ---------------------- > ping fd6a:b54b:d6a3:b05a:d7dc:8e90:9bc9:ecbc 16 bytes from fd6a:b54b:d6a3:b05a:d7dc:8e90:9bc9:ecbc: icmp_seq=1 hlim=255 time=123ms 1 packets transmitted, 1 packets received. Packet loss = 0.0%. Round-trip min/avg/max = 123/123.0/123 ms. Done
8. Passing messages between Thread nodes with UDP
In this session, you will learn how to send a message between two Thread devices. For example, open udp and bind it on port 20617
and listen for all addresses on BR:
## BR Commissioner ## ---------------------- > udp open Done > udp bind :: 20617 I (1298739) OPENTHREAD: Platform UDP bound to port 20617 Done
Then send a message from Board1 to BR MLE-ID address and port 20617
:
## Board1 Joiner ## ---------------------- > udp open Done > udp send fd6a:b54b:d6a3:b05a:a8df:eb43:63d8:bda0 20617 ESP
You can see the message received on BR:
## BR Commissioner ## ---------------------- 3 bytes from fd6a:b54b:d6a3:b05a:e461:db08:c833:1248 49154 ESP
9. Congratulations!
You've created a physical Thread network using ESP boards!
You now know:
- Building and flashing OpenThread CLI binaries to ESP boards.
- Building an flashing border router to ESP Thread Border Router board.
- Manually managing Thread nodes with ESP Monitor and the OpenThread CLI.
- Forming a Thread network on the Thread Border Router.
- Securing commissioning of devices onto a Thread network.
- Pinging IPv6 address between Thread nodes.
- Passing messages between Thread nodes with UDP.
Further reading
Check out openthread.io and GitHub for a variety of OpenThread resources, including:
- Supported Platforms — discover all the platforms that support OpenThread
- Build OpenThread — further details on building and configuring OpenThread
- Thread Primer — covers all the Thread concepts featured in this Codelab
Reference: