Tutorials:
Sensors, interfaces and bus systems (SENIN, BUSSY)

LoRa and LoRaWan

last updated: 2021-03-17

Introduction

LoRa and LoRaWAN are two quite new technologies in the world IoT, growing in popularity every year.

LoRa stands for Long Range and allows low-powered devices to communicate over long range wireless connections. LoRa is located on the physical (PHY) layer (bits) of the OSI model.

LoRaWAN is a media access control (MAC) protocol for wide area networks. It can be mapped to the second and third layer of the OSI model (data link and network layer for physical and logical addressing (frames and packets)).

The LoRaWAN protocols are defined by the LoRa Alliance.

LoRa OSI

LoRaWAN allows e.g. LoRa devices to communicate with Internet-connected applications. It is implemented on top of LoRa or FSK modulation in ISM radio bands.

LoRa

Let's start with the physical layer LoRa.

LoRa stands for Long Range, and refers to a new radio technology designed for the IoT, increasing the radio range and using very little power.

LoRa beats other radio technologies like WiFi, ZigBee or Bluetooth in range and largely in power consumption (look here under comparing different wireless protocolls). So normally some 100 meters in buildings are no problem, and LoRa devices can run for months or even years on battery. The LoRa radio receiver is very sensitive. It may receive signals many times weaker (down to -160 dBm) than other wireless technologies.

To achieve this performance a LoRa node will wake up perhaps once an hour, and send tiny data packet containing data. So most of the time (99.99 %) the LoRa node would be in an ultra-low-power sleep.

All this comes with a significant cost: The bit rate of LoRa is very much lower than the bit rate of other wireless technologies. Compared to other technologies, the biggest difference you’ll notice with LoRa is that even the advertised data rates are really low. LoRa can, depending on the channel configuration, handle bit rates of between 250 bit/s and 11 kbit/s (Europe). Besides this, it is a half-duplex transmission, so we get half the data rate of the channel if we don't use both directions and we can use this data rate only 1 % of the time of a day (1 % duty cycle). This 1 % duty cycle reduces the effective data rate to 55 bits/s!

ISM band

LoRa communication uses small parts of the radio spectrum initially reserved internationally for Industrial, Scientific and Medical purposes other than telecommunications called ISM radio bands. Nowadays these bands are often used for short-range, low power wireless communications systems to avoid government licenses needed to transmit on other frequency bands. Communications equipment operating in ISM bands must tolerate any interference generated other ISM applications. In Europe to use the ISM band (863 MHz - 870 MHz) users must accept the following restrictions:

Besides these ISM band rules, the network operator (for example The Things Network) can also add additional restrictions.

LoRa properties and modulation

The radio part was developed by SEMTECH and is closed source.

CAD and TDMA

The LoRa radio has a feature which can wake it from a low power state when it detects the start of a message. Other radios need here a power consuming RSSI scan. This feature is called Channel Activity Detection (CAD) and allows a randomized Time-Division Multiple Access (TDMA).

TDMA allows several users to share the same frequency channel (ISM frequencies) by dividing the signal into different time slots. In LoRa the time-slots are generated asynchronously respecting the 1 % duty cycle. We rely on a statistical likelihood, that if devices only transmit for 1% of the time we can operate several devices at the same time without many collisions. So LoRa is designed for small packets of data sent infrequently, and we keep in mind, that LoRa does not guarantee message delivery (collisions may occur).

Power

The maximum transmit power in Europe is is limited by law to 25 mW. We must respect this if we built our own antennas with higher gain.

Radio Modulation and LoRa

LoRa uses a proprietary spread-spectrum modulation technique. It is derived from existing Chirp Spread Spectrum (CSS) technology and uses a fixed-bandwidth channel of either 125 KHz or 500 KHz. This big bandwidth allows to reduce power (Shannon).

The key LoRa modulation property is the [Spreading Factor SF].
With a higher spreading factor the energy of the total signal is spread over a wider range of frequencies, allowing the receiver to be more sensitive and to discern a signal with a lower signal-to-noise ratio (SNR) and so to increase the range.

Channel parameters

We get several channel parameters of a physical LoRa link that affect the signal conditions, the data rate and power constraints. These parameters must be the same for the sender and the transmitter, to be able to communicate.

Their are no real predefined channels. The Things Network (TTN) uses e.g. 868.1 MHz, 868.3 MHz and 868.5 MHz for their first 3 channels. It is important that the sender and the receiver use the same frequency!

LoRaWan

https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html

868.1 - SF7BW125 to SF12BW125 868.3 - SF7BW125 to SF12BW125 and SF7BW250 868.5 - SF7BW125 to SF12BW125 867.1 - SF7BW125 to SF12BW125 867.3 - SF7BW125 to SF12BW125 867.5 - SF7BW125 to SF12BW125 867.7 - SF7BW125 to SF12BW125 867.9 - SF7BW125 to SF12BW125 868.8 - FSK

Simple LoRa sender and LoRa receiver

We will start without gateway and WAN, with a simple radio communication.

Hardware

There exist many boards with a LoRa chip. In the following picture we see two Arduino shields (top right), one with supplementary GPS chip (Draguino). The left board, also with GPS has an ESP32 µC, as the board in the middle (bottom) with supplementary SD card slot and OLED display. The board at the right (bottom) is an Arduino (mega328) with LoRa but without USB/TTL chip.

lora boards

Frequency

LoRa uses the license-free industrial, scientific and medical (ISM) bands. For Europe we get 433 MHz, and 868 MHz (915 MHz for Australia and North America and 923 MHz for Asia). We choose 868 MHz because this band is exclusively reserved for communication between wireless sensor networks. It is less used than 433 MHz and it is less likely to be interfered.

Higher frequencies result in shorter wavelengths. Theoretically 433 MHz can travel a greater distance than 868 MHz, but because of disturbances this often is not true. The antennas for 868 MHz are shorter.

It is clear, that only chips with the same frequency can operate together.

Breakout board

The chips used are from SEMTECH. For own solutions we can use the SX1276 chip that can be bought on a breakout board RFM95W-V2.0 from hoperf (specification document). Unfortunately the board uses a 2 mm pin header pitch instead of the usually used 2.54 mm (0.1 in). So we need an additional breakout board to be able to use the chip on a breadboard.

lora breakout

lora breakout
Source: RFM95W-V2.0 specification document from hoperf

Connections:

Don't forget to connect the antenna before powering the board! Without antenna the board can be damaged!

If you don't have an antenna, use a wire with 8.2 cm in length.

The board uses the SPI interface (MISO, MOSI, SCK, SS (NSS)) to communicate with the microcontroller, and it is powered with 3.3 V (GND, +3.3 V). For SPI we usually use the pins of the default SPI interface for MISO, MOSI and SCK. With the function SPI.begin() it is possible to change if a second interface is available. The chip select pin is freely selectable. The library uses by default pin 5 for the Uno. The DI00 pin (RFM95W) must be connected to a pin supporting interrupts, because the LoRa chip signals an incoming message with this output to the microcontroller (default Uno pin 2). Same for DI01, needed only for LoRaWAN (pin 6 for UNO). An output pin of the microcontroller can also be used to reset (RESET pin) the LoRa chip if needed.

Even if we find schematics connecting the Arduino Uno directly to the RFM95W board, this is not a valabel solution! The output pins (MOSI, CLK etc.) of the Uno have 5 V! One solution can be to use level shifters like on the Dragino shield, or to use voltage dividers for all outputs. A simpler solution is an Arduino Uno with 3V by changing the voltage regulator. We will use ESP boards for our exercises.

LoRa Schield Arduino Uno (3V!) ESP8266 (Lolin/Wemos) ESP32
3.3V (Vin) 3.3V 3.3V 3.3V
GND GND GND GND
MOSI 11 14 23
MISO 12 12 19
SCK 13 13 18
NSS (SS, CS) 5 16 26
RST (Reset) 9 not connected or 2 not connected or 16
DIO0 (G0, IRQ) 2 15 5
DIO1 (G1, IRQ) 6 (only needed for LoRaWAN!) 0 (only needed for LoRaWAN!) 17 (only needed for LoRaWAN!)
DIO2-5 not connected not connected not connected
ANT antenna antenna antenna


lora breakout esp32

Software

We use the LoRa library from Sandeep Mistry. Information about the library can be found in the corresponding LoRa Application Programming Interface (API).

Here are two basic sketches for the sender (transmitter):

    /*
      lora_simple_sender_esp_868.ino
      ESP32:   MH ET LIVE ESP32-MINI-KIT  with RFM95W (SX1276)
      or ESP8266: LOLIN/WEMOS D1 mini pro with RFM95W (SX1276)
      CS(SS)=16/26, RST=2/16, DIO0(IRQ)=15/5, freq = 868MHz
      SPI (ESP default): MOSI=13/23, MISO=12/19, SCK=14/18

      MHET    | MHET    - LOLIN        |---| LOLIN      - MHET    | MHET

      GND     | RST     - RST          |---| TxD        - RxD(3)  | GND
       NC     | SVP(36) -  A0          |---| RxD        - TxD(1)  | 27
      SVN(39) | 26      -  D0(16)      |---|  D1(5,SCL) -  22     | 25
       35     | 18      -  D5(14,SCK)  |---|  D2(4,SDA) -  21     | 32
       33     | 19      -  D6(12,MISO) |---|  D3(0)     -  17     | TDI(12)
       34     | 23      -  D7(13,MOSI) |---|  D4(2,LED) -  16     | 4
      TMS(14) | 5       -  D8(15,SS)   |---| GND        - GND     | 0   
       NC     | 3V3     - 3V3          |---|  5V        -  5V     | 2
      SD2(9)  | TCK(13)                |---|              TD0(15) | SD1(8)
      CMD(11) | SD3(10)                |---|              SD0(7)  | CLK(6)
    */

    #include <SPI.h>
    #include <LoRa.h>

    #ifdef ESP8266
      const byte PIN_SS = 16;         // LoRa radio chip select
      const byte PIN_RST = NOT_A_PIN; // LoRa radio reset
      const byte PIN_IRQ = 15 ;       // hardware interrupt pin!
    #else
      const byte PIN_SS = 26;
      const byte PIN_RST = NOT_A_PIN;
      const byte PIN_IRQ = 5 ;
    #endif // #ifdef ESP8266

    //const byte PIN_SCK = 18;
    //const byte PIN_MISO = 19;
    //const byte PIN_MOSI = 23;

    int counter = 0;

    void setup() {
      Serial.begin(115200);
      Serial.println("LoRa sender\n");
      //SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_SS);   //SPI LoRa pins
      LoRa.setPins(PIN_SS, PIN_RST, PIN_IRQ);  // setup LoRa transceiver module
      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true);      //endless loop
      }
    }

    void loop() {
      Serial.print("Sending packet number: ");
      Serial.println(counter);
      LoRa.beginPacket();
      LoRa.print("This is packet number ");
      LoRa.print(counter);
      LoRa.endPacket();
      counter++;
      delay(60000);
    }

And the receiver:

    /*
      Lora simple receiver lora_receiver_esp_868.ino
      ESP32:   MH ET LIVE ESP32-MINI-KIT  with RFM95W (SX1276)
      or ESP8266: LOLIN/WEMOS D1 mini pro with RFM95W (SX1276)
      CS(SS)=16/26, RST=2/16, DIO0(IRQ)=15/5, freq = 868MHz
      SPI (ESP default): MOSI=13/23, MISO=12/19, SCK=14/18
    */

    #include <SPI.h>
    #include <LoRa.h>

    #ifdef ESP8266
      const byte PIN_SS = 16;         // LoRa radio chip select
      const byte PIN_RST = NOT_A_PIN; // LoRa radio reset
      const byte PIN_IRQ = 15 ;       // hardware interrupt pin!
    #else
      const byte PIN_SS = 26;
      const byte PIN_RST = NOT_A_PIN;
      const byte PIN_IRQ = 5 ;
    #endif // #ifdef ESP8266

    //const byte PIN_SCK = 18;
    //const byte PIN_MISO = 19;
    //const byte PIN_MOSI = 23;

    byte packet_size = 0;

    void setup() {
      Serial.begin(115200);
      delay(1000);
      Serial.println("LoRa receiver\n");
      //SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_SS);   //SPI LoRa pins
      LoRa.setPins(PIN_SS, PIN_RST, PIN_IRQ);  // setup LoRa transceiver module
      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true);                           // endless loop
      }
    }

    void loop() {
      packet_size = LoRa.parsePacket();         // try to parse packet
      if (packet_size) {  // received a packet
        Serial.print("Received packet with ");
        Serial.print(packet_size);
        Serial.print(" byte: '");
        while (LoRa.available()) {              // read packet
          Serial.print((char)LoRa.read());
        }
        Serial.print("' with RSSI = ");
        Serial.print(LoRa.packetRssi());
        Serial.println("dBm");
      }
    }

Note: If we use other pins than the library defaults to connect to our chip, we must declare this in the software:

    const byte PIN_SS = 5;                      // LoRa radio chip select
    const byte PIN_RST = 33;                    // LoRa radio reset
    const byte PIN_IRQ = 26;                    //  hardware interrupt pin!

    void setup() {
      ...
      LoRa.setPins(PIN_SS, PIN_RST, PIN_IRQ);  // setup LoRa transceiver module
      ...
    }
"Just do it" Lora 1:

Transceiver

The following sketch shows how a transceiver can be build with duplex communication and callbacks. Transmitter and receiver use a unique address (only 1 byte = 256 addresses, 0xFF for broadcast messages). The message gets an identifier (ID), realised in the sketch with a simple message counter. The delay time between sends is not static (randomized) to avoid collisions.

    /*
      lora_sender_esp_868_duplex.ino
      LoRa duplex communication with callback
      ESP32:   MH ET LIVE ESP32-MINI-KIT  with RFM95W (SX1276)
      or ESP8266: LOLIN/WEMOS D1 mini pro with RFM95W (SX1276)
      CS(SS)=16/26, RST=2/16, DIO0(IRQ)=15/5, freq = 868MHz
      SPI (ESP default): MOSI=13/23, MISO=12/19, SCK=14/18
    */

    #include <SPI.h>
    #include <LoRa.h>

    #ifdef ESP8266
      const byte PIN_SS = 16;         // LoRa radio chip select
      const byte PIN_RST = NOT_A_PIN; // LoRa radio reset
      const byte PIN_IRQ = 15 ;       // hardware interrupt pin!
    #else
      const byte PIN_SS = 26;
      const byte PIN_RST = NOT_A_PIN;
      const byte PIN_IRQ = 5 ;
    #endif // #ifdef ESP8266

    //const byte PIN_SCK = 18;
    //const byte PIN_MISO = 19;
    //const byte PIN_MOSI = 23;

    const byte NODE_ADDR = 0x01;                 // address of this device
    const byte GATEWAY_ADDR = 0xFE;              // destination 0xFE = gateway 0xFF = broadcast
    unsigned long send_delay = 6000;             // delay in ms between sends
    byte msg_out_id = 0;                         // counter of outgoing messages = message id

    byte addr_in_rec, addr_in_sender, msg_in_id, msg_in_length;
    String message, msg_out, msg_in, lora_rssi, lora_snr;
    volatile bool flag_message_received = false; // flag set by callback

    void setup() {
      Serial.begin(115200);
      delay(1000);
      Serial.println("LoRa duplex with callback\n");
      //SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_SS);   //SPI LoRa pins
      LoRa.setPins(PIN_SS, PIN_RST, PIN_IRQ);  // setup LoRa transceiver module

      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true); // endless loop
      }
      LoRa.onReceive(onReceive);                 // init the callback function
      LoRa.receive();                            // start receive mode
    }

    void loop() {
      LoRa.receive();                            // go back into receive mode
      if (flag_message_received) {               // if receive flag is set by callback
        readMessage();
        flag_message_received = false;           // set flag back to false
      }
      if (non_blocking_delay(send_delay)) {      // send a message all delay ms
        message = "HeLoRa World!";
        send_message(message);
        Serial.println("Sending:");
        Serial.print("GW addr.: ");
        Serial.print(GATEWAY_ADDR);
        Serial.print(" (1 byte) + node addr.: ");
        Serial.print(NODE_ADDR);
        Serial.print(" (1 byte) + msg ID: ");
        Serial.print(msg_out_id);
        Serial.println(" (1 byte) +");
        Serial.print("msg length: ");
        Serial.print(message.length());
        Serial.println(" (1 byte) + message: \"" + message + "\"");
        Serial.println("---------------------------------------------------------------------");
        send_delay = send_delay + random(1000);  // randomize delay time (avoid collisions)
      }
      delay(1);
    }

    // callback function
    void onReceive(int packetSize) {
      if (packetSize == 0) {                // if there's no packet, return
        return;
      }
      flag_message_received = true;         //Set flag to perform read in main loop
    }

    // send the message and increment ID
    void send_message(String message_out) {
      LoRa.beginPacket();                   // start packet
      LoRa.write(GATEWAY_ADDR);             // add destination address
      LoRa.write(NODE_ADDR);                // add sender address
      LoRa.write(msg_out_id);               // add message ID (counter)
      LoRa.write(message_out.length());     // add payload length
      LoRa.print(message_out);              // add payload
      LoRa.endPacket();                     // finish packet and send it
      msg_out_id++;                         // increment message counter (ID)
    }

    // read a message and check if valid
    void readMessage() {
      addr_in_rec = LoRa.read();            // recipient address
      addr_in_sender = LoRa.read();         // sender address
      msg_in_id = LoRa.read();              // incoming msg ID
      msg_in_length = LoRa.read();          // incoming msg length
      while (LoRa.available()) {
        msg_in = LoRa.readString();
        yield();
      }
      if (msg_in_length != msg_in.length()) {// check length for error
        Serial.println("error: message length does not match length");
        return;
      }
      if (addr_in_rec != GATEWAY_ADDR && addr_in_rec != 0xFF) {
        Serial.println("This message is not for me.");
        return;
      }
      lora_rssi = LoRa.packetRssi();
      lora_snr = LoRa.packetSnr();
      Serial.print("From: 0x" + String(addr_in_sender, HEX));
      Serial.print("\tto: 0x" + String(addr_in_rec, HEX));
      Serial.print("\tRSSI: " + lora_rssi);
      Serial.println("\tSnr: " + lora_snr);
      Serial.print("Message: " + msg_in);
      Serial.print("\tLength: " + String(msg_in_length));
      Serial.println("\tID: " + String(msg_in_id));
      Serial.println("-----------------------------------------------------------");
    }

    // non blocking delay using millis(), returns true if time is up
    bool non_blocking_delay(unsigned long milliseconds) {
      static unsigned long nb_delay_prev_time = 0;
      if(millis() >= nb_delay_prev_time + milliseconds) {
        nb_delay_prev_time += milliseconds;
        return true;
      }
      return false;
    }
"Just do it" Lora 2:

LoRaWan

Software library

To implement LoRaWAN we need to use a LoRaWan library with a reduced footprint, because the memory in ATmega chips (Uno, Leonardo) is very limited. Install the MCCI LoRaWAN LMIC library by IBM, Matthis K... in the library manager. This library provides a fairly complete LoRaWAN Class A and Class B implementation (tested for V1.0.3 of the LoRaWAN specification) and is more up to date than the older LMIC-Arduino by IBM that is no longer maintained.

We have to tell the library what frequency and chip we use. For this we open the file lmic_project_config.h in the following folder: sketchbook/libraries/MCCI_LoRaWAN_LMIC_library/project_config/ with an editor. Then we uncomment (remove //) the following lines. All other lines must be commented (add //).

    // project-specific definitions
    #define CFG_eu868 1
    #define CFG_sx1276_radio 1

Connect to TTN and create an application

Before our LoRa node can communicate with The Things Network (TTN), we need to create an application. First, we must register an account with TTN. Navigate to the account registration page and set up an account. When logged in, navigate to the TTN Console.

ttn console

Under APPLICATIONS we can add applications and add new devices or gateways.

Click on APPLICATIONS and than on ADD APPLICATION. We give the application an Application ID (lowercase alphanumeric characters with '-' or '_') and a Descripton of the application. The Application EUI will be created automatically and we set our handler registration to ttn-handler-eu and click on Add  application.

ttn add application
click for a better view

Now we see the APPLICATION OVERVIEW and the created APPLICATION EUIS (here one EUI 0x70B3D57ED0029220). In the section called DEVICES we can now add a device, so that our hardware can connect to this application. Click on register device (top right under DEVICES).

ttn application
click for a better view

On the Register Device page, the Device ID should be a unique string to identify the device. The Device EUI is sometimes given by a vendor. It must be unique and so we better let TTN generate it for us by using the left icon. The App Key will also be generated by TTN, so leave the App Key field as it is. Click on Register.

ttn register device
click for a better view

Next we will see the DEVICE OVERVIEW page. We see that the activation method is OTAA. We also see the Application EUI, the Device EUI and the App Key (click on the eye) needed to communicate with the application. At the bottom of this page, we see a box called "Example Code". Wonderfully, this is a snippet of code that can directly be copied in our sketch.

ttn device registered
click for a better view

Adjust the Arduino sketch

In Arduino we choose the ttn-otaa example from the LMIC library (File > Examples > MCCI LoRaWAN LMIC library). We will use here an Arduino Uno board with SX1276 breakout board.

**In the OTAA mode (Over-the-air activation), we need to configure a Device EUI, an Application EUI and an Application Key (app key). They are used in an over-the-air activation procedure where a device address and session keys are assigned/generated for use with all further communication.

We can copy the needed information from our DEVICE OVERVIEW by clicking on the right icon. In our sketch both EUIs need to be Little Endian meaning the Least Significant Byte (LSB) must be first. Click first on the most left-hand icon (<>) to get a C-style representation and then on the second left icon (two arrows) to change to LSB. Copy with the right icon and paste in the sketch (replace FILLMEIN).

We should see something like this after pasting:

    // APPEUI and DEVEUI LSB first! APPKEY MSB first!
    static const u1_t PROGMEM APPEUI[8]={ 0x20, 0x92, 0x02, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
    void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
    static const u1_t PROGMEM DEVEUI[8]={ 0x83, 0x0A, 0x89, 0xF0, 0x8D, 0x04, 0x5F, 0x00 };
    void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
    static const u1_t PROGMEM APPKEY[16] = { 0x60, 0x32, 0xD8, 0xC5, 0xEE, 0x5E, 0x13,
                                             0x86, 0x04, 0x36, 0x1C, 0x28, 0xB1, 0xFB, 0xED, 0x48 };
    void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

Next we must configure the right pins for our breakout board. For LoRa we didn't need the second interrupt pin DIO1. Here we must use it to detect an RX from the Things Network. Connect it to the digital pin 6.

LoRa Schield Arduino
NSS (SS, CS) 10
RST (Reset) 9
DIO0 (G0, IRQ) 2
DIO1 (G1, IRQ) (6 only needed for LoRaWAN!)

Replace the pin mapping in the example sketch:

    // Pin mapping
    const lmic_pinmap lmic_pins = {
      .nss = 10,                       //NSS and DIO0 are required
      .rxtx = LMIC_UNUSED_PIN,
      .rst = 9,
      .dio = {2, 6, LMIC_UNUSED_PIN},  //DIO1 is required for LoRa
    };

Because the clock of the Arduino is not accurate enough, add the following two lines to setup() (we also disable link-check mode, insert after Serial.println()):

    LMIC_setLinkCheckMode(0); //Disable link-check mode and ADR.
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

Now run the sketch.

In our serial monitor we should see the following text:

ttn uno sender<em>serial</em>monitor
click for a better view

And in the TTN console under data we see joining (yellow flash) and information on the UPLINK.

ttn console uno sender
click for a better view

To decode the payload we need the ASCII table (0x48 = 'H', 0x65 = 'e', ...). To see the text we could add a decoder function under the Payloads Formats tab.

Interesting also to the estimate the quality of our transmission are the following information: channel number, rssi, snr and the Estimated Airtime.

ttn console uno sender 2
click for a better view

"Just do it" Lora 3:

Getting MQTT data from TTN

One cool thing about TTN is their MQTT API. The server address is eu.thethings.network. We have to provide a user name and a password. The user name is the Application ID and the password is the access key. Both can be found on the APPLICATION OVERVIEW page. The very long access key can be copied with the icon on the right. After this we can subscribe to our topic: <AppID>/devices/<DevID>/up.

ttn mqtt
click for a better view

We get now all the data in a neat json format. Under "payload_raw" we find the payload: "SGVsbG8sIHdvcmxkIQ==". Ok this is not self explaining :)).

The payload is encoded in Base64. Letters , numbers, '+' and '/' are used to encode a 6 digit binary number (26 = 64) ('=' is used for padding). Let's look at our first 4 characters (use the table from the wiki page):

"SGVs" = 010010 000110 010101 101100.

If we regroup and use the ASCII table we get:

01001000 01100101 01101100 = 0x48 0x65 0x6C = 'H' 'e' 'l'.

For simplicity We can use an online decoder or the console in Linux with:

    echo SGVsbG8sIHdvcmxkIQ== | base64 --decode

In a sketch we can use the Arduino library base64.

"Just do it" Lora 4:

Interesting links: