Arduino ProjectsLoRa
Trending

Multiple LoRa Nodes Communication with Master LoRa Node

LoRa Two Way Communication with Multiple Nodes

Today in this tutorial, we will learn to make Multiple LoRa Nodes communication with the Master LoRa Node. But, before getting started with this tutorial, let’s have a quick overview of our previous Arduino and SX1278 LoRa transceiver modules.


Quick Overview of Previous LoRa SX1278 based Projects

In the first tutorial, I explained the maximum basic things including the SX1278 LoRa module Pinout, technical specifications, and its interfacing with the Arduino. I demonstrated a simple LoRa one-way communication project. It was an agriculture monitoring and automatic irrigation system. In which I monitored multiple sensors like soil moisture sensor, DS18B20 temperature sensor, and DHT22 Temperature & Humidity sensor remotely using LoRa SX1278 module on Blynk IoT Platform.

Then I made a long-range LoRa wireless two-way communication system using the same 433Mhz SX1278 LoRaTransceiver modules. In this project, I interfaced DHT22 sensor and 16×2 I2C LCD on the first LoRa Node. While on the second LoRa node I interface the DS18B20 temperature sensor and OLED Display.

Here I was simply sending the DHT22 temperature and humidity value from the First Node to the Second Node and then I was printing those values on the I2C OLED display module. While on the other side I used a DS18B20 temperature sensor and I was able to send the temperature value to the first node and then print its value on a 16×2 i2c LCD display. You can easily modify this project to monitor multiple sensors and control multiple devices as per your requirement.


Overview: Multiple LoRa Nodes Communication with Master LoRa Node

In today’s tutorial, you will learn how to perform Multiple LoRa Nodes Communication with the Master Lora Node. Here, I have three LoRa modules, you can use more if you have. So, in this demonstration, I am using one as the Master LoRa node and the other two as the LoRa end devices

To the LoRa Node1, a capacitive soil moisture sensor is connected which I am going to use to measure the Relative Humidity of soil. But, you can replace this sensor with any other sensor of your requirement. In a LoRa Node2, the DHT22 temperature & humidity sensor is connected.

Multiple LoRa Nodes Communication with Master LoRa Node

To the master LoRa Node, a 0.96 inch i2c supported Oled display module is connected which is used for displaying the data received from the other two LoRa end devices. So, you can see it in the image below. I have connected two different sensors to the Arduino LoRa nodes or LoRa end devices. We will send those sensor values to the master LoRa Node and print them on OLED Display along with the Node1 or Node2 information.  You can add multiple LoRa Nodes with different sensors connected. So, let’s go ahead and check how this system works.


Working of Multiple LoRa Nodes Communication

Here, Master LoRa Node sends a request to the LoRa end devices. For this, I created a timer using the millis() function. So, for the first 5 seconds, the Master LoRa node sends multiple requests to the LoRa Node1 and receives Soil Moisture Sensor data from the LoRa Node1. Then for the next 5 seconds, it receives temperature and humidity data from the LoRa Node2. You can change this time duration in the program code.

Monitoring Multiple LoRa Node Sensor data on Master LoRa Node

Those received sensor data from LoRa Nodes are printed on OLED Display Module. On the top of the Display, the Node name is printed. So you won’t have any confusion about from which node you are receiving data. This entire system is based on two-way communication. Thus you can also send commands to remote LoRa nodes to control devices.

Multiple LoRa Nodes with Master LoRa Node

You can DIY your own LoRaWAN project by converting this Master Node to LoRa Gateway. This is the main reason for using the NodeMCU ESP8266 12E Board on Master Node instead of the Arduino board. Because, using the nodemcu ESP8266 board I can easily send sensor data to IoT platforms like Thingspeak, Blynk IoT, Arduino IoT Cloud, Ubidots, AWS IoT, etc. It’s totally up to you how you modify and for what purpose you use this project. So, I hope you already got an idea of what you are going to learn here.


Components Required

All the components required for making Multiple LoRa Nodes Communication with Master LoRa Node are provided below. You can purchase all the components online from Amazon.

S.NComponents NameQuantityGet Products from Amazon
1NodeMCU ESP8266-12E Board1https://amzn.to/3sCrEbj
2Capacitive Soil Moisture Sensor1https://amzn.to/3nyL9y7
3DHT22 Temperature & Humidity Sensor1https://amzn.to/32VEw1X
40.96" I2C OLED Display1https://amzn.to/3kvENyc
5Arduino Nano2 https://amzn.to/3Hf7zvN
6LoRa SX1278 Transceiver Module3https://amzn.to/3G6xapO
7Few jumpers wires20https://amzn.to/3klh0A4

*Please Note: These are affiliate links. I may make a commission if you buy the components through these links. I would appreciate your support in this way!


Circuit Diagram of Multiple LoRa Communication

Now, let us see how we can connect Multiple LoRa Nodes with Master LoRa Node. The circuit diagram and explanation of each LoRa node are provided below.


Master LoRa Node Circuit:

LoRa Master Node Circuit Diagram

This is the circuit diagram of the Master LoRa Node. The VCC of the SX1278 Lora module is connected with the 3.3V of the NodeMCU. The MISO Pin of the LoRa module is connected with the NodeMCU pin D6. The MOSI pin is connected with the NodeMCU pin D7. The SCK pin of the LoRa module is connected with NodeMCU pin D5. The NSS pin is connected with pin D8 and the ground pin of the LoRa module is connected with the NodeMCU GND. The VCC and GND pins of the SSD1306 Oled display module are connected with the NodeMCU 3.3V and GND pins. The SDA and SCL pins of the Oled display module are connected with the NodeMCU I2C pins D1 and D2.


Arduino LoRa Node1 Circuit:

LoRa Sensor Node Circuit Diagram

This is the circuit diagram of the LoRa Node1. The connection of the SX1278 Lora module, and Capacitive Soil Moisture Sensor remains exactly as shown here. The VCC of the LoRa module is connected with the 3.3V of the Arduino. The MISO Pin of the LoRa module is connected with Arduino’s pin 12. The MOSI pin is connected with the Arduino’s pin 11. The SCK pin of the LoRa module is connected with Arduino’s pin 13. The NSS pin is connected with the Arduino’s pin 10 and the ground pin of the LoRa module is connected with the Arduino’s GND. 

The data wire (yellow) of the capacitive soil moisture sensor is connected with Analog pin A0 while the other two Red and Black wire of the soil moisture sensor is connected with the Arduino’s 3.3V and GND.


Arduino LoRa Node2 Circuit:

Arduino LoRa Node2 Circuit Diagram

This is the circuit diagram of the LoRa Node2. The connection of the SX1278 Lora module remains exactly the same as LoRa Node1.

Out pin of the DHT22 sensor is connected to the D5 pin of the Arduino. Whereas VCC and GND are connected to 3.3V and GND pins of Arduino respectively.


Project PCB Gerber File & PCB Ordering Online

You can simply assemble the circuit on a breadboard. But To remove messy wiring and give a clean look, I designed a PCB prototype for this project. It is also helpful for troubleshooting without any errors. You can download the Gerber file of my PCB Design from the link attached below. The PCB looks like the image shown below.

  • LoRa based IoT Smart Irrigation System with ESP8266 Gateway PCB
  • Lora sensor node PCB

I provided the Gerber File for Multiple LoRa Nodes Communication with Master LoRa Node PCB below.

You can simply download the Gerber File and order your custom PCB from PCBWay

PCBWay website

Visit the PCBWay official website by clicking here: https://www.PCBWay.com/. Simply upload your Gerber File to the Website and place an order. I prefer PCBWay for ordering custom PCBs. PCBWay is a place that brings manufacturers and customers together. They have more than a decade of experience in this field of fabrication, prototyping, and assembling PCBs. PCBWay have proved their focus to their customers’ needs in terms of cost-effectiveness, delivery, and quality. And this can be proved by their outstanding customer reviews.

PCB 3D Rendering for IoT Smart Agriculture

Arduino Multiple LoRa Nodes Programming:

Before you start programming, first of all, make sure you download and install all the necessary library files.

As this project is based on multiple LoRa Nodes. Therefore, each LoRa Node has its own code. In this demonstration, we have three LoRa nodes. So, we will have three different codes. First, let’s start with the Master LoRa node.


Master LoRa Node Program Code:

/*
  Master Lora Node
  The IoT Projects

*/
#include <SPI.h>              // include libraries
#include <LoRa.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define ss 15  //GPIO 15
#define rst 16  //GPIO 16
#define dio0 4  //GPIO 4

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

byte MasterNode = 0xFF;
byte Node1 = 0xBB;
byte Node2 = 0xCC;

String SenderNode = "";
String outgoing;              // outgoing message

byte msgCount = 0;            // count of outgoing messages
String incoming = "";

// Tracks the time since last event fired
unsigned long previousMillis = 0;
unsigned long int previoussecs = 0;
unsigned long int currentsecs = 0;
unsigned long currentMillis = 0;
int interval = 1 ; // updated every 1 second
int Secs = 0;

int temperature;
int humidity;
int soilmoisturepercent;
int soilMoistureValue;

void setup() {
  Serial.begin(115200);                   // initialize serial
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  delay(500);
  display.clearDisplay();
  display.setTextColor(WHITE);

  while (!Serial);

  Serial.println("LoRa Master Node");

  LoRa.setPins(ss, rst, dio0);

  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {


  currentMillis = millis();
  currentsecs = currentMillis / 1000;
  if ((unsigned long)(currentsecs - previoussecs) >= interval) {
    Secs = Secs + 1;
    //Serial.println(Secs);
    if ( Secs >= 11 )
    {
      Secs = 0;
    }
    if ( (Secs >= 1) && (Secs <= 5) )
    {

      String message = "10";
      sendMessage(message, MasterNode, Node1);
    }

    if ( (Secs >= 6 ) && (Secs <= 10))
    {

      String message = "20";
      sendMessage(message, MasterNode, Node2);
    }

    previoussecs = currentsecs;
  }

  // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());

}


void sendMessage(String outgoing, byte MasterNode, byte otherNode) {
  LoRa.beginPacket();                   // start packet
  LoRa.write(otherNode);              // add destination address
  LoRa.write(MasterNode);             // add sender address
  LoRa.write(msgCount);                 // add message ID
  LoRa.write(outgoing.length());        // add payload length
  LoRa.print(outgoing);                 // add payload
  LoRa.endPacket();                     // finish packet and send it
  msgCount++;                           // increment message ID
}

void onReceive(int packetSize) {
  if (packetSize == 0) return;          // if there's no packet, return

  // read packet header bytes:
  int recipient = LoRa.read();          // recipient address
  byte sender = LoRa.read();            // sender address
  if ( sender == 0XBB )
    SenderNode = "Node1:";
  if ( sender == 0XCC )
    SenderNode = "Node2:";
  byte incomingMsgId = LoRa.read();     // incoming msg ID
  byte incomingLength = LoRa.read();    // incoming msg length


  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }

  if (incomingLength != incoming.length()) {   // check length for error
    //Serial.println("error: message length does not match length");
    ;
    return;                             // skip rest of function
  }

  // if the recipient isn't this device or broadcast,
  if (recipient != Node1 && recipient != MasterNode) {
    // Serial.println("This message is not for me.");
    ;
    return;                             // skip rest of function
  }

  // if message is for this device, or broadcast, print details:
  //Serial.println("Received from: 0x" + String(sender, HEX));
  //Serial.println("Sent to: 0x" + String(recipient, HEX));
  //Serial.println("Message ID: " + String(incomingMsgId));
  // Serial.println("Message length: " + String(incomingLength));
  // Serial.println("Message: " + incoming);
  //Serial.println("RSSI: " + String(LoRa.packetRssi()));
  // Serial.println("Snr: " + String(LoRa.packetSnr()));
  // Serial.println();

  if ( sender == 0XCC )
  {
    String t = getValue(incoming, ',', 0); // Temperature
    String h = getValue(incoming, ',', 1); // Humidity

    temperature = t.toInt();
    humidity = h.toInt();
    incoming = "";
    //clear display
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(30, 0);
    display.print(SenderNode);
    // display temperature
    display.setTextSize(2);
    display.setCursor(0, 20);
    display.print("Temp: ");
    display.setCursor(60, 20);
    display.print(temperature);
    display.print(" ");
    display.setTextSize(1);
    display.cp437(true);
    display.write(167);
    display.setTextSize(2);
    display.print("C");

    // display humidity
    display.setTextSize(2);
    display.setCursor(0, 45);
    display.print("Humi: ");
    display.setCursor(60, 45);
    display.print(humidity);
    display.print(" %");
  }

  if ( sender == 0XBB )
  {

    String v = getValue(incoming, ',', 0); // Soil Moisture Value
    String p = getValue(incoming, ',', 1); // Soil Moisture percentage

    soilMoistureValue = v.toInt();
    soilmoisturepercent = p.toInt();


    incoming = "";

    //clear display
    display.clearDisplay();

    display.setTextSize(2);
    display.setCursor(35, 0);
    display.print(SenderNode);

    display.setCursor(20, 20); //oled display
    display.setTextSize(2);
    display.println("Soil RH:");

    display.setCursor(35, 40); //oled display
    display.setTextSize(3);
    display.print(soilmoisturepercent);
    display.setCursor(70, 40);
    display.setTextSize(3);
    display.println(" %");
    display.display();
  }

  display.display();
}
String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = data.length() - 1;

  for (int i = 0; i <= maxIndex && found <= index; i++) {
    if (data.charAt(i) == separator || i == maxIndex) {
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }
  return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}

Arduino LoRa Node1 Program Code:

/*
  Lora Node1
  The IoT Projects

*/
#include <SPI.h>              // include libraries
#include <LoRa.h>

#define ss 10
#define rst 9
#define dio0 2

String outgoing;              // outgoing message

byte msgCount = 0;            // count of outgoing messages
byte MasterNode = 0xFF;
byte Node1 = 0xBB;

int AirValue = 590;   //you need to replace this value with Value_1
int WaterValue = 300;  //you need to replace this value with Value_2
int SensorPin = A0;
int soilMoistureValue = 0;
int soilmoisturepercent = 0;

String Mymessage = "";

void setup() {
  Serial.begin(115200);                   // initialize serial


  while (!Serial);

  Serial.println("LoRa Node1");

  LoRa.setPins(ss, rst, dio0);

  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  soilMoistureValue = analogRead(SensorPin);  //put Sensor insert into soil
  soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);

  // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());
}

void onReceive(int packetSize) {
  if (packetSize == 0) return;          // if there's no packet, return

  // read packet header bytes:
  int recipient = LoRa.read();          // recipient address
  byte sender = LoRa.read();            // sender address
  byte incomingMsgId = LoRa.read();     // incoming msg ID
  byte incomingLength = LoRa.read();    // incoming msg length

  String incoming = "";

  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }

  if (incomingLength != incoming.length()) {   // check length for error
    // Serial.println("error: message length does not match length");
    ;
    return;                             // skip rest of function
  }

  // if the recipient isn't this device or broadcast,
  if (recipient != Node1 && recipient != MasterNode) {
    //Serial.println("This message is not for me.");
    ;
    return;                             // skip rest of function
  }
  Serial.println(incoming);
  int Val = incoming.toInt();
  if (Val == 10)
  {
    Mymessage = Mymessage + soilMoistureValue + "," + soilmoisturepercent;
    sendMessage(Mymessage, MasterNode, Node1);
    delay(100);
    Mymessage = "";
  }

}
void sendMessage(String outgoing, byte MasterNode, byte Node1) {
  LoRa.beginPacket();                   // start packet
  LoRa.write(MasterNode);              // add destination address
  LoRa.write(Node1);             // add sender address
  LoRa.write(msgCount);                 // add message ID
  LoRa.write(outgoing.length());        // add payload length
  LoRa.print(outgoing);                 // add payload
  LoRa.endPacket();                     // finish packet and send it
  msgCount++;                           // increment message ID
}

Arduino LoRa Node1 Program Code:

/*
  Lora Node2
  The IoT Projects

*/
#include <SPI.h>              // include libraries
#include <LoRa.h>
#include <DHT.h>

#define DHTPIN 5          //pin where the dht22 is connected
DHT dht(DHTPIN, DHT22);
#define ss 10
#define rst 9
#define dio0 2

String outgoing;              // outgoing message

byte msgCount = 0;            // count of outgoing messages
byte MasterNode = 0xFF;
byte Node2 = 0xCC;

float temperature;
float humidity;

String Mymessage = "";
String incoming = "";

void setup() {
  Serial.begin(115200);                   // initialize serial
  dht.begin();


  while (!Serial);

  Serial.println("LoRa Node2");

  LoRa.setPins(ss, rst, dio0);

  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {

  temperature = dht.readTemperature();
  humidity = dht.readHumidity();


  // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());
}

void onReceive(int packetSize) {
  if (packetSize == 0) return;          // if there's no packet, return

  // read packet header bytes:
  int recipient = LoRa.read();          // recipient address
  byte sender = LoRa.read();            // sender address
  byte incomingMsgId = LoRa.read();     // incoming msg ID
  byte incomingLength = LoRa.read();    // incoming msg length

  String incoming = "";

  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }

  if (incomingLength != incoming.length()) {   // check length for error
    // Serial.println("error: message length does not match length");
    ;
    return;                             // skip rest of function
  }

  // if the recipient isn't this device or broadcast,
  if (recipient != Node2 && recipient != MasterNode) {
    //Serial.println("This message is not for me.");
    ;
    return;                             // skip rest of function
  }
  Serial.println(incoming);
  int Val = incoming.toInt();
  if (Val == 20)
  {
    Mymessage = Mymessage + temperature + "," + humidity;
    sendMessage(Mymessage, MasterNode, Node2);
    delay(100);
    Mymessage = "";
  }

}

void sendMessage(String outgoing, byte MasterNode, byte Node2) {
  LoRa.beginPacket();                   // start packet
  LoRa.write(MasterNode);              // add destination address
  LoRa.write(Node2);             // add sender address
  LoRa.write(msgCount);                 // add message ID
  LoRa.write(outgoing.length());        // add payload length
  LoRa.print(outgoing);                 // add payload
  LoRa.endPacket();                     // finish packet and send it
  msgCount++;                           // increment message ID
}

LoRa Nodes Codes Explanation:

A detailed explanation of the Multiple LoRa Nodes Communication with Master LoRa Node program code is done in this video.

Simply copy the code to your Arduino IDE and upload the code to the respective LoRa Nodes. Don’t forget to choose the right COM port from the tools menu.

Multiple LoRa Nodes Communication with Master LoRa Node using Arduino

Conclusion

So, this is how we connect multiple Lora Nodes with the Master Lora Node for wireless communication system using LoRa SX1278 Module and Arduino. I hope the tutorial was helpful for you. In upcoming projects, I will make a network in which the Master Node will request data from the multiple Slave Nodes and upload data to the IoT Platform. Till then stay happy, stay safe.


Related Articles

4 Comments

  1. Bro plz make smart health monitoring system using node MCU and online website which can measure our heart beat,O2,body temperature and room temperature .

  2. Hi,Thank you for sharing this impressive project, but i have question after reading article, that is i was wondering the “Node”, can i add infinite “Node” to the network? and how this LoRa network topology looks like? can i daisy chain these node? thx for reply, if you can pls mail me 😀 i’m dying to find the answer~

  3. Hello ,
    multi node lora topic
    I would like to have a circuit with a soil moisture lora transmitter (nano card).
    and another circuit with an ssd1306 which displays the soil humidity and a relay which sticks when the humidity is 80%.
    possible (uno card) .
    email: [email protected]

    1. Hello all,
      Hope all doing well.
      I am building smart irrigation project, for that I have bought 3 Reyax RYLR998 Lora modules.
      I have connected one node to ESP8266 and made it gateway, and other two nodes are connected to ESP8266 which are slave node.
      Slave node collect sensor data and send to gateway send commands to each node to operate relays connected to it.
      Unfortunately, it does not work when I use two slave node, it works for one node to other node only.
      So how to implement it? I googled it, could not find satisfactory solution.

      Could you please share docs/links which shows, how to implement multiple Reyax RYLR998 lora nodes?

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button