ESP32 LoRaWAN Gateway tutorial with Sensor Node: Example Code Included

In the era of the Internet of Things (IoT), connecting devices and collecting data has become more accessible and vital than ever before. LoRaWAN (Long Range Wide Area Network) technology has emerged as a powerful solution for long-range, low-power IoT communication. In this tutorial, we will build a LoRaWAN Gateway circuit using ESp32 and also, build a sensor node circuit using ESP32 and BME280 sensor. For both the circuit we will use SX1278 based (Ra-02) LoRa module for wireless communication between the devices. We will also show you, how to transmit sensor data to the popular IoT platform, ThingSpeak.

Our other ESP32-related tutorials are:

Understanding ESP32 and LoRaWAN

The ESP32 is a versatile microcontroller that has gained significant popularity in the field of embedded systems and IoT applications. With its dual core powerful processing capabilities, built-in Wi-Fi and Bluetooth connectivity, and a wide range of peripherals and I/Os, the ESP32 offers a comprehensive platform for developing various projects. It provides a flexible and cost-effective solution for building connected devices, enabling seamless communication, data processing, and control functionalities. 

LoRaWAN (Long Range Wide Area Network) is a wireless communication protocol specifically designed for long-range, low-power IoT applications. It operates on unlicensed radio bands, allowing devices to transmit data over extended distances while consuming minimal energy. LoRaWAN utilizes a star network architecture, where low-power end devices communicate with gateway devices that serve as intermediaries between the devices and the network server.

This technology enables efficient and secure communication between IoT devices and cloud-based applications, making it suitable for a wide range of applications such as smart cities, agriculture, asset tracking, and environmental monitoring.

LoRaWAN Network

To know more about LoRa and LoRaWAN, please read our following article:

Regional Frequency Considerations for LoRa Modules

The LoRa modules suitable for different regions vary based on the regulatory frequency bands allocated for use. In Asia, the frequency band typically used for LoRa modules is 433MHz. For example, the SX1278 LoRa module is widely used in Asia, supporting the 433MHz frequency band.

In North America, the LoRa modules operate in the 915MHz frequency band. An example module for this region is the RFM95W, which operates on the 915MHz frequency band and is compliant with North American regulations. You can buy it from Amazon

In Europe, LoRa modules typically operate in the 868MHz frequency band. One example is the REYAX RYLR896 Lora Module, which is commonly used in Europe and supports the 868MHz frequency band.

As we are from Asia, SX1278 Ra-02 module is suitable for us and we will use the module in our project. The SX1278 Ra-02 module is a low-cost, low-power, long-range transceiver module based on the LoRa technology. It operates in the 433MHz frequency band and can transmit up to 10 km of data in open spaces. The module includes an SPI interface for communication with microcontrollers like Arduino, Esp32, or Stm32.

SX1278 Ra-02 LoRa Module

ESP32 LoRaWAN Gateway with Sensor Node: The Project

In this section of the tutorial, we will build a real-world LoRaWAN project by using LoRa and ESP32. We will send the sensor data from the LoRa node to LoRaWAN using LoRa wireless protocol and the LoRaWAN circuit will transmit the data to the ThingSpeak server using WiFi. let’s build the project,

LoRaWAN gateway project

Component List for the Project

Component NameQuantityPurchase Link
ESP32 Development Board2Amazon
LoRa Module2Amazon
BME2801Amazon
Breadboard2Amazon
Jumper wire Pack1Amazon

Affiliate Disclosure: When you click on links to make a purchase, this can result in this website earning a commission. Affiliate programs and affiliations include, but are not limited to Amazon.com

Setting up the ESP32 LoRaWAN Gateway Circuit

To create a LoRaWAN gateway, we need an ESP32 development board and a LoRa transceiver module (we are using SX1278 (Ra-02) module). The ESP32 is responsible for receiving LoRaWAN packets from sensor nodes and forwarding them to the LoRaWAN network server like thingspeak. Setting up the gateway involves configuring the LoRa module, connecting it to the ESP32, and programming the ESP32 with the appropriate firmware.

Circuit Diagram of LoRaWAN Gateway

Circuit Diagram of LoRaWAN Gateway

LoRaWAN Gateway Circuit Connection

Esp32 Dev. BoardLora sx1278 (Ra-02)
3.3VVCC
GroundGnd
GPIO 23MOSI
GPIO 19MISO
GPIO 18SCLK
GPIO 4NSS
GPIO 5RST
GPIO 2DIO0

Setting up the Sensor Node Circuit

The BME280 sensor is a versatile environmental sensor capable of measuring temperature, humidity, and barometric pressure. To create the sensor node, we integrate the BME280 sensor with an ESP32. The sensor node is programmed to collect data from the BME280 sensor and transmit it to the gateway using LoRaWAN technology.

Circuit Diagram of LoRa Sensor Node

Circuit Diagram of LoRa Sensor Node

LoRaWAN Sensor Node Circuit Connection

Esp32 Dev. BoardLora sx1278 (Ra-02)BME280
3.3VVCCVCC
GroundGndGnd
GPIO 23MOSI
GPIO 19MISO
GPIO 18SCLK
GPIO 4NSS
GPIO 5RST
GPIO 2DIO0
GPIO 21SDA
GPIO 22SCL

Integrating with ThingSpeak

ThingSpeak is a widely-used IoT platform that enables users to collect, analyze, and visualize sensor data in real-time. To integrate the ESP32 LoRaWAN gateway with ThingSpeak, we need to create a ThingSpeak account and set up a channel to receive the sensor data. ThingSpeak provides an API that allows us to send HTTP requests to update the channel with the received sensor data. There are some steps you need to follow to configure ThinkSpeak:

Step 1: Create an account at ThinkSpeak. For this go to thingspeak and create an account.

3 min

Step 2: Then click on Channels and create a new channel.

5 min

Step 3: After creating a channel, Click Channels > My Channels and select your Channel Name

9 min

Step 4: After Step 3, Click on Channels > My Channels > API Keys and copy the Write API Key and paste it to your LoRaWAN code in Arduino IDE.

api key img

Step 5: After Step 4, Click on Channels > My Channels > Channel Settings and select how many fields you want to show on your dashboard.

8

Step 6: If all the steps are complete, then Click on Private View Tab on ThingSpeak Dashboard and you will see this kind of interface. Where sensor data is continuously received by the ThingSpeak server from our ESP32 LoRaWAN device if your device is connected.

1 min

Developing the Gateway and Sensor Node Firmware

On the gateway side, we program the ESP32 with LoRa using a library called LoRa by Sandeep Mistry, also use ESP32 built-in WiFi library for Arduino IDE, the WiFi library handles the forwarding of LoRaWAN packets to the network server. Additionally, we integrate the ThingSpeak API to send the received data to the appropriate ThingSpeak channel.

Here is the LoRa Library which will use in the project:

lora bibrary

LoRaWAN Gateway Code

.ino file for Arduino IDE

#include <WiFi.h> //WiFi Library for esp32
#include <LoRa.h> //LoRa Library

// Enter your Write API key from ThingSpeak
// go to ThingSpeak and click channels > API Keys
// and copy the Write API key
String api_key = "72MCYGKPXF5VDDIL";
// replace with your wifi ssid
const char *ssid = "wifi_ssid";
// replace with your wifi password
const char *password = "wifi_password";
// ThinkSpeak Server Address
const char* server = "api.thingspeak.com";

WiFiClient client; //Initialize WiFi as client

//define the pins used by the transceiver module
#define NSS 4
#define RST 5
#define DI0 2

String temp; // This string hold the temperature data
String pressure; // This string hold the presser data
String humidity; // This string hold the humidity data

// This string receive the Lora data 
// which is comming from sensor node
String lora_data = "";

// these variables are used to identify the position
// of the sensor data from the string
int pos_1, pos_2;

void setup() {
  Serial.begin(115200);

  //setup LoRa sender
  LoRa.setPins(NSS, RST, DI0);

  //replace the LoRa.begin(frequency) argument with your location's frequency  
  //433E6 for Asia
  //866E6 for Europe
  //915E6 for North America
  while (!LoRa.begin(433E6)) {
    Serial.println(".");
    delay(500);
  }
 
 Serial.println("LoRa init succeeded.");

  // Change sync word (0xF0) to match the receiver
 // The sync word assures that to not get LoRa messages from other LoRa transceivers
 // ranges from 0-0xFF
 LoRa.setSyncWord(0xF0);

 // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to WiFi ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  // Print local IP address and start the web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


void loop() { 
  // try to parse packet
  int packetSize = LoRa.parsePacket();
  if (packetSize)
  {
    // received a packet from lora node
    Serial.print("Received packet:  ");
    String lora_data = LoRa.readString();
    Serial.print(lora_data);
    // read packet
    while (LoRa.available()) {
      Serial.print((char)LoRa.read());
    }
    // print RSSI of packet
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
 
    pos_1 = lora_data.indexOf('a');
    pos_2 = lora_data.indexOf('b');
 
    temp = lora_data.substring(0, pos_1);
    pressure = lora_data.substring(pos_1 + 1, pos_2);
    humidity = lora_data.substring(pos_2 + 1, lora_data.length());

    Serial.print("Temperature: ");
    Serial.println(temp);
    Serial.print("Pressure: ");
    Serial.println(pressure);
    Serial.print("Humidity: ");
    Serial.println(humidity);
  }

  //send data to thingspeak server
  if (client.connect(server, 80)) // "184.106.153.149" or api.thingspeak.com
   {
      String str_data = api_key;
      str_data += "&field1=";
      str_data += String(temp);
      str_data += "&field2=";
      str_data += String(humidity);
      str_data += "&field3=";
      str_data += String(pressure);
      str_data += "\r\n\r\n\r\n\r\n";
    
      client.print("POST /update HTTP/1.1\n");
      client.print("Host: api.thingspeak.com\n");
      client.print("Connection: close\n");
      client.print("X-THINGSPEAKAPIKEY: " + api_key + "\n");
      client.print("Content-Type: application/x-www-form-urlencoded\n");
      client.print("Content-Length: ");
      client.print(str_data.length());
      client.print("\n\n");
      client.print(str_data);
 
    }    

  delay(1000);
  
}

On the sensor node side, we program the microcontroller (ESP32) to collect data from the BME280 sensor and transmit it to the gateway circuit using LoRa communication. We will use Adafruit Unified Sensor and Adafruit BME280 library to configure the BME280 sensor which measures pressure, temperature, and humidity data from the environment.

Here is the Adafruit Libraries for BME280 sensor which will use in the project:

Go to Tools > Manage Libraries and search for “Adafruit Unified Sensor Library” then install the library.

adafriut unified sensor min

Again search for “Adafruit BME280” and install the library.

adafruit bme280 min

LoRa Sensor node Code

.ino file for Arduino IDE

#include <Wire.h> //WiFi Library for esp32
#include <Adafruit_Sensor.h> //Adafruit Unified Sensor library
#include <Adafruit_BME280.h> //Adafruit Adafruit BME280 library
#include <LoRa.h> //LoRa Library

//define the pins used by the LoRa module
#define NSS 4
#define RST 5
#define DI0 2

Adafruit_BME280 bme; // I2C

//this structure type for store the sensor value
struct sensor{
  float read_temp;
  float read_pressure;
  float read_humidity;
};

//Initialize the structure type as bme280
struct sensor bme280;

// this string variable for sending the sensor data
// to gateway circuit using lora communication
String lora_message = "";

void setup() {
  Serial.begin(115200);

  //setup LoRa sender
  LoRa.setPins(NSS, RST, DI0);

  //replace the LoRa.begin(frequency) argument with your location's frequency 
  //433E6 for Asia
  //866E6 for Europe
  //915E6 for North America
  while (!LoRa.begin(433E6)) {
    Serial.println(".");
    delay(500);
  }
 
 Serial.println("LoRa init succeeded.");

 // Change sync word (0xF0) to match the receiver
 // The sync word assures that to not get LoRa messages from other LoRa transceivers
 // ranges from 0-0xFF
 LoRa.setSyncWord(0xF0);
 
  Serial.println("Initialize BME280");

  bool status;

  //Initialize the bme280 sensor with its i2c address (0x76)
  status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid sensor..");
    while (1);
  }

  Serial.println("BME280 sensor Connection Sucessful!");
  Serial.println();
}


void loop() { 
  // Read Temperature data from bme280
  bme280.read_temp = bme.readTemperature();
  Serial.print("Temperature = ");
  Serial.println(bme280.read_temp);
  // Read Pressure data from bme280
  bme280.read_pressure = bme.readPressure();
  bme280.read_pressure = bme280.read_pressure / 100.0F;
  Serial.print("Pressure = ");
  Serial.print(bme280.read_pressure);
  Serial.println(" hPa");
  // Read Humidity data from bme280
  bme280.read_humidity = bme.readHumidity();
  Serial.print("Humidity = ");
  Serial.print(bme280.read_humidity);
  Serial.println(" %");

  // convert the 3 data to string and concatenate the string
  // we use "a" and "b" as string between sensor data to properly
  // search the substring and collect the sensor data in gateway side
  lora_message = String(bme280.read_temp) + "a" + String(bme280.read_pressure) + "b" + String(bme280.read_humidity);
  Serial.println(lora_message);

   // send the LoRa packet
  LoRa.beginPacket();
  LoRa.print(lora_message);
  LoRa.endPacket();
  delay(1000);

  
}

Testing and Deployment

Once the gateway and sensor node firmware are ready, we can deploy the system and start collecting sensor data. Verify that the gateway is properly receiving LoRaWAN packets from the sensor node and forwarding them to the network server. Check the ThingSpeak channel to ensure that the data is being updated correctly.

ThingSpeak user interface

Video Tutorial

Mahamudul Hasan

I hold a B.Sc degree in Electrical & Electronic Engineering from Daffodil International University, Bangladesh. I am a Printed Circuit Board (PCB) designer and Microcontroller programmer with an avid interest in Embedded System Design and IoT. As an Engineer, I love taking challenges and love being part of the solution. My Linkedin Profile Link: https://linkedin.com/in/mheee

Recent Posts