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

LoRaWan

last updated: 19/01/20

Introduction

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

https://en.wikipedia.org/wiki/LoRa

https://de.wikipedia.org/wiki/Long_Range_Wide_Area_Network

https://fr.wikipedia.org/wiki/LoRaWAN

https://lora-alliance.org/about-lorawan

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. 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 also very sensitive. It may receive signals many times weaker than other wireless technologies. So the LoRa transmitter needs less power to communicate.

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 peer technologies, the biggest difference you’ll notice with LoRa is that even the advertised data rates are rather low. LoRa can, depending on the channel configuration, handle bit rates of between 250 bit/s and 11 kbit/s (Europe).

LoRaWan

Simple sender and 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. 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

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. Additional to these 6 connections we have to connect the Reset of the chip and an Interrupt input (DI0 or G0) to pins of the microcontroller. Standard for an Arduino Uno are the following pins:

LoRa Schield Arduino
3.3V (Vin) 3.3V
GND GND
MOSI 11
MISO 12
SCK 13
NSS (SS, CS) 10
RST (Reset) 9
DI0 (G0, IRQ) 2
DI1 (G1, IRQ) (6 only needed for LoRaWAN!)
ANT antenna

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 lora_sender_868.ino
    // (CS=10, RST=9, IRQ(0)=2, freq = 868MHz)

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

    int counter = 0;

    void setup() {
      Serial.begin(115200);
      Serial.println("LoRa sender\n");
      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(5000);
    }

And the receiver:

    // LoRa simple receiver lora_receiver_868.ino
    // (CS=10, RST=9, IRQ(0)=2, freq = 868MHz)

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

    byte packet_size = 0;

    void setup() {
      Serial.begin(115200);
      Serial.println("LoRa receiver\n");
      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.println(LoRa.packetRssi());
      }
    }

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

    const int csPin = 10;         // LoRa radio chip select
    const int resetPin = 9;       // LoRa radio reset
    const int irqPin = 2;         // must be a hardware interrupt pin (check for your board)

    void setup() {
      ...
      LoRa.setPins(csPin, resetPin, irqPin);// set CS, reset, IRQ pin
      ...
    }
"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 (1 byte = 256 addresses, 0xFF for broadcast messages). The message gets an identifier (ID), realised in the sketch with a simple message counter.

    // LoRa duplex communication with callback lora_duplex_callback_868.ino

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

    byte msg_out_id = 0;            // counter of outgoing messages = message id
    byte node_1_addr = 0x01;        // address of this device
    byte gateway_addr = 0xFE;       // destination 0xFE = gateway 0xFF = broadcast
    long millis_delay = 20000;      // interval between sends
    long millis_now, millis_prev=0;
    byte addr_in_rec, addr_in_sender, msg_in_id, msg_in_length;
    String msg_out, msg_in, lora_rssi, lora_snr;
    volatile bool flag_message_received = false; // flag set by callback

    void setup() {
      Serial.begin(115200);
      Serial.println("LoRa duplex with callback\n");
      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true); // endless loop
      }
      LoRa.onReceive(onReceive); // callback
      LoRa.receive();
    }

    void loop() {
      LoRa.receive();                       // go back into receive mode
      if (flag_message_received) {
        readMessage();
        flag_message_received = false;      // Set flag back to false
      }
      millis_now = millis();
      if (millis_now - millis_prev > millis_delay) {
        String message = "HeLoRa World!";   // send a message
        send_message(message);
        Serial.println("Sending " + message);
        Serial.println("---------------------------------------------------------");
        millis_prev = millis();             // timestamp the message
        millis_delay = millis_delay + random(1000);     // randomize delay time
      }
      delay(1);
    }

    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
    }

    void send_message(String message_out) {
      LoRa.beginPacket();                   // start packet
      LoRa.write(gateway_addr);             // add destination address
      LoRa.write(node_1_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)
    }

    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();
      }
      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("-----------------------------------------------------------");
    }
"Just do it" Lora 2:

LoRaWan

In LoRa sensors can communicate wirelessly over long range. A LoRa sensor transmitter iscalled a ‘node’.

In LoRaWAN the receiver of LoRa messages acts as a gateway, sending the information onto the internet. We will connect a LoRa node to The Things Network, a crowdsourced network of gateways. This enables us to receive data from a node and transmit some data across the internet to a nice dashboard displaying our data.

hackspace 22

The Things Network is a community-hosted network that consists of gateways connected to the internet. LoRaWAN devices, in our case a The Things Uno, can be received by any gateway, and their data packets are then forwarded to an account registered by the device owner on The Things Network website. The website application can be set up to integrate or forward those pieces of information to other systems, allowing the user to create a visual web dashboard, a phone application, an SMS alert, an email, or other options triggered or populated by the data from the device or devices in the field. The Things Network website has a map of gateways – check and see if you have one locally that you may be able to connect to.

https://www.disk91.com/2019/technology/lora/hoperf-rfm95-and-arduino-a-low-cost-lorawan-solution/

What is the difference between the different Semtech chip for LoRa ? The SX1276 was the first version of Semtech’s LoRa chips. The SX126x Semtech’s family chip has been released in January 2018. This new version, including SX1262, has lower (50%) consumption in reception. It also offers higher transmission power (+15db and +22dB). The SX1262 is smaller with 4x4mm.

So the RFM95w module is using the first version of Semtech LoRa chip. Actually, most of the transceiver are using this chip, so it is not a negative comment.

The SX1276 chip proposes a +14dB transmission for CE area and +20dB for FCC area. The datasheet can be found on Semtech website.

The HopeRF RFM95w module is a LoRa transceiver implementing the SX1276 chip. There is nothing more than a SX1276 standard design on it. this is why you can find different brand proposing equivalent circuit. Some with shield, some without.

The transceiver is LoRa and not LoRaWAN. It means the RFM95w do not implement the LoRaWan stack and you need to use a MCU to implement it.

The RFM95w powering is 3.3Volts. The module documentation is accessible on the HopeRF website.https://www.hoperf.com/modules/lora/RFM95.html

At first, Arduino is powered with 5V when the Semtech chip only supports 3.9V as max voltage and usually works with 3.3V. You can cable the module to the Arduino 3.3V but you need to know this powering source is coming from the FTDI (USB) chip and will not be supplied when a battery is in use. The Arduino’s 3.3V power source is also limited to 50mA. For FCC (basically higher than 14dB) usage you will need to use another power supply to provide the right currant.

As a consequence, by connecting your module to an Arduino as I’ll describe it in the next lines you understand you have a risk to make it burned or to see its lifetime largely reduced due to this over-voltage.

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 MCII 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 1.03) 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: sketchbook/libraries/MCCI_LoRaWAN_LMIC_library/project_config/ and uncomment 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 ID (lowercase alphanumeric characters with - or _) and a description of what the application is. 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

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".

ttn application

Next we will see the Device Overview page. We see that the activation method is OTAA. We also see the app and device EUI and the app key 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 register device

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 device registered

In the "DEVICE OVERVIEW" we see that the activation method is OTAA. We also see the app and device EUI and the app key needed to communicate with the application.

Adjust the sketches

In Arduino we choose the ttn-otaa example from the LMIC library (File > Examples > MCCI LoRaWAN LMIC library). In OTAA (Over-the-air activation), we need to configure a device and an application EUI and an application 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 DI1. Here we must use it to detect an RX from the Things Network.

LoRa Schield Arduino
NSS (SS, CS) 10
RST (Reset) 9
DI0 (G0, IRQ) 2
DI1 (G1, IRQ) (6 only needed for LoRaWAN!)
    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
    };

coming soon :))

Interesting links: