OpenThread is...
...an open-source implementation of the Thread networking protocol. Nest has released OpenThread to make the technology used in Nest products more broadly available to developers to accelerate the development of products for the connected home.
...OS and platform agnostic, with a narrow platform abstraction layer and a small memory footprint, making it highly portable. It supports both system-on-chip (SoC) and network co-processor (NCP) designs.
...a Thread Certified Component, implementing all features defined in the Thread 1.1.1 specification, including 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.
More information about Thread can be found at threadgroup.org. Thread is a registered trademark of the Thread Group, Inc.
Cloud IoT Core is a fully managed service that allows you to easily and securely connect, manage, and ingest data from millions of globally dispersed devices. Cloud IoT Core, in combination with other services on Google Cloud platform, provides a complete solution for collecting, processing, analyzing, and visualizing IoT data in real time to support improved operational efficiency.
You will build a prototype of an IoT system with Google Cloud IoT Core. You will connect a simulated OpenThread device to internet via border router. The device will publish temperature data to their telemetry feeds, and a server consumes the telemetry data from a Cloud Pub/Sub topic. The server then decides whether to turn on or off the individual devices' fans, via a Cloud IoT Core configuration update.
This Codelab is designed to use Docker on a Linux machine.
Download and Install Docker for your linux distribution.
Once Docker is installed, open a terminal window and pull the openthread/codelab_otsim
Docker image. This image features OpenThread and wpantund
pre-built and ready to use for this Codelab.
docker pull openthread/codelab_cloudiot:latest
Note that it may take a few minutes to completely download.
Click the following link to open the end-to-end sample in Google Cloud Shell:
If you have already cloned the repo, input 1 to cd into the sample folder and then cd iot/api-client/end_to_end_example
; otherwise, enter the following command to `cd
` into the sample folder:
cd iot/api-client/end_to_end_example
Next, initialize virtual environment and install the sample dependencies:
virtualenv env && source env/bin/activate pip install -r requirements.txt
At this point, you can check that you have installed the Python dependencies correctly by running all the Python script without passing any parameters:
python cloudiot_pubsub_example_server.py
If the dependencies installed successfully, the programs will print their respective usage messages, for example:
usage: cloudiot_pubsub_example_server.py [-h] --project_id PROJECT_ID --pubsub_subscription PUBSUB_SUBSCRIPTION [--service_account_json SERVICE_ACCOUNT_JSON]
If you see an error similar to `ImportError: No module named ...`, go back and make sure you installed Virtual Environment correctly, or see the Python Development Environment Setup Guide for detailed information on using Python with Google Cloud. Now that you have the program libraries installed, it's time to set up your Google Cloud IoT Core project.
To ensure your Cloud shell has the latest versions of the Cloud IoT Core API installed, update the gcloud components.
gcloud components update
Open the Google Cloud Console and enable the API if it has not already been enabled on your Kiosk or Google account.
After you have enabled the API, select the current project to get your project ID.
The project name shown in the menu bar can differ from the project ID, so make sure you set it to the correct value.
gcloud config set project <your-project-id>
Create a Pub/Sub topic using the following gcloud command:
gcloud pubsub topics create tour-pub --project="${DEVSHELL_PROJECT_ID:-Cloud Shell}" gcloud pubsub subscriptions create tour-sub --topic=tour-pub
Create your Cloud IoT Device Registry using the following gcloud command:
gcloud iot registries create tour-registry \ --region=us-central1 --event-notification-config=topic=tour-pub
Next, you will need to generate RSA public and private keys that will be used for authenticating your virtual device when it connects.
openssl req -x509 -newkey rsa:2048 -days 3650 -keyout rsa_private.pem \ -nodes -out rsa_public.pem -subj "/CN=unused"
Make a copy of rsa private key onto your local host machine.
With your keys in hand, you're ready to register a device. Register your device using the public key.
gcloud iot devices create test-dev --region=us-central1 \ --registry=tour-registry \ --public-key path=rsa_public.pem,type=rs256
Congratulations, you have now set up Cloud Pub/Sub, created your device registry, and added a device to the registry!
Now that you have created all of the Cloud resources you need to connect your device and communicate with it via Pub/Sub, it's time to simulate a device and server.
Edit cloudiot_pubsub_example_server.py
and replace the code used to generate service account credentials from a provided JSON file to instead use the built-in credentials for Compute Engine, which is what is running under the hood of the Cloud Shell.
Replace the following code:
def __init__(self, service_account_json):
credentials = ServiceAccountCredentials.from_json_keyfile_name(
service_account_json, API_SCOPES)
With:
def __init__(self, service_account_json):
from google.auth import compute_engine
credentials = compute_engine.Credentials()
Now that you have changed the server to use the Compute Engine credentials, start the server using the following syntax:
python cloudiot_pubsub_example_server.py \ --project_id="PROJECT_ID" \ --pubsub_subscription=PUBSUB_SUBSCRIPTION
For example, if you used the example values in previous commands, the command is:
python cloudiot_pubsub_example_server.py \ --project_id="${DEVSHELL_PROJECT_ID:-Cloud Shell}" \ --pubsub_subscription=tour-sub
When the server starts, you will see the message "Listening for messages on projects/your-project-id/subscriptions/tour," which indicates the server is running.
docker run --sysctl \ "net.ipv6.conf.all.disable_ipv6=0 \ net.ipv4.conf.all.forwarding=1 \ net.ipv6.conf.all.forwarding=1" \ -it --privileged codelab_cloudiot
The entrypoint script will launch the OpenThread border router.
OTBR docker provides a web gui to manage Thread networks. We directly use the web api to form the Thread network. Inside docker container, run:
curl --header "Content-Type: application/json" --request POST --data \ '{"networkKey":"00112233445566778899aabbccddeeff","prefix":"fd11:22::","defaultRoute":true,"extPanId":"dead00beef00cafe","panId":"0x1234","passphrase":"123456","channel":11,"networkName":"OpenThread"}' \ http://127.0.0.1/form_network
ot-rtos is a library integrating OpenThread, lwIP and FreeRTOS to make task management and network development easy with OpenThread. We are using the linux simulation command line application provided in the repository so you can easily move to a real device with FreeRTOS support.
First copy the private key into docker container. On local host machine, run:
docker cp rsa_private.pem <codelab-container-id>:/app/
You can find docker container id by running:
docker ps
Inside docker run:
cd /app/ot-rtos mkdir build && cd build cmake .. -DPLATFORM_NAME=linux -DCLOUDIOT_DEVICE=test-dev \ -DCLOUDIOT_REGISTRY=tour-registry -DCLOUDIOT_PROJECT=<your project id> \ -DCLOUDIOT_REGION=us-central1 -DCLOUDIOT_PRIV_KEY=/app/rsa_private.pem make -j8
Now run the OpenThread command line application
cd ~/ot-rtos/build ./ot_cli_linux 2
If you don't see the >
prompt after running this command, press enter
.
Now connect the device to thread network:
> panid 0x1234 Done > ifconfig up Done > thread start Done
Wait for a few seconds for the device to connect itself to thread network. Then you can start publishing device status to Google Cloud IoT Core:
> test mqtt
The following section shows the output of the device that is transmitting its telemetry events to the server.
The device (test-dev) has a temperature of: -4 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -3 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -2 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -1 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: 0 The device (test-dev) has a temperature of: 1 The device (test-dev) has a temperature of: 2 The device (test-dev) has a temperature of: 3 The device (test-dev) has a temperature of: 4 The device (test-dev) has a temperature of: -4 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -3 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -2 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: -1 Setting fan state for device test-dev to off. The device (test-dev) has a temperature of: 0 The device (test-dev) has a temperature of: 1 The device (test-dev) has a temperature of: 2 The device (test-dev) has a temperature of: 3 The device (test-dev) has a temperature of: 4 The device (test-dev) has a temperature of: 5 The device (test-dev) has a temperature of: 6 The device (test-dev) has a temperature of: 7 The device (test-dev) has a temperature of: 8 The device (test-dev) has a temperature of: 9 The device (test-dev) has a temperature of: 10 The device (test-dev) has a temperature of: 11 Setting fan state for device test-dev to on. The device (test-dev) has a temperature of: 12 Setting fan state for device test-dev to on. The device (test-dev) has a temperature of: 13 Setting fan state for device test-dev to on.
The following section shows the output of the server that is subscribed to the telemetry events from the device.
Mqtt Connected Connect done data callback len=17 Topic /devices/test-dev/config get message len = 17 {"fan_on": false} data callback len=17 Topic /devices/test-dev/config get message len = 17 {"fan_on": false} Publish message: {"temperature": -4} Publish message: {"temperature": -3} data callback len=17 Topic /devices/test-dev/config get message len = 17 {"fan_on": false} Publish message: {"temperature": -2} data callback len=17 Topic /devices/test-dev/config get message len = 17 {"fan_on": false} Publish message: {"temperature": -1} data callback len=17 Topic /devices/test-dev/config get message len = 17 {"fan_on": false} Publish message: {"temperature": 0} Publish message: {"temperature": 1} Publish message: {"temperature": 2} Publish message: {"temperature": 3} Publish message: {"temperature": 4} Publish message: {"temperature": 5} Publish message: {"temperature": 6} Publish message: {"temperature": 7} Publish message: {"temperature": 8} Publish message: {"temperature": 9} Publish message: {"temperature": 10} Publish message: {"temperature": 11} data callback len=16 Topic /devices/test-dev/config get message len = 16 {"fan_on": true} Publish message: {"temperature": 12} data callback len=16 Topic /devices/test-dev/config get message len = 16 {"fan_on": true} Publish message: {"temperature": 13} data callback len=16 Topic /devices/test-dev/config get message len = 16 {"fan_on": true}
After you're finished with the codelab, run the following commands to clean up the resources you created on your Cloud account:
gcloud iot devices delete test-dev --region=us-central1 --registry=tour-registry gcloud iot registries delete tour-registry --region=us-central1 gcloud pubsub subscriptions delete tour-sub gcloud pubsub topics delete tour-pub