Sensors, interfaces and bus systems (SENIN, BUSSY)


last updated: 19/01/20


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






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


Simple sender and receiver

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


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


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


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
SCK 13
NSS (SS, CS) 10
RST (Reset) 9
DI0 (G0, IRQ) 2
DI1 (G1, IRQ) (6 only needed for LoRaWAN!)
ANT antenna


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.println("LoRa sender\n");
      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true); //endless loop

    void loop() {
      Serial.print("Sending packet number: ");
      LoRa.print("This is packet number ");

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.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(" byte: '");
        while (LoRa.available()) {     // read packet
        Serial.print("' with RSSI ");

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:


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.println("LoRa duplex with callback\n");
      if (!LoRa.begin(868E6)) {
        Serial.println("Error starting LoRa!");
        while (true); // endless loop
      LoRa.onReceive(onReceive); // callback

    void loop() {
      LoRa.receive();                       // go back into receive mode
      if (flag_message_received) {
        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
        Serial.println("Sending " + message);
        millis_prev = millis();             // timestamp the message
        millis_delay = millis_delay + random(1000);     // randomize delay time

    void onReceive(int packetSize) {
      if (packetSize == 0) {                // if there's no packet, 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();
        yield(); // avoid watchdog to bark
      if (msg_in_length != msg_in.length()) {// check length for error
        Serial.println("error: message length does not match length");
      if (addr_in_rec != gateway_addr && addr_in_rec != 0xFF) {
        Serial.println("This message is not for me.");
      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));
"Just do it" Lora 2:


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: