Introduction: LoRa->4G Gateway_Soil Monitoring With Cloud Server Via 4G

I have a LoRa Soil Moisture Sensor, but I want to use 4G to monitor soil remotely from the cloud server, so I made this LoRa to 4G device.

Supplies

What you need are just the following:

Note: detect the soil moisture/air humidity/temperature and broadcast every 60 minutes.

This gateway is composed of an ESP32S3 4G LTE A7670 module and a LoRa radio expansion

Note: LoRa communication needs the sender& receiver to work at the same frequency. The frequency of the LoRa Soil Moisture Sensor is 915MHz, so the frequency of the LoRa Expansion Board needs to be 915MHz as well.

Step 1: Hardware

  • Connect the pins of both boards as indicated in the photo above
  • Insert the SIM card into the slot on the back of the ESP32S3 based 4G LTE module


Step 2: Thingspeak

ThingSpeak Is The Open IoT Platform With MATLAB Analytics.

  • Register and log in to your account
  • Define the parameter you want on the Channel page and save it.
  • On the API keys page, you can find the API key used to write the data, and you can see an example of an API request on the right.
  • By accessing the URL of the write channel, you can modify the parameters, and the result you can view at "Private View" page.

Step 3: Software

  • First, we need to prepare the environment for ESP32 development board programming in Arduino, and you can check this guide.
  • RadioLib library is a wireless communication library. It supports a variety of wireless communication modules, including LoRa, NRF24L01, SX127x, and more. Using the RadioLib library, you can easily add wireless communication capabilities to your Arduino projects, whether it's for data transfer, remote control, or sensor networks.
#include <RadioLib.h>
  • The SPI.h header file enables your Arduino project to use the functionality provided by the SPI library to communicate with external SPI devices.
#include <SPI.h>
  • Define the pins used to connect to the LoRa module. Set the LoRa module frequency, bandwidth, spreading factor, coding rate, output power, and leading code length. Initialise "radio" to represent the LoRa module and pass the appropriate pins and parameters.
HardwareSerial mySerial2(2);
#define DEBUG true
#define IO_RXD2 47
#define IO_TXD2 48
#define IO_GSM_PWRKEY 4
#define IO_GSM_RST 5
// LoRa
#define LORA_MOSI 16 // 23
#define LORA_MISO 18 // 19
#define LORA_SCK 8 // 18
#define LORA_CS 17 // 21
#define LORA_RST 15 // 22
#define LORA_DIO0 9 // 32
#define LORA_DIO1 14 // 35
#define FREQUENCY 915.0
#define BANDWIDTH 125.0
#define SPREADING_FACTOR 9
#define CODING_RATE 7
#define OUTPUT_POWER 10
#define PREAMBLE_LEN 8
#define GAIN 0
SX1276 radio = new Module(LORA_CS, LORA_DIO0, LORA_RST, LORA_DIO1, SPI, SPISettings());
  • Initialize your devices so that they work properly


    mySerial2.begin(115200,SERIAL_8N1, IO_RXD2, IO_TXD2);
    pinMode(IO_GSM_RST, OUTPUT);
    digitalWrite(IO_GSM_RST, LOW);

    pinMode(IO_GSM_PWRKEY, OUTPUT);
    digitalWrite(IO_GSM_PWRKEY, HIGH);
    delay(3000);
    digitalWrite(IO_GSM_PWRKEY, LOW);


    SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);

    Serial.print(F("[SX1276] Initializing ... "));


    int state = radio.begin(FREQUENCY, BANDWIDTH, SPREADING_FACTOR, CODING_RATE, SX127X_SYNC_WORD, OUTPUT_POWER, PREAMBLE_LEN, GAIN);
    // int state = radio.begin();
    if (state == ERR_NONE)
    {
        Serial.println(F("success!"));
    }
    else
    {
        Serial.print(F("failed, code "));
        Serial.println(state);
        while (true);

    }
 Serial.print(F("Waiting for incoming transmission ... "));
String str;
  int state = radio.receive(str);


  // you can also receive data as byte array
  /*
    size_t len = 8;
    byte byteArr[len];
    int state = radio.receive(byteArr, len);
  */


  if (state == ERR_NONE) {
    // packet was successfully received
    Serial.println(F("success!"));


    // print data of the packet
    Serial.print(F("Data:\t\t\t"));
    Serial.println(str);


    // print RSSI (Received Signal Strength Indicator)
    // of the last received packet
    Serial.print(F("RSSI:\t\t\t"));
    Serial.print(radio.getRSSI());
    Serial.println(F(" dBm"));


    // print SNR (Signal-to-Noise Ratio)
    // of the last received packet
    Serial.print(F("SNR:\t\t\t"));
    Serial.print(radio.getSNR());
    Serial.println(F(" dB"));


    // print frequency error
    // of the last received packet
    Serial.print(F("Frequency error:\t"));
    Serial.print(radio.getFrequencyError());
    Serial.println(F(" Hz"));


  } else if (state == ERR_RX_TIMEOUT) {
    // timeout occurred while waiting for a packet
    //Serial.println(F("timeout!"));


  } else if (state == ERR_CRC_MISMATCH) {
    // packet was received, but is malformed
    Serial.println(F("CRC error!"));


  • Extract the number from the received message and store it in an array, modify the write channel URL given by ThingSpeak according to the array data
String numbers[10];

int extractNumbers(String input, String numbers[]) {
  int count = 0;
  String number = "";

  for (int i = 0; i < input.length(); i++) {
    char c = input.charAt(i);


    if (isDigit(c) || c == '.') {
      number += c;
    }


    else if (c == ' ' && number != "") {
      numbers[count++] = number;
      number = "";
    }
  }



  if (number != "") {
    numbers[count++] = number;
  }

  return count;
}

String http_str = "AT+HTTPPARA=\"URL\",\"http://api.thingspeak.com/update?api_key=" + Apikey + "&field1=" + numbers[1] +"&field2=" + numbers[2] + "&field3="+ numbers[3] +"&field4="+ numbers[4]+"&field5="+ numbers[5] +"\"\r\n";
  • Controlling LTE Access to Write Channel URLs Using AT Commands
String Apikey = "ANPNRNZOVQO0UBRY";

sendData("AT", 1000, DEBUG);
delay(3000);
sendData("AT+CICCID", 1000, DEBUG);
delay(3000);
sendData("AT+SIMCOMATI", 1000, DEBUG);
delay(3000);
sendData("AT+COPS?", 1000, DEBUG);
delay(3000);
sendData("AT+CPIN?", 3000, DEBUG);
delay(3000);
sendData("AT+CSQ", 1000, DEBUG);
delay(3000);
sendData("AT+CREG?", 1000, DEBUG);
delay(3000);
sendData("AT+CGREG?", 1000, DEBUG);
delay(3000);
sendData("AT+CPSI?", 1000, DEBUG);
delay(3000);
sendData("AT+CGDCONT=1,\"IP\",\"CMNET\"", 1000, DEBUG);
delay(3000);
sendData("AT+CGATT=1", 1000, DEBUG);
delay(3000);

String http_str = "AT+HTTPPARA=\"URL\",\"http://api.thingspeak.com/update?api_key=" + Apikey + "&field1=" + numbers[1] +"&field2=" + numbers[2] + "&field3="+ numbers[3] +"&field4="+ numbers[4]+"&field5="+ numbers[5] +"\"\r\n";
sendData("AT+HTTPINIT\r\n", 2000, DEBUG);
delay(2000);
sendData(http_str, 2000, DEBUG);
delay(2000);
sendData("AT+HTTPACTION=0\r\n", 3000, DEBUG);
delay(2000);
sendData("AT+HTTPTERM\r\n", 3000, DEBUG);
delay(2000);

Step 4: Result

Insert two AAA batteries into the Lora Temperature/ Humidity/ Soil Moisture Sensor V3 battery compartment, burn the code into the ESP32S3 based 4G LTE module, and open the serial port, when ESP32S3 based 4G LTE module successfully receives the Lora Temperature/ Humidity/ Soil Moisture Sensor V3 information, it can extract the data and request the URL of the write channel of Thingspeak to upload the data to the "Private View" page.