Deploying a LoRaWAN network server on Azure

There is something oddly fascinating about radio waves, radio communications, and the sheer amount of innovations they’ve enabled since the end of the 19th century.

What I find even more fascinating is that it is now very easy for anyone to get hands-on experience with radio technologies such as LPWAN (Low-Power Wide Area Network, a technology that allows connecting pieces of equipment over a low-power, long-range, secure radio network) in the context of building connected products.

A portrait of Heinrich Rudolf Hertz

It’s of no use whatsoever […] this is just an experiment that proves Maestro Maxwell was right—we just have these mysterious electromagnetic waves that we cannot see with the naked eye. But they are there.

— Heinrich Hertz, about the practical importance of his radio wave experiments

LG02 Indoor LoRaWAN Gateway from Dragino, available for less than $100.

Nowadays, not only is there a wide variety of hardware developer kits, gateways, and radio modules to help you with the hardware/radio aspect of LPWAN radio communications, but there is also open-source software that allows you to build and operate your very own network. Read on as I will be giving you some insights into what it takes to set up a full-blown LoRaWAN network server in the cloud!

A quick refresher on LoRaWAN

LoRaWAN is a low-power wide-area network (LPWAN) technology that uses the LoRa radio protocol to allow long-range transmissions between IoT devices and the Internet. LoRa itself uses a form of chirp spread spectrum modulation which, combined with error correction techniques, allows for very high link budgets—in other terms: the ability to cover very long ranges!

Data sent by LoRaWAN end devices gets picked up by gateways nearby and is then routed to a so-called network server. The network server de-duplicates packets (several gateways may have “seen” and forwarded the same radio packet), performs security checks, and eventually routes the information to its actual destination, i.e. the application the devices are sending data to.

Bosch’s Smart Parking Lot sensor.

LoRaWAN end nodes are usually pretty “dumb”, battery-powered, devices (ex. soil moisture sensor, parking occupancy, …), that have very limited knowledge of their radio environment. For example, a node may be in close proximity to a gateway, and yet transmit radio packets with much more transmission power than necessary, wasting precious battery energy in the process. Therefore, one of the duties of a LoRaWAN network server is to consolidate various metrics collected from the field gateways to optimize the network. If a gateway is telling the network server it is getting a really strong signal from a sensor, it might make sense to send a downlink packet to that device so that it can try using slightly less power for future transmissions.

As LoRa uses an unlicensed spectrum and granted one follows their local radio regulations, anyone can freely connect LoRa devices, or even operate their own network.

My private LoRaWAN server, why?

The LoRaWAN specification puts a really strong focus on security, and by no means do I want to make you think that rolling out your own networking infrastructure is mandatory to make your LoRaWAN solution secure. In fact, LoRaWAN has a pretty elegant way of securing communications, while keeping the protocol lightweight. There is a lot of literature on the topic that I encourage you to read but, in a nutshell, the protocol makes it almost impossible for malicious actors to impersonate your devices (messages are signed and protected against replay attacks) or access your data (your application data is seen by the network server as an opaque, ciphered, payload).

So why should you bother about rolling your ow LoRaWAN network server anyway?

Coverage where you need it

In most cases, relying on a public network operator means being dependant on their coverage. While some operators might allow a hybrid model where you can attach your own gateways to their network, and hence extend the coverage right where you need it, oftentimes you don’t get to decide how well a particular geographical area will be covered by a given operator.

When rolling out your own network server, you end up managing your own fleet of gateways, bringing you more flexibility in terms of coverage, network redundancy, etc.

Data ownership

While operating your own server will not necessarily add a lot in terms of pure security (after all, your LoRaWAN packets are hanging in the open air a good chunk of their lifetime anyway!), being your own operator definitely brings you more flexibility to know and control what happens to your data once it’s reached the Internet.

What about the downsides?

It goes without saying that operating your network is no small feat, and you should obviously do your due diligence with regards to the potential challenges, risks, and costs associated with keeping your network up and running.

Anyway, it is now high time I tell you how you’d go about rolling out your own LoRaWAN network, right?

The Things Stack on Azure

The Things Stack is an open-source LoRaWAN network server that supports all versions of the LoRaWAN specification and operation modes. It is actively being maintained by The Things Industries and is the underlying core of their commercial offerings.

A typical/minimal deployment of The Things Stack network server relies on roughly three pillars:

  • A Redis in-memory data store for supporting the operation of the network ;
  • An SQL database (PostgreSQL or CockroachDB are supported) for storing information regarding the gateways, devices, and users of thje network ;
  • The actual stack, running the different services that power the web console, the network server itself, etc.

The deployment model recommended for someone interested in quickly testing out The Things Stack is to use their Docker Compose configuration. It fires up all the services mentioned above as Docker containers on the same machine. Pretty cool for testing, but not so much for a production environment: who is going to keep those Redis and PostgreSQL services available 24/7, properly backed up, etc.?

I have put together a set of instructions and a deployment template that aim at showing how a LoRaWAN server based on The Things Stack and running in Azure could look like.

The Things Stack running on Azure – Deployment diagram.

The instructions in the GitHub repository linked below should be all you need to get your very own server up and running!

In fact, you only have a handful of parameters to tweak (what fancy nickname to give your server, credentials for the admin user, …) and the deployment template will do the rest!

OK, I deployed my network server in Azure, now what?

Just to enumerate a few, here are some of the things that having your own network server, running in your own Azure subscription, will enable. Some will sound oddly specific if you don’t have a lot of experience with LoRaWAN yet, but they are important nevertheless. You can:

  • benefit from managed Redis and PostgreSQL services, and not have to worry about potential security fixes that would need to be rolled out, or about performing regular backups, etc. ;
  • control what LoRaWAN gateways can connect to your network server, as you can tweak your Network Security Group to only allow specific IPs to connect to the UDP packet forwarder endpoint of your network server ;
  • completely isolate the internals of your network server from the public Internet (including the Application Server if you which so), putting you in a better position to control and secure your business data ;
  • scale your infrastructure up or down as the size and complexity of the fleet that you are managing evolves ;
  • … and there is probably so much more. I’m actually curious to hear in the comments below about other benefits (or downsides, for that matter) you’d see.

I started to put together an FAQ in the GitHub repository so, hopefully, your most obvious questions are already answered there. However, there is one that I thought was worth calling out in this post, which is: How big of a fleet can I connect?.

It turns out that even a reasonably small VM like the one used in the deployment template—2 vCPUs, 4GB of RAM—can already handle thousands of nodes, and hundreds of gateways. You may find this LoRaWAN traffic simulation tool that I wrote helpful in case you’d want to conduct your own stress testing experiments.

What’s next?

You should definitely expect more from me when it comes to other LoRaWAN related articles in the future. From leveraging DTDL for simplifying end application development and interoperability with other solutions, to integrating with Azure IoT services, there’s definitely a lot more to cover. Stay tuned, and please let me know in the comments of other related topics you’d like to see covered!

Embedded IoT

Using Github Codespaces for Embedded Development

Managing an embedded development environment can be pretty painful and error-prone, from properly checking out the codebase and all its dependencies, to making sure the correct (and often pretty big!) toolchains are setup and used, to having the developers’ IDE use the right set of extensions and plugins.

When you start thinking of containers as a technology that can be used not only for runtime (ex. for packaging microservices) but also at development time, it becomes possible to easily describe the entirety of the required development environment for a particular project. Make this description part of your source code repository and you end up with a versioned, fully reproducible, dev environment! Hey, using a cloud-based IDE surely you should even be able to code straight from your web browser, right?

I recently gave GitHub Codespaces a try to get a sense of the benefits of the approach. Spoiler alert: there is already a lot that can be done (debugging embedded code from your web browser anyone?), so I am really excited to see what’s ahead of us in terms of making embedded development even more seamless.

I highly encourage you to give Codespaces a try and see for yourself what you think might be missing in the picture. I would love to hear about it!

A good way for you to get started if you have STM32L4 developer kit handy would be to go with the Azure RTOS getting started example, like I did in the video. Don’t forget to check the debugging instructions—they complement what you see in the video nicely.


Connecting the Wio Terminal to Azure IoT

It’s been a few months now since I started playing with the Wio Terminal from Seeed Studio. It is a pretty complete device that can be used to power a wide range of IoT solutions—just look at its specifications!

Wio Terminal Features
  • Cortex-M4F running at 120MHz (can be overclocked to 200MHz) from Microchip (ATSAMD51P19) ;
  • 192 KB of RAM, 4MB of Flash ;
  • Wireless connectivity: WiFi 2.4 & 5 GHz  (802.11 a/b/g/n), BLE, BLE 5.0, powered by a Realtek RTL8720DN module ;
  • 2.4″ LCD screen, 320×240 pixels ;
  • microSD card reader ;
  • Built-in sensors and actuators: light sensor, LIS3DH accelerometer, infrared emitter, microphone, buzzer, 5-way switch ;
  • Expansion ports: 2x Grove ports, 1x Raspberry-Pi compatible 40-pin header.

Wireless connectivity, extensibility, processing power… on paper, the Wio Terminal must be the ideal platform for IoT development, right? Well, ironically, one thing it doesn’t do out-of-the-box is to actually connect to an IoT cloud platform!

You will have guessed it by now… In this blog post, you’ll learn how to connect your Wio Terminal to Azure IoT. More importantly, you will learn about the steps I followed, giving you all the information you need in order to port the Azure IoT Embedded C libraries to your own IoT device.

Connecting your Wio Terminal to Azure IoT

I have put together a sample application that should get you started in no time.

You will need a Wio Terminal, of course, an Azure IoT Hub instance, and a working Wi-Fi connection. The Wio Terminal will need to be connected to your computer over USB—kudos to Seeed Studio for providing a USB-C port, by the way!—so it can be programmed.

Here are the steps you should follow to get your Wio Terminal connected to Azure IoT Hub:

  1. If you don’t have an Azure subscriptioncreate one for free before you begin.
  2. Create an IoT Hub and register a new device (i.e. your Wio Terminal). Using the Azure portal is probably the most beginner-friendly method, but you can also use the Azure CLI or the VS Code extension. The sample uses symmetric keys for auhentication.
  3. Clone and open the sample repository in VS Code, making sure you have the PlatformIO extension installed.
  4. Update the application settings (include/config.h) file with your Wi-Fi, IoT Hub URL, and device credentials.
  5. Flash your Wio Terminal. Use the command palette (Windows/Linux: Ctrl+Shift+P / macOS: ⇧⌘P) to execute the PlatformIO: Upload command. The operation will probably take a while to complete as the Wio Terminal toolchain and the dependencies of the sample application are downloaded, and the code is compiled and uploaded to the device.
  6. Once the code has been uploaded successfully, your Wio Terminal LCD should turn on and start logging connection traces.
    You can also open the PlatformIO serial monitor to check the logs of the application (PlatformIO: Serial Monitor command).
> Executing task: C:\Users\kartben\.platformio\penv\Scripts\platformio.exe device monitor <
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at
--- Miniterm on COM4  9600,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Connecting to SSID: WiFi-Benjamin5G
Connecting to Azure IoT Hub...

Your device should now be sending its accelerometer sensor values to Azure IoT Hub every 2 seconds, and be ready to receive commands remotely sent to ring its buzzer.

Please refer to the application’s README to learn how to test that the sample is working properly using Azure IoT Explorer.

It is important to mention that this sample application is compatible with IoT Plug and Play. It means that there is a clear and documented contract of the kind of messages the Wio Terminal may send (telemetry) or receive (commands).

You can see the model of this contract below—it is rather straightforward. It’s been authored using the dedicated VS Code extension for DTDL, the Digital Twin Description Language.

  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:seeed:wioterminal;1",
  "@type": "Interface",
  "displayName": "Seeed Studio Wio Terminal",
  "contents": [
      "@type": [
      "unit": "gForce",
      "name": "imu",
      "schema": {
        "@type": "Object",
        "fields": [
            "name": "x",
            "displayName": "IMU X",
            "schema": "double"
            "name": "y",
            "displayName": "IMU Y",
            "schema": "double"
            "name": "z",
            "displayName": "IMU Z",
            "schema": "double"
      "@type": "Command",
      "name": "ringBuzzer",
      "displayName": "Ring buzzer",
      "description": "Rings the Wio Terminal's built-in buzzer",
      "request": {
        "name": "duration",
        "displayName": "Duration",
        "description": "Number of milliseconds to ring the buzzer for.",
        "schema": "integer"

When connecting to IoT Hub, the Wio Terminal sample application “introduces itself” as conforming to the dtmi:seeed:wioterminal;1 model.

This allows you (or anyone who will be creating IoT applications integrating with your device, really) to be sure there won’t be any impedence mismatch between the way your device talks and expects to be talked to, and what your IoT application does.

A great example of why being able to automagically match a device to a corresponding DTDL model is useful can be illustrated with the way we used the Azure IoT Explorer earlier. Since the device “introduced itself” when connecting to IoT Hub, and since Azure IoT Explorer has a local copy of the model, it automatically showed us a dedicated UI for sending the ringBuzzer command!

Thanks to IoT Plug and Play, any application or tool can easily leverage the model that describes a device’s capabilities to.
Here, Azure IoT Explorer uses the model to help the user send commands that the device can actually understand.

Azure SDK for Embedded C

In the past, adding support for Azure IoT to an IoT device using the C programming language required to either use the rather monolithic (ex. it is not trivial to bring your own TCP/IP or TLS stack) Azure IoT C SDK, or to implement everything from scratch using the public documentation of Azure IoT’s MQTT front-end for devices.

Enter the Azure SDK for Embedded C!

The Azure SDK for Embedded C is designed to allow small embedded (IoT) devices to communicate with Azure services.

The Azure SDK team has recently started to put together a C SDK that specifically targets embedded and constrained devices. It provides a generic, platform-independent, infrastructure for manipulating buffers, logging, JSON serialization/deserialization, and more. On top of this lightweight infrastructure, client libraries for e.g Azure Storage or Azure IoT have been developed.

You can read more on the Azure IoT client library here, but in a nutshell, here’s what I had to implement in order to use it on the Wio Terminal connected:

  • As the sample uses symmetric keys to authenticate, we need to be able to generate a security token.
    • The token needs to have an expiration date (typically set to a few hours in the future), so we need to know the current date and time. We use an NTP library to get the current time from a time server.
    • The token includes an HMAC-SHA256 signature string that needs to be base64-encoded. Luckily, the recommended WiFi+TLS stack for the Wio Terminal already includes Mbed TLS, making it relatively simple to compute HMAC signatures (ex. mbedtls_md_hmac_starts) and perform base64 encoding (ex. mbedtls_base64_encode).
  • The Azure IoT client library helps with crafting MQTT topics that follow the Azure IoT conventions. However, you still need to provide your own MQTT implementation. In fact, this is a major difference with the historical Azure IoT C SDK, for which the MQTT implementation was baked into it. Since it is widely supported and just worked out-of-the-box, the sample application uses the PubSubClient MQTT library from Nick O’Leary.
  • And of course, one must implement their own application logic. In the context of the sample application, this meant using the Wio Terminal’s IMU driver to get acceleration data every 2 seconds, and hooking up the ringBuzzer command to actual embedded code that… rings the buzzer.


I hope you found this post useful! I will soon publish additional articles that go beyond the simple “Hey, my Wio Terminal can send accelerometer data to the cloud!” to more advanced use cases such as remote firmware upgrade. Stay tuned! 🙂

Let me know in the comments what you’ve done (or will be doing!) with your Wio Terminal, and also don’t hesitate to ask any burning question you may have.

If you liked this article, don’t forget to subscribe to be notified of upcoming publications. And of course, you can also always find me on Twitter.