Overview
OpenThread is an open-source implementation of the Thread networking protocol, released by Google’s Nest team. Thread is an IPv6-based mesh networking protocol designed specifically for low-power IoT devices, providing reliable, secure, and scalable connectivity for smart home and building automation applications. OpenThread implements the full Thread specification including mesh routing (6LoWPAN), border router functionality, network commissioning, and built-in security with DTLS-based authentication and AES-CCM encryption.
Thread networks are self-healing mesh networks where devices can communicate directly with each other and route traffic across multiple hops to reach any destination. Unlike Wi-Fi or Bluetooth, Thread is specifically optimized for low-bandwidth, battery-powered devices that need reliable IP connectivity. OpenThread supports multiple hardware platforms including Nordic Semiconductor (nRF52840), Silicon Labs (EFR32), TI (CC2652), and simulation environments. It is the foundation for Matter (formerly Project CHIP), the unified smart home standard backed by Apple, Google, Amazon, and Samsung.
Installation
Build from Source
# Clone OpenThread
git clone --recursive https://github.com/openthread/openthread.git
cd openthread
# Bootstrap (install dependencies)
./script/bootstrap
# Build for simulation (POSIX)
./script/cmake-build simulation
# Build for Nordic nRF52840
./script/cmake-build nrf52840
# Build with specific features
cmake -GNinja -DCMAKE_BUILD_TYPE=Release \
-DOT_PLATFORM=simulation \
-DOT_COMMISSIONER=ON \
-DOT_JOINER=ON \
-DOT_BORDER_ROUTER=ON \
build
ninja -C build
OTBR (OpenThread Border Router)
# Clone Border Router
git clone https://github.com/openthread/ot-br-posix.git
cd ot-br-posix
# Bootstrap
./script/bootstrap
# Build and install
./script/setup
# Start Border Router
sudo systemctl start otbr-agent
sudo systemctl enable otbr-agent
Docker (Simulation)
# Run OpenThread simulation in Docker
docker pull openthread/environment
docker run -it --rm \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
--cap-add=NET_ADMIN \
openthread/environment bash
Thread Network Concepts
Device Roles
| Role | Description |
|---|
| Leader | Manages router ID assignment, partition |
| Router | Forwards packets for other devices |
| REED | Router-Eligible End Device (can become router) |
| End Device (SED/MED) | Sleepy/Minimal end device, leaf node |
| Border Router | Connects Thread to external IP networks |
| Commissioner | Authenticates and commissions new devices |
| Joiner | Device requesting to join the network |
Network Parameters
| Parameter | Description |
|---|
| Network Name | Human-readable network identifier |
| PAN ID | 16-bit Personal Area Network ID |
| Extended PAN ID | 64-bit extended PAN identifier |
| Channel | IEEE 802.15.4 radio channel (11-26) |
| Network Key | 128-bit AES encryption key |
| Mesh-Local Prefix | IPv6 /64 prefix for mesh |
| Commissioner Credential | Passphrase for commissioning |
CLI Commands
# Start the OpenThread CLI
./build/simulation/examples/apps/cli/ot-cli-ftd 1
# Create a new Thread network
> dataset init new
> dataset commit active
> ifconfig up
> thread start
# Check device state
> state
# Output: leader, router, child, detached, disabled
# View network info
> dataset active
> networkname
> panid
> channel
> networkkey
> extpanid
Joining a Network
# On the joiner device
> ifconfig up
> joiner start MY_PASSPHRASE
# Wait for "Join success"
> thread start
# Manual join with known credentials
> dataset networkname MyThreadNet
> dataset networkkey 00112233445566778899aabbccddeeff
> dataset panid 0x1234
> dataset channel 15
> dataset commit active
> ifconfig up
> thread start
# Device state and identity
> state
> rloc16
> eui64
> extaddr
# IP addresses
> ipaddr
> ipaddr mleid # Mesh-Local EID
> ipaddr rloc # Routing Locator
> ipaddr linklocal # Link-Local
# Neighbor/routing info
> neighbor table
> router table
> childtable
> parentinfo
> leaderdata
# Network diagnostics
> networkdiagnostic get 0xfc00 0 1 2 3 4 5 6 7 8 9
# Partition info
> partitionid
> networkdata show
Commissioning
# On Commissioner device
> commissioner start
> commissioner joiner add * MY_PASSPHRASE
# Or add specific joiner by EUI-64
> commissioner joiner add 18b4300000000001 MY_PASSPHRASE
# Check commissioner state
> commissioner state
> commissioner sessionid
# On Joiner device
> ifconfig up
> joiner start MY_PASSPHRASE
# Wait for success
> thread start
Messaging
# Send UDP message
> udp open
> udp bind :: 1234
> udp send fdde:ad00:beef:0:0:ff:fe00:fc00 1234 hello
# Send to multicast
> udp send ff03::1 1234 "hello mesh"
# Ping another device
> ping fdde:ad00:beef:0:558:f56b:d688:799
> ping ff02::1 # All nodes link-local
> ping ff03::1 # All nodes mesh-local
CoAP (Constrained Application Protocol)
# Start CoAP
> coap start
# Create resource
> coap resource test-resource
# Send CoAP GET request
> coap get fdde:ad00:beef:0:558:f56b:d688:799 test-resource
# Send CoAP POST
> coap post fdde:ad00:beef:0:558:f56b:d688:799 test-resource con "hello"
# Send CoAP PUT
> coap put fdde:ad00:beef:0:558:f56b:d688:799 test-resource con "update"
Border Router Configuration
OTBR Web GUI
# Access web interface
# http://<border-router-ip>:80
# Form network via web
# Navigate to Form > Set parameters > Form
# Join existing network
# Navigate to Join > Enter credentials > Join
OTBR CLI
# Check OTBR agent status
sudo systemctl status otbr-agent
# View Thread interface
sudo ot-ctl state
sudo ot-ctl ipaddr
sudo ot-ctl dataset active
# Form network via CLI
sudo ot-ctl dataset init new
sudo ot-ctl dataset commit active
sudo ot-ctl ifconfig up
sudo ot-ctl thread start
# Enable Border Router
sudo ot-ctl prefix add fd00:dead:beef::/64 paros
sudo ot-ctl netdata register
# External route
sudo ot-ctl route add 2001:db8::/48 s
sudo ot-ctl netdata register
NAT64 Configuration
# Enable NAT64 on Border Router
sudo ot-ctl nat64 enable
# Check NAT64 status
sudo ot-ctl nat64 state
# Map IPv4 addresses
sudo ot-ctl nat64 mappings
Advanced Usage
Simulation Environment
# Run multiple simulated nodes
cd openthread
# Terminal 1: Start node 1 (will become Leader)
./build/simulation/examples/apps/cli/ot-cli-ftd 1
# Terminal 2: Start node 2
./build/simulation/examples/apps/cli/ot-cli-ftd 2
# On node 1: Create network
> dataset init new
> dataset commit active
> ifconfig up
> thread start
> commissioner start
> commissioner joiner add * JOINER_PASS
# On node 2: Join network
> ifconfig up
> joiner start JOINER_PASS
> thread start
SRP (Service Registration Protocol)
# Register a service
> srp client host name my-device
> srp client host address auto
> srp client service add my-service _http._tcp 80
> srp client start fdde:ad00:beef:0:0:ff:fe00:fc00 53535
# List registered services
> srp client service
> srp client host
DNS-SD Service Discovery
# Browse services
> dns browse _http._tcp.default.service.arpa
# Resolve service
> dns service my-service _http._tcp.default.service.arpa
# Resolve hostname
> dns resolve my-device.default.service.arpa
Power Management
# Configure as Sleepy End Device
> mode -
> pollperiod 5000 # Poll parent every 5 seconds
# Configure as Minimal End Device
> mode rn
# Check current mode
> mode
# r=rx-on, s=secure, d=full-function, n=full-network-data
Configuration
Build Options
| CMake Option | Description |
|---|
-DOT_COMMISSIONER=ON | Enable Commissioner role |
-DOT_JOINER=ON | Enable Joiner role |
-DOT_BORDER_ROUTER=ON | Enable Border Router |
-DOT_DHCP6_CLIENT=ON | Enable DHCPv6 client |
-DOT_DHCP6_SERVER=ON | Enable DHCPv6 server |
-DOT_DNS_CLIENT=ON | Enable DNS client |
-DOT_SRP_CLIENT=ON | Enable SRP client |
-DOT_COAP=ON | Enable CoAP |
-DOT_LOG_LEVEL=DEBG | Set log level |
Troubleshooting
| Issue | Solution |
|---|
| Device stuck in “detached” | Verify network key and channel match |
| Joiner fails authentication | Check commissioner credential passphrase |
| No IPv6 connectivity | Verify border router prefix, check netdata |
| High packet loss | Check radio channel interference, try scanning |
| Leader election loops | Reduce network size, check partitioning |
| Border router not routing | Verify prefix registration, check ip6tables |
| Cannot ping external hosts | Verify NAT64 or IPv6 routing on border router |
| Firmware flash fails | Check USB connection, reset device to DFU mode |
Diagnostic Commands
# Scan available channels
> scan
# Energy scan
> scan energy 100
# Check connectivity
> ping ff02::1
# View routing table
> router table
# Network diagnostic
> networkdiagnostic get ff02::1 0 1 2 8 9
# Factory reset
> factoryreset
# View logs
sudo journalctl -u otbr-agent -f