Sending Messages to Azure IoT Hub

July 21, 2018

Although I use many of the Azure services as part of my day job as a web developer, one I’ve never had the chance to use is their Internet of Things (IoT) offering. This post seeks to remedy that by creating a simulated IoT device then using it to send telemetry data to the Azure IoT hub.

The Azure IoT hub allows the provisioning and control of millions of IoT devices, as well as providing a central point to manage two-way secure communications between devices and other Azure services.

In order to test out the IoT hub we will follow these steps:

  • Create an IoT hub in Azure
  • Register a device in our IoT hub
  • Build a simulated device using Go, the Gobot framework, and the MQTT protocol
  • Send messages from our simulated client to the IoT hub and check that the messages are received.
  • A future post will cover routing messages into other Azure services.

Create the Iot Hub

I used the Azure CLI to handle the creation of resources. If you don’t already have it installed, it is available here. After installing the CLI, install the IoT extensions by running the following command, which adds some additional commands for interacting with the Azure IoT services.

az extension add --name azure-cli-iot-ext

Create a new Resource Group and a new IoT Hub. Not all features of the IoT Hub are currently supported in all regions, so it it important to create the resource group in a region that offers all features. I normally create resources in the UK South region, but the Events feature of the IoT Hub is not currently available there. The nearest region offering all features is West Europe. The following commands create a new Resource Group called ‘iot’ in the West Europe region, then creates a new IoT Hub called ‘my-iot-hub’ in the Resource Group ‘iot’ using the free plan ‘f1’.

az group create --name iot --location westeurope
az iot hub create -resource-group iot --name my-iot-hub --sku f1

Then retrieve the connection string for the IoT Hub, which we will need later,

az iot hub show-connection-string --hub-name my-iot-hub --output tsv

which will return something that looks something like this.

HostName=my-iot-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=xxxxx...xxxxx

Create the client Device

Before we create the client device, it is worthing installing the Azure Device Explorer. The Device Explorer makes it easy to generate a password that our device will use to connect to the Iot Hub. It will also allow us to monitor the Iot Hub for any messages received from our device.

Create a new device called ‘goclient’ in our newly created Iot Hub

az iot hub device-identity create --hub-name my-iot-hub --device-id goclient

then launch the Device Explorer. Connect to the Iot Hub by pasting the Iot Hub connection string from earlier into the “Iot Hub Connection String” box, and clicking the “Update” button on the Configuration tab.

Device Explorer Configuration Tab

We can then use the Device Explorer to generate a Shared Access Signature (SAS) token, part of which will be used as the password when connecting the device to the IoT Hub. To generate an SAS token, follow these steps

  • Click the managment tab
  • The new device should be listed
  • Click on the device, then click the “SAS Token…” button

Device Explorer Management Tab

  • In the dialog box that pops up, set the TTL to 1 day
  • Click the generate button

Generate SAS Token Dialog Box

  • From the generated SAS token, copy everything from the second SharedAccessSignature until the end to use as the device connection password.

The Code

The client device will not be an actual physical device, but a simulated device written as a simple Go program. One of the things that helps keep this process simple is the robot abstraction implemented in the Gobot package, which allows us to define a piece of work for our device to perform repeatedly based on a time interval. It also offers an abstration over the MQTT protocol (based on the excellent MQTT package written by the Eclipse Foundation), which is used to communicate with the Iot Hub.

Using MQTT to connect to an Azure IoT Hub has several additional restrictions:

  • Connections must use TLS/SSL, so must use port 8883.
  • Azure uses the Baltimore Root CA certificate to secure the connection, so that must also be used by the client device. The Baltimore Root CA certificate is available here.
  • Quality of Service (QoS) level 2 messages are not supported.
  • The only available topic is devices/{device_id}/messages/events

I’ve used environment variables to hold the values to be used for the username, password, hostname and device id needed to make the connection to the IoT hub, which take the following format:

  • MQTT_HOST - this is the url of the Iot Hub, for example, my-iot-hub.azure-devices.net.
  • MQTT_DEVICE - the device id of the client device, for example, goclient.
  • MQTT_USERNAME - the username is made up using the format {iot_hub_url}/{device_id}/api-version=2016-11-14, for example, my-iot-hub.azure-devices.net/goclient/api-version=2016-11-14.
  • MQTT_PASSWORD - this is password we generated earlier as part of the SAS token in the Device Explorer.
package main

import (
	"fmt"
	"os"
	"time"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/platforms/mqtt"
)

func main() {
	deviceID := os.Getenv("MQTT_DEVICE_ID")
	username := os.Getenv("MQTT_USERNAME")
	password := os.Getenv("MQTT_PASSWORD")
	host := os.Getenv("MQTT_HOST")
	
	// TLS/SSL MQTT port
	port := 8883

	brokerURL := fmt.Sprintf("tcps://%s:%d", host, port)

	mqttAdaptor := mqtt.NewAdaptorWithAuth(
		brokerURL,
		deviceID,
		username,
		password,
	)

	// load the Baltimore Root CA certificate
	mqttAdaptor.SetServerCert("BaltimoreRootCertificate.cer")
	
	// Force the use of TLS/SSL
	mqttAdaptor.SetUseSSL(true)

	err := mqttAdaptor.Connect()

	work := func() {

		// message payload
		data := []byte("hello")

		// topic must be devices/{device_id}/messages/events
		eventTopic := fmt.Sprintf("devices/%s/messages/events/", deviceID)

		// send the message payload to the topic every 5 seconds
		gobot.Every(5*time.Second, func() {
			fmt.Printf("Sending '%s' to IoT Hub topic %s\n", data, eventTopic)
			mqttAdaptor.Publish(eventTopic, data)
		})
	}

	robot := gobot.NewRobot("azbot",
		[]gobot.Connection{mqttAdaptor},
		work,
	)

	err = robot.Start()

	if err != nil {
		fmt.Println(err)
	}
}

Testing

All that is now left to do is test that our device can send messages to the IoT hub. Start the Device Explorer, if it is not already running, and click on the data tab. Select the device from the device drop down, the click the monitor button. The Device Explorer is now connected to the IoT Hub and is listening for messages from our device.

Now run the device code

go run main.go

and our device will send the message “hello” to the IoT Hub every 5 seconds. These messages will show up in the Device Explorer as in the following image

Monitor messages

Coming Up

In the next post, I’ll take a look at routing device messages to Azure Functions, and then sending messages back to the device.

Copyright (c) 2018, all rights reserved.