Use Azure IoT Hub without client libraries (MQTT)
This is the second last post of the series on IoT Communication which has gone on for slightly more than a month now. In this post, I endeavor to connect an IoT device to the Azure IoT Hub without using the provided IoT libraries.
WHY AZURE IOT HUB?
To many, this is a matter of personal preference more than it is of functionality. The Azure IoT Hub is more of a gateway than anything else. It will connect to your IoT devices while your other applications (e.g. management web interface etc.) connect to it. My reasons for choosing it:
- the per-device authentication features included. (Each device has its own authentication key)
- most of my other workloads are on Azure making easier to interface with other services like Stream Analytics.
AUTHENTICATION
As with many other Azure products, the documentation is ample on authentication schemes or procedures. If you use the client libraries provided by Microsoft, you do not need this step. Unfortunately, depending on the coding environment you have, using a prebuilt library may not work. For me, it kept failing numerously until I decided to do away with it.
Each device has a set of keys (a primary and a secondary one). To authenticate a device to the hub, an SAS (Shared Access Signature) token is required. This is normally done for us in the client libraries. So I used the C# client library to understand the process of generating SAS tokens for use with Azure IoT hub and then built a simple function to handle that on my pre-existing code. The SAS token forms the password used in the CONNECT packet for MQTT.
Generating the SAS Token
The steps for doing this may seem overwhelming at first but they really are not hard.
- Decode the device key, encoded in base 64, to plain bytes.
- Create the audience for your request in the format
{iot-hub-host-name}/devices/{device-id}
. Name the resultaud
. - Create an expiry time in seconds since Epoch (01-01-1970) by taking the current time and adding the duration for which the key will be in use. e.g. for Sunday, 13 March 11:00 PM will be 1457866800. You can use this utility to play around in case this is new stuff. Name this variable
exp
. - Create the request string in the format
{aud}\n{exp}
and encode it to base 64. - Perform HMAC-SHA256 on the request string using the device's primary key as the key to your HMAC engine. Name the result
signed
. - Make the complete token using the format:
SharedAccessSignature sr={aud}&sig={signed}&se={exp}&skn=
The CONNECT packet for MQTT
The other fields for authentication present in the CONNECT packet are ClientId and Username. As per the docs provided, the ClientId = deviceId and the Username has the format {iot-hub-host-name}/{device-id}
.
That is all that is required. Once it is working alright, the Azure IoT Hub will then work like any other MQTT broker. You should, however, make note of the MQTT topics used to send/receive telemetry to/from the IoT Hub.
I have only two files to do this sas_utils.c and url_encode.c. In them, the above steps are practically done.
These two files belong to the bigger group of changes in commit 70dce2a7 where there is specific code to communicate to the IoT Hub using MQTT. It is evident that the changes from the previous commit mainly relate to the authentication of the device.
- The Azure IoT Hub does not allow communication via the unsecured channel, 1883. We solved this by adding the mbedTLS library which provided TLS and in this blog post, was used to do hashing and base 64 encoding/decoding.
- In case of errors when connecting the device, capture the response to the CONNECT packet (a.k.a the CONNACK packet) and relate the response code to the MQTT spec.
- Do not consider the information here on the Azure IoT Hub as conclusive, but read on some more. There is a lot more available here.