LoRaWAN Bridge

From AllWize Wiki
Revision as of 12:35, 20 August 2019 by Allwize (talk | contribs) (Sending a LoRaWAN message over Wize)
Jump to navigation Jump to search

A LoRaWAN Network Server (LNS) is the piece of the LoRaWAN stack responsible for de-duplicating messages and route them to the Application Server where the user can configure the appropriate handlers to send the data to depending on the device address of the source node. Most of the servers available, including the The Things Network LNS and the LoRaServer open-source LNS support the Semtech Legacy Protocol. This protocol is a simple way to send data from a LoRaWAN Gateway to the LNS using UDP.


LoRaWAN Frame Format

The Semtech Legacy Protocol is open-spec and fairy simple so we can actually use it to send data to a LNS from wherever we want, the only requirement is that the data must be a LoRaWAN-compatible frame so the LNS can understand it. This is what a LoRaWAN frame looks like:

LoRaWAN Frame

The first row is the raw LoRa frame we don't have to worry about, the PHY Payload is the MAC part of the frame. In order:

  • MAC Header (type of message, version of the protocol,... for instance: 0x40 means unconfirmed uplink)
  • Device Address (the source device address)
  • Frame Control (LoRaWAN specific control bits: ACK, ADR, device class,...)
  • Frame Counter (a 16-bit autoincrement number)
  • Frame Options (LoRaWAN MAC options)
  • Frame Port (used to tell the frame payload format)
  • Frame Payload (the data, often LLP since the Application Server already have a decoder)
  • MIC (Message Integrity Code, used by the LNS to check the message is valid)

Wize Frame Format

A Wize frame looks like this. Encryption is optional unlike in LoRaWAN.

LoRaWAN Frame

Sending a LoRaWAN message over Wize

Of course the simpler option would be to encapsulate a LoRaWAN message inside the Wize Payload, but the total payload would have a lot of duplicated or fixed data:

LoRaWAN Wize Size Notes
MAC Header - 1 Always 0x40 in our case
Device Address A-Field 4
Frame Control - 1 Always 0x00 in our case
Frame Counter L6-Cpt 2
Frame Port L6-App 1

As you can see we can actually map up to 7 bytes of the LoRAWAN frame to Wize specific frame bytes, and two more bytes are fixed since we are only able to do unconfirmed uplinks at the moment. Then just add the Frame Payload (encrypted using the Application Session Key) and the MIC (encrypted using the Network Session Key).

And this is what the AllWize_LoRaWAN class does:

  • Encrypts the payload using the Application Session Key
  • Generates the Message Integrity Code (MIC) using the Network Session Key
  • Configures the radio module to use a specific C-field (0x80)
  • Maps the LoRaWAN fields to Wize values
  • Sends only the required bytes

The same class can the be used in the receiver to rebuild the LoRaWAN Frame and forward the contents to a LoRaWAN Network Server using Semtech Legacy Protocol.


The code examples here are part of the LoRaWAN examples you can find with the AllWize library: lorawan_gateway and lorawan_node.


Using the AllWize_LoRaWAN class is very simple. First we add it to our sketch and instantiate an object, this code will work on an AllWize K2 board:

#include "AllWize_LoRaWAN.h"
AllWize_LoRaWAN allwize(&SerialWize, PIN_WIZE_RESET);

Next you will need to initialize the Wize radio, the same way we are doing in all the examples:

if (!allwize.waitForReady()) {
    SerialUSB.println("[WIZE] Error connecting to the module, check your wiring!");
    while (true);
allwize.setChannel(CHANNEL_04, true);

Now we are going to configure the LoRaWAN part, this is done very similar to other LoRaWAN libraries out there:

uint8_t DEVADDR[4] = { 0x26, 0x01, 0x13, 0x3D };
uint8_t NWKSKEY[16] = { 0xF6, 0x59, 0x13, 0x16, 0x99, 0x35, 0x0E, 0xBF, 0x41, 0xE5, 0xEA, 0xA6, 0x95, 0xFE, 0x64, 0x27 };
uint8_t APPSKEY[16] = { 0xA2, 0x40, 0xE9, 0xF6, 0xB1, 0xB1, 0x3B, 0x53, 0xB1, 0xE2, 0x0A, 0x0D, 0x3D, 0x50, 0x74, 0xCB };

Finally we can start sending data. Here we are using CayenneLPP to encode the payload since most LoRaWAN Application Server already have a decoder for it. We will need to include the library first:

#include "CayenneLPP.h"

And the this code can go into your main loop:

CayenneLPP lpp(32);
lpp.addTemperature(1, getTemperature());
lpp.addRelativeHumidity(2, getHumidity());
lpp.addBarometricPressure(3, getPressure());
if (!allwize.send(lpp.getBuffer(), lpp.getSize(), 1)) {
    SerialUSB.println("[WIZE] Error sending message");


The Gateway part is a little more involved since it has to:

  • Connect to the Wize radio module using the AllWize_LoRAWAN class to get correct LoRaWAN frames
  • Connect to a local WiFi router to gain Internet access
  • Query a NTP server to get current time
  • Encode the messages using Semtech's Legacy Protocol and send them to a LoRaWAN Network Server

You can check the full example in the lorawa_gateway folder in the repository, but here you have some important things to remember:

  • Use the AllWize_LoRaWAN class, that will rebuild and return the original LoRaWAN frame
  • Use the same channel and datarate in the Wize configuration as your nodes, otherwise the gateway won't receive the messages
  • Create an account on a LoRaWAN Network Server (if you don't already have one), you will need to know the IP and port (usually the 1700) to send the UDP packets to
  • Create a device in the LoRaWAN Application Server, configure it for ABP actvation and copy the DevAddr, NwkSKey and AppSKey to the node code.