Connecting TTN to Azure Functions
Posted by: mbmadmin | | 1 Comment »
The Things Network and Microsoft Azure Functions
Overview
We love The Things Network for low power LoRaWAN-based IoT hardware and we love Microsoft Azure Functions for server-less data processing. This article shows how to use them together.
The process involves creating an Azure Function to act as a webhook and then using the TTN webhook integration to send data to that function when data arrives from your devices. Further, the Azure Function can also send data back to the IoT device using the TTN integration, in the other direction (aka downlink.)
Create a Webhook-based Azure Function
Sign-in to your Azure Portal and add a ‘Function App’, choose the appropriate pricing model.
Inside your newly created Function App add a new function. This will show a list of function templates, find the HTTP Trigger function (in your preferred language – we’ll be using C#) and add it to the Function App. (You could probably use a Generic Webhook too but the Trigger template works nicely.)
The default sample code looks like this…
This function handles a web request, finds a ‘name’ parameter and returns a response saying ‘Hello Name’. However, in our case, we want to take the JSON that comes from the TTN integration and processes it. Firstly, you’ll need to add some libraries to the code, add this to the top of your code…
#r "Newtonsoft.Json"
using Newtonsoft.Json;
using System.Text;
using System.Net;
// Get request body
dynamic reqbody = await req.Content.ReadAsAsync<object>();
byte[] data = Convert.FromBase64String((string)reqbody.payload_raw);
string decodedString = Encoding.UTF8.GetString(data);
This gives us a ‘reqbody’ object that contains all the data from TTN’s JSON and a ‘decodedString’ string that contains JSON of the data from your devices. The JSON structure of the TTN uplink can be found here – https://www.thethingsnetwork.org/docs/applications/http/. Most of the message is to do with the LoRaWAN and TTN network itself, it’s only “payload_raw” (and “payload_fields”) that actually contain the data from your devices. In our case, we only get “payload_raw”, this is a Base64-encoded JSON object which our code converts to ‘decodeString’ for use in your Azure Function.
This line will send the data from the devices and the TTN device ID to the log. (You can see the function logs by expanding the ‘Logs’ panel at the bottom of the function page.)
log.Info("Data: " + decodedString + " " + reqbody.dev_id);
Create a TTN Webhook Integration
You’ll want to take a look at the TTN documentation link as there’s useful stuff in there. For now, enter a sensible name of your integration in ‘Process ID’, then choose ‘default key’ in ‘Access Key’ field. The URL comes from your Azure Function so go back to your Azure portal and find the ‘</> Get function URL’ (top right) on your function source code page. Copy the URL to the clipboard, it’ll look something like this…
https://<your-app-service-name>.azurewebsites.net/api/<your-trigger-function-name>?code=<your-function-key>
Switch back to the TTN integration page and paste that URL into the ‘URL’ field. Leave all the other fields blank and save your new integration.
Uplink Testing
You now need to make your devices send some data, the TTN integration will then call your Azure Function using the URL you gave it and you’ll be able to see those function calls in the Log panel of the function portal. In our example a function log looks like this…
2017-12-15T15:24:52.146 Function started (Id=2d52f339-8c9c-487f-a58d-aad93349535f) 2017-12-15T15:24:52.146 C# HTTP trigger function processed a request. 2017-12-15T15:24:52.146 Data: {"distance": 52, "speed": "25"} pycom_lopy_01 2017-12-15T15:24:52.177 Function completed (Success, Id=2d52f339-8c9c-487f-a58d-aad93349535f, Duration=28ms)
You can see ‘distance’ and ‘speed’ data that came from the Pycom LoPy device in the TTN JSON’s message in the payload_raw element.
Sending Data Back – TTN Downlink
You can use your Azure Function (or Azure in general) to send data back to your IoT devices via the TTN integration. Each TTN JSON upload message has an element known as ‘downlink_url’, it’s this that contains the webhook URL to use to send a reply back to the device sending data. This next piece of code, builds a as JSON upload message in the correct format for TTN and sends it to the downlink_url mentioned in the initial message.
Here’s my code to send a reply (known as an downlink)…
// Sending Reply // Get the downlink URL from the uplink message Uri ourUri = new Uri((string)reqbody.downlink_url); // Create a .NET web request WebRequest request = WebRequest.Create(ourUri); request.Method = "POST"; // We're going to use a random number to set the colour of the LoPy's LED Random rnd = new Random(); int r = rnd.Next(1,16777216); // Build the JSON that the device will interpret string replyJSON = @"{""colour"": " + r + "}"; // Build the TTN JSON downlink message. Notice the Base64 conversion for the device message JSON string postData = @"{""dev_id"": """ + reqbody.dev_id + @""",""port"": " + reqbody.port + @", ""confirmed"": false, ""payload_raw"": """ + Convert.ToBase64String(Encoding.UTF8.GetBytes(replyJSON)) + @"""}"; log.Info("Response: " + postData); byte[] byteArray = Encoding.UTF8.GetBytes(postData); // Set the ContentType property of the WebRequest. request.ContentType = "application/x-www-form-urlencoded"; // Set the ContentLength property of the WebRequest. request.ContentLength = byteArray.Length; // Get the request stream. Stream dataStream = request.GetRequestStream(); // Write the data to the request stream. dataStream.Write (byteArray, 0, byteArray.Length); // Close the Stream object. dataStream.Close(); WebResponse response = request.GetResponse();
C# is not my first language so this could be prettier but it builds a downlink message and sends it back to TTN. When the device next connects to TTN, this message will be delivered and the device can act upon it… in our case, change the colour of its LED. It would be good form to monitor the WebResponse from TTN to make sure all is well but we ignore it at the moment.
Conclusion
We like Azure Functions because they are powerful, flexible and scalable and it’s nice to be able to wire-up TTN so that the process is seamless. We’ve not yet deployed this into a live IoT project but we’ve no doubt that it will run successfully and give you very little trouble.
Author
Jason Timmins – Technical Director – MBM Ltd – jason@mbmltd.co.uk
1 Comment
Arjan
Nice article. One note:
> “payload_raw”, this is a Base64-encoded JSON object
True when the node sends JSON, but to save bandwidth a node should not send text, let alone JSON.
TTN uses Base64 encoding for the raw payload to allow nodes to transmit binary data, which then does not decode to JSON. Instead, one can decode that into an array of bytes, and process those.