OpenThread is an open-source implementation of the Thread networking protocol. Nest has released OpenThread to make the technology used in Nest products broadly available to developers 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 including IPv6, 6LoWPAN, IEEE 802.15.4 with MAC security, Mesh Link Establishment, and Mesh Routing.

This Codelab will walk you through simulating a Thread network on emulated devices.

What you'll learn

What you'll need

Git

Git is required to complete this Codelab. Download and install it before continuing.

Download Git

Once installed, follow the instructions for your specific OS to download and build OpenThread.

Build on Linux

These installation instructions have been tested on Ubuntu Server 14.04 LTS.

Install dependencies:

$ sudo apt-get install -y software-properties-common
$ sudo apt-get update -qq

Install packages needed for wpantund build and runtime:

$ sudo apt-get install -y build-essential git make autoconf \
                          autoconf-archive automake dbus libtool gcc \
                          g++ gperf flex bison texinfo ncurses-dev \                  
                          libexpat-dev python sed python-pip gawk \
                          libreadline6-dev libreadline6 libdbus-1-dev \
                          libboost-dev
$ sudo apt-get install -y --force-yes gcc-arm-none-eabi
$ sudo pip install pexpect

Install wpantund:

$ mkdir -p ~/src
$ cd ~/src
$ git clone --recursive https://github.com/openthread/wpantund.git
$ cd wpantund
$ sudo git checkout full/master
$ ./configure --sysconfdir=/etc
$ make
$ sudo make install

Sometimes there are issues with dbus when it comes to wpantund. Force a restart of dbus to be safe:

$ sudo service dbus restart

Install OpenThread:

$ cd ~/src
$ git clone --recursive https://github.com/openthread/openthread.git
$ cd openthread
$ ./bootstrap

Continue with the next step in the Codelab.

Build on Mac OS X

These installation instructions have been tested on Mac OS X Sierra 10.12.6.

XCode is needed to install and build OpenThread on Mac OS X.

Download XCode

After XCode is installed, install the XCode Command Line Tools:

$ xcode-select --install

Install the build toolchain:

$ mkdir -p ~/src
$ cd ~/src
$ git clone --recursive https://github.com/openthread/openthread.git
$ cd openthread
$ ./script/bootstrap

Install wpantund:

$ cd ~/src
$ git clone --recursive https://github.com/openthread/wpantund.git
$ cd wpantund
$ sudo git checkout full/master
$ brew install ./etc/wpantund.rb --HEAD

# Start the dbus daemon
$ sudo cp "$(brew --prefix)"/Cellar/dbus/*/org.freedesktop.dbus-session.plist /Library/LaunchDaemons/
$ sudo launchctl load -w /Library/LaunchDaemons/org.freedesktop.dbus-session.plist

# Configure and install wpantund
$ ./configure --sysconfdir=/etc
$ make
$ sudo make install

Install Openthread:

$ cd ~/src/openthread
$ ./bootstrap

Continue with the next step in the Codelab.

Build on Windows

Full installation instructions for building on Windows can be found on GitHub.

Build on Windows

We recommend using Linux or Mac OS X for this Codelab. The Windows build has not been tested for this Codelab, and is currently not supported.

If you prefer Windows, we recommend trying the Docker version of this Codelab.

OpenThread Simulation on Docker

Once your installation is complete, build the example OpenThread application. For this Codelab we are using the emulated POSIX example.

$ cd ~/src/openthread
$ make -f examples/Makefile-posix

The example application you'll use for this Codelab demonstrates a minimal OpenThread application that exposes the OpenThread configuration and management interfaces via a basic command-line interface (CLI).

This exercise takes you through the minimal steps required to ping one emulated Thread device from another emulated Thread device.

The figure below describes a basic Thread network topology. For this exercise, we'll emulate the two nodes within the green circle: a Thread Leader and Thread Router with a single connection between them.

Ping a node

1. Start Node 1

Navigate to the openthread directory and spawn the CLI process for an emulated Thread device using the ot-cli-ftd binary.

$ cd ~/src/openthread
$ ./output/x86_64-unknown-linux-gnu/bin/ot-cli-ftd 1

This binary implements an OpenThread device emulated on top of POSIX. The IEEE 802.15.4 radio driver is implemented on top of UDP (IEEE 802.15.4 frames are passed within UDP payloads).

The argument of 1 is a file descriptor that represents the least-significant bits of the "factory-assigned" IEEE EUI-64 for the emulated device. This value is also used when binding to a UDP port for IEEE 802.15.4 radio emulation (port = 9000 + file descriptor). Each instance of an emulated Thread device in this Codelab will use a different file descriptor.

Note: Only use file descriptors of 1 or greater as noted in this Codelab when spawning the process for an emulated device. A file descriptor of 0 is reserved for other use.

If you don't see the > prompt after running this command, press enter.

Set the Personal Area Network (PAN) ID. This is the identifier for the Thread network you are creating. PANs are short-distance networks reserved for personal use.

> panid 0x1234
Done

Bring up the IPv6 interface:

> ifconfig up
Done

Start Thread protocol operation:

> thread start
Done

Wait a few seconds and verify that the device has become the Thread Leader. The Leader is the device responsible for managing router ID assignment.

> state
leader
Done

View the IPv6 addresses assigned to Node 1's Thread interface (your output will be different):

> ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc00
fdde:ad00:beef:0:0:ff:fe00:5800
fdde:ad00:beef:0:d41:e070:730d:ad2f
fe80:0:0:0:804b:ad57:9ad4:40f3
Done

Note the specific IPv6 address types:

Mesh-local address types are classified further:

Identify the EID in your console output make a note of it for later use. In the sample output above, the EID is:

fdde:ad00:beef:0:d41:e070:730d:ad2f

2. Start Node 2

Open a new terminal and navigate to the openthread directory and spawn the CLI process. This is your second emulated Thread device:

$ cd ~/src/openthread
$ ./output/x86_64-unknown-linux-gnu/bin/ot-cli-ftd 2

If you don't see the > prompt after running this command, press enter.

Set the PAN ID, using the same value as Node 1.

> panid 0x1234
Done

Bring up the IPv6 interface:

> ifconfig up
Done

Start Thread protocol operation:

> thread start
Done

The device will initialize itself as a Child. A Thread Child is equivalent to an End Device, which is a Thread device that transmits and receives unicast traffic only with a Parent device.

> state
child
Done

Within 2 minutes you should see the state switch from child to router. A Thread Router is capable of routing traffic between Thread devices. It is also referred to as a Parent.

> state
router
Done

Verify the network

An easy way to verify the mesh network is to look at the router table.

1. Check connectivity

On Node 2, get the RLOC16. The RLOC16 is the last 16 bits of the device's RLOC IPv6 address.

> rloc16
a800
Done

On Node 1, check the router table for Node 2's RLOC16. Make sure Node 2 has switched to the router state first.

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQI In | LQI Out | Age | Extended MAC     |
+----+--------+----------+-----------+--------+---------+-----+------------------+
| 42 | 0xa800 |       63 |         0 |      3 |       3 |  12 | 06110017a9f6f2c4 |
| 52 | 0xd000 |       52 |         0 |      0 |       0 |  21 | 02e4d04fae41de50 |

Node 1's RLOC of 0xa800 is found in the table, confirming that it is connected to the mesh.

2. Ping Node 1 from Node 2

Verify connectivity between the two emulated Thread devices. In Node 2, ping the EID assigned to Node 1:

> ping fdde:ad00:beef:0:d41:e070:730d:ad2f
16 bytes from fdde:ad00:beef:0:d41:e070:730d:ad2f: icmp_seq=1 hlim=64 time=1ms

Press enter to return to the > CLI prompt.

Test the network

Now that you can successfully ping between two emulated Thread devices, test the mesh network by taking one node offline.

Return to Node 1 and stop Thread:

> thread stop
Done

Switch to Node 2 and check the state. Within two minutes, Node 2 detects that the leader (Node 1) is offline, and you should see Node 2 transition to be the leader of the network:

> state
router
Done
...
> state
leader
Done

Once confirmed, stop Thread and factory reset Node 2 before exiting. A factory reset is done to ensure that the Thread network credentials we used in this exercise are not carried over to the next exercise.

> thread stop
Done
> factoryreset
>
> exit

Also factory reset and exit Node 1:

> factoryreset
>
> exit

See the OpenThread CLI Reference to explore all available CLI commands.

In the previous exercise, you set up a Thread network with two simulated devices and verified connectivity. However, this only allows unauthenticated IPv6 link-local traffic to pass between devices. To route global IPv6 traffic between them (and the Internet via a Thread border router), nodes must be authenticated.

In order to authenticate, one device must act as a Commissioner. The Commissioner is the currently elected authentication server for new Thread devices, and the authorizer for providing the network credentials required for the devices to join the network.

In this exercise, we will use the same two-node topology as before. For authentication, the Thread Leader will act as the Commissioner, the Thread Router as a Joiner.

1. Create a network

If continuing from the previous exercise, you should already have two terminal windows open. If not, make sure two are open and ready to use. One will serve as Node 1, the other as Node 2.

In Node 1, spawn the CLI process:

$ cd ~/src/openthread
$ ./output/x86_64-unknown-linux-gnu/bin/ot-cli-ftd 1

If you don't see the > prompt after running this command, hit enter.

Configure the Thread router:

> panid 0x1234
Done
> ifconfig up
Done
> thread start
Done

Wait a few seconds and verify that the device has become a Thread Leader:

> state
leader
Done

2. Start the Commissioner role

While still on Node 1, start the Commissioner role:

> commissioner start
Done

Allow any Joiner (by using the * wildcard) with the J01NME Joiner Credential to commission onto the network. A Joiner is a device that is added by a human administrator to a commissioned Thread Network.

> commissioner joiner add * J01NME
Done

3. Start the Joiner role

In a second terminal window, spawn a new CLI process. This is Node 2.

$ cd ~/src/openthread
$ ./output/x86_64-unknown-linux-gnu/bin/ot-cli-ftd 2

On Node 2, enable the Joiner role using the J01NME Joiner Credential.

> ifconfig up
Done
> joiner start J01NME
Done

... wait a few seconds for confirmation ...

Join success

As a Joiner, the device (Node 2) has successfully authenticated itself with the Commissioner (Node 1) and received the Thread Network credentials.

Now that Node 2 is authenticated, start Thread:

> thread start
Done

4. Validate network authentication

Check the state on Node 2, to validate that it has now joined the network. Within two minutes, Node 2 transitions from child to router:

> state
child
Done
...
> state
router
Done

5. Reset configuration

To prepare for the next exercise, reset the configuration. On each Node, stop Thread, do a factory reset, and exit the emulated Thread device:

> thread stop
Done
> factoryreset
>
> exit

You may have to press enter a few times to bring the > prompt back after a factoryreset command.

For this exercise, we are going to simulate one CLI instance (a single embedded SoC Thread device) and one Network Co-Processor (NCP) instance.

wpantund is a user-space network interface driver/daemon that provides a native IPv6 network interface to a low-power wireless NCP. It can be used to simplify supporting Thread connectivity on Unix-like operating systems, and is designed to marshall all access to the NCP, ensuring that it always remains in a consistent and well-defined state.

wpanctl is a CLI provided by wpantund to manage and configure the NCP. Using this, we'll connect the NCP to the network created by the Thread device.

Use wpantund

This exercise will use three terminal windows, corresponding to the following:

  1. CLI instance of simulated Thread device (Node 1)
  2. wpantund process
  3. wpanctl CLI instance

If continuing from the previous exercise you should already have two terminal windows open. Open a third to ensure you have three terminal windows available for this exercise.

1. Start Node 1

In the first terminal window, spawn the CLI process for your emulated Thread device:

$ cd ~/src/openthread
$ ./output/x86_64-unknown-linux-gnu/bin/ot-cli-ftd 1

If you don't see the > prompt after running this command, hit enter.

Set up a new Thread network with these specific credentials:

> networkname wpantund-test
Done
> extpanid DEBA7AB1E5EAF00D
Done
> panid 0x1234
Done
> channel 14
Done
> masterkey 1234ABCD1234ABCD1234ABCD1234ABCD
Done
> ifconfig up
Done
> thread start
Done
> state
leader
Done

View the IPv6 addresses assigned to Node 1's Thread interface:

> ipaddr
fdde:ba7a:b1e5:0:0:ff:fe00:fc00
fdde:ba7a:b1e5:0:0:ff:fe00:a800
fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1
fe80:0:0:0:9c62:f299:c1f:ec1a
Done
> 

As explained in the Simulate a Thread network step, one address is link-local (fe80) and three are mesh-local (fd). The EID is the mesh-local address that does not contain ff:fe00 in the address. In this sample output, the EID is fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1.

Identify the specific EID from your ipaddr output, which will be used to communicate with the node.

2. Start wpantund

In the second terminal window, navigate to the openthread directory, and start wpantund with an interface of utun6:

$ cd ~/src/openthread
$ sudo /usr/local/sbin/wpantund -o Config:NCP:SocketPath \
    "system:output/x86_64-unknown-linux-gnu/bin/ot-ncp-ftd 2" \
    -o Daemon:SyslogMask " -info" \
    -o Config:TUN:InterfaceName utun6

When successful, wpantund generates output similar to the following:

wpantund[58454]: Starting wpantund 0.08.00d (Nov  6 2018 10:16:08) . . .
wpantund[58454]:         SOURCE_VERSION = 0.07.01-124-g038e8b0
wpantund[58454]: Configuration file "/etc/wpantund.conf" read.
wpantund[58455]: About to exec "output/x86_64-unknown-linux-gnu/bin/ot-ncp-ftd 2"
wpantund[58454]: Ready. Using DBUS bus ":1.450111"
wpantund[58454]: Running as root without dropping privileges!
wpantund[58454]: [-NCP-]: NCP was reset (STATUS_RESET_POWER_ON, 112)
wpantund[58454]: State change: "uninitialized" -> "offline"
wpantund[58454]: NCP is running "OPENTHREAD/20170716-01058-g6f578589; POSIX; Nov  6 2018 10:19:45"
wpantund[58454]: Driver is running "0.08.00d (0.07.01-124-g038e8b0; Nov  6 2018 10:16:08)"
wpantund[58454]: Network is not joinable
wpantund[58454]: Resetting interface(s). . .
wpantund[58454]: Finished initializing NCP

3. Use wpanctl to join the network

The network interface is currently down because we haven't told wpantund to connect to anything yet. This is where wpanctl comes in.

In a third terminal window, start wpanctl for the interface utun6:

$ sudo /usr/local/bin/wpanctl -I utun6
wpanctl:utun6>

Check the status of the interface you just created:

wpanctl:utun6> status
utun6 => [
        "NCP:State" => "offline"
        "Daemon:Enabled" => true
        "NCP:Version" => "OPENTHREAD/g0449c2b; POSIX; Mar 14 2017 16:14:24"
        "Daemon:Version" => "0.07.01rc1 (0.07.01rc1-23-g07f6861; Mar 14 2017 16:05:11)"
        "Config:NCP:DriverName" => "spinel"
        "NCP:HardwareAddress" => [18B4300000000002]
]

Use the scan command to see the network you created earlier on Node 1:

wpanctl:utun6> scan
   | Joinable | NetworkName        | PAN ID | Ch | XPanID           | HWAddr           | RSSI
---+----------+--------------------+--------+----+------------------+------------------+------
 1 |       NO | "wpantund-test"    | 0x1234 | 14 | DEBA7AB1E5EAF00D | 9E62F2990C1FEC1A |  -20

Note the row index of 1 (the first column in the table). You'll need this to join the network.

Add the network key you specified on Node 1 to the interface:

wpanctl:utun6> set Network:Key --data 1234ABCD1234ABCD1234ABCD1234ABCD

Join the network using the join command and the row index from the earlier scan:

wpanctl:utun6> join 1
Joining "wpantund-test" DEBA7AB1E5EAF00D as node type "end-device"
Successfully Joined!

A quick status check now yields more information:

wpanctl:utun6> status
utun6 => [
        "NCP:State" => "associated"
        "Daemon:Enabled" => true
        "NCP:Version" => "OPENTHREAD/g4f5fa83-dirty; POSIX; Oct 20 2017 17:25:25"
        "Daemon:Version" => "0.08.00d (0.07.01-124-g038e8b0/0.07.01-153-g6752c40; Oct 20 2017 17:22:28)"
        "Config:NCP:DriverName" => "spinel"
        "NCP:HardwareAddress" => [18B4300000000002]
        "NCP:Channel" => 14
        "Network:NodeType" => "end-device"
        "Network:Name" => "wpantund-test"
        "Network:XPANID" => 0xDEBA7AB1E5EAF00D
        "Network:PANID" => 0x1234
        "IPv6:LinkLocalAddress" => "fe80::d864:18da:9256:c03e"
        "IPv6:MeshLocalAddress" => "fdde:ba7a:b1e5:0:9e11:3f68:f68a:6395"
        "IPv6:MeshLocalPrefix" => "fdde:ba7a:b1e5::/64"
        "com.nestlabs.internal:Network:AllowingJoin" => false
]

Quit wpanctl and ping Node 1, using its EID with the ping6 command. If the wpantund interface is successfully joined to and communicating with the Thread network, the ping succeeds.

wpanctl:utun6> quit

$ ping6 fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1
PING fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1(fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1) 56 data bytes
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=1 ttl=64 time=6.27 ms
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=2 ttl=64 time=2.16 ms
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=3 ttl=64 time=3.71 ms
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=4 ttl=64 time=3.69 ms
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=5 ttl=64 time=2.90 ms
64 bytes from fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1: icmp_seq=6 ttl=64 time=2.22 ms
^C
--- fdde:ba7a:b1e5:0:ebea:df63:74ba:aa1 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5008ms
rtt min/avg/max/mdev = 2.165/3.497/6.279/1.387 ms

Use Ctrl+C to stop the ping.

You can also check the wpantund log in the second terminal window to confirm the scan by wpanctl, as well as the successful join:

wpantund[22908]: Scan -> Name:wpantund-test    , PanId:0x1234, Ch:14, Joinable:NO , XPanId:0xDEBA7AB1E5EAF00D, HwAddr:0xE6583ADE8121540D, RSSI:-20 , LQI:0  , ProtoId:3  , Version: 0, ShortAddr:0xFFFF
wpantund[22908]: State change: "offline" -> "associating"
wpantund[22908]: State change: "associating" -> "associated"
wpantund[22908]: Node type change: "unknown" -> "end-device"

You've successfully simulated your first Thread network using OpenThread. Awesome!

In this Codelab you learned how to:

If you want to learn more, explore these references: