Introduction: ESP32 LORA: Gas Sensor, Humidity, and Temperature by SMS – Part 2

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Continuing the subject we discussed last Friday, in today’s article and video we return to the creation of extremely useful devices for your home or workplace, in regard to the Internet of Things. As we have shown, you can use safety sensors that involve gas, temperature, and humidity (just as examples), with an ESP32 LORA. This enables you to set up an alarm that sends an SMS message to your smartphone, in the unfortunate event of a gas leak, as an example.

In the first part of this video: ESP32 LORA: Gas Sensor, Humidity, and Temperature by SMS – Part 1, we use an MQ2 gas sensor module and a DHT22 (AM2302) temperature and humidity sensor. As you can see in the image below, both are read by the first ESP32 LORA, which will function as the Sender. It will then send an alert to the second ESP32 LORA, which will be the Receiver, in case there is any intercurrence.

Via UART, the Receiver will send the information to the Arduino Nano. Via SPI, this makes cable communication the internal network, making you independent from a 2.4 WiFi network. Then, from the communication with the Server, this activates a gateway that will send an SMS to your cell phone.

Now, in this third and last part, we will do a brief review of the prototype's operation with ESP32 LORA. We will start with the .INO code of the Receiver, as well as the Arduino Nano.

Step 1: Receiver - Organization of the Code

1. Setup

2. Loop

2.1. readPacket: Function responsible for reading the bytes of the received packet, and the assigning to a String.

2.1.1. showDisplay: Function responsible for displaying a message on the display, with the fonts and alignments already configured.

2.1.2. Alarm: Function responsible for activating the buzzer for 1 second.

Step 2: Receiver Code [Includes and Defines]

So, similarly to the Sender, we will include the libraries and make the pin definition at the beginning of the RECEIVED code. Also, let's select the radio frequency, add parameters, and point details of the data packet and buzzer.

#include <SPI.h> //serial peripheral interface (SPI) library
#include <LoRa.h> //wifi lora library
#include <Wire.h>  //communication i2c library
#include "SSD1306.h" //display communication library

// Pins definition 
#define SCK     5   // GPIO5  -- SX127x's SCK
#define MISO    19  // GPIO19 -- SX127x's MISO
#define MOSI    27  // GPIO27 -- SX127x's MOSI
#define SS      18  // GPIO18 -- SX127x's CS
#define RST     14  // GPIO14 -- SX127x's RESET
#define DI00    26  // GPIO26 -- SX127x's IRQ(Interrupt Request)

#define BAND    433E6  //Radio frequency, we can still use: 433E6, 868E6, 915E6
//parameters: address,SDA,SCL 
SSD1306 display(0x3c, 4, 15); 
//display object
String packSize; 
//variable used to receive the size of package converted in string
String packet;
//variable used to receive the package
const int buzzerpin = 13; 
//buzzer

Step 3: Receiver Code [Setup]

In the Setup, we will initialize the serial, and configure the buzzer and display operation.

void setup() 
{
  //initialize the Serial with 9600b per second
  Serial.begin(9600);
  //configures buzzer as output
  pinMode(buzzerpin, OUTPUT);    
  //configures oled pins as output
  pinMode(16,OUTPUT);
  //reset oled
  digitalWrite(16, LOW);   
  //waits 50ms
  delay(50); 
  //while the oled is on, GPIO16 must be HIGH
  digitalWrite(16, HIGH);
  //initializes the display
  display.init();
  //flip vertically the display
  display.flipScreenVertically();  
  //set display font 
  display.setFont(ArialMT_Plain_10);
  //waits 1500ms
  delay(1500);

Then, we start the serial with LORA, configure the pins that will be used by the library, and initialize the LORA with the specific frequency. We will enable it to receive data.

//clear the display
  display.clear();
  //initializes serial interface
  SPI.begin(SCK,MISO,MOSI,SS); 
  //set Lora pins
  LoRa.setPins(SS,RST,DI00); 
  //initializes the lora, seting the radio frequency
  if (!LoRa.begin(BAND)) 
  {
	//draw in the position 0,0 the message in between quotation marks
    display.drawString(0, 0, "Starting LoRa failed!");
    //turns on the LCD display
    display.display();
	//do nothing forever
    while (1);
  }
  //sets lora as receiver
  LoRa.receive(); 
}

Step 4: Receiver Code [Loop]

Here in the Loop, we make new definitions on the display.

void loop() 
{
  //clear display
  display.clear();
  //set the text alignment to left
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  //sets the text font
  display.setFont(ArialMT_Plain_16);
  //draw in the position 0,0 the message in between quotation marks
  display.drawString(0, 0, "Running...");
  //turns on the LCD display
  display.display();
  
  //parsePacket: check if a packet was received
  int packetSize = LoRa.parsePacket();
  //if a packet was received
  if (packetSize) 
  { 
    //reads byte to byte and concatenates to string  "packet"
    readPacket(packetSize);  
  }
  //waits 10ms
  delay(10);
}

Step 5: Receiver Code [readPacket]

We define the function that deals with the reception of package contents, display date in the display, and the firing of the buzzer.

//reads byte to byte and concatenates to string  "packet"

void readPacket(int packetSize) 
{
  //sets string to ""
  packet ="";</p><p>  //reads byte to byte and concatenates to string  "packet"
  for (int i = 0; i < packetSize; i++) 
  { 
    packet += (char) LoRa.read(); 
  }  
  
  // if the received message contains "alarm", then turns on the buzzer
  if(strstr(packet.c_str(),"ALARM")!=NULL)
  {
    //shows packet to the serial
    Serial.println(packet);
    //shows 'gas detected' to the serial
    showDisplay("Gas Detected!");
    //turns on the buzzer
    alarm();
  }
}

Step 6: Receiver Code [alarm and ShowDisplay]

In this part of the code, we deal with the activation of the alarm, as well as the display data related to this measurement in the display.

void alarm()

{
  //turns on the buzzer
  digitalWrite(buzzerpin, HIGH);
  //waits 1s
  delay(1000);  
  //turns off the buzzer
  digitalWrite(buzzerpin, LOW);
}

void showDisplay(String msg)
{
  //clear display
  display.clear();
  //set the text alignment to left
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  //sets the text font
  display.setFont(ArialMT_Plain_16);
  //draw in the position 0,25 the message in between quotation marks
  display.drawString(0 , 25 , msg); 
  //turns on the LCD display
  display.display();  
}

Step 7: Arduino Nano – Code Organization

In this project, we use the Arduino as a kind of bridge.

Setup - startEthernet: Function responsible for initiating the Ethernet client connection.

Loop - splitString: Function responsible for "removing" the values of humidity and temperature of the string received by the serial.

Step 8: Arduino Code [Includes and Defines]

First, let's include the SPI lib, as well as the Ethernet library for the ENC28J60 module. We work with the configuration of the LEDs, the structure to house the MAC Address, and the SMS sending gateway, as well as the IP of the network destined for the Ethernet module. We identify the internal network and the Client object. We use a Flag, which allows only one message to be sent.

#include <SPI.h> //Serial Peripheral Interface (SPI) library
#include <UIPEthernet.h> //Ethernet ENC28J60 module library
#define GREENLED 7 //green led pin 
#define REDLED 8   //red led pin
//mac address (1,2,3,4,5) to ethernet configuration
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
//sms sender gateway
char gateway[] = "111.11.111.1";   
//network ip to the ethernet module (conected with cable)
IPAddress ip(111,11,111,11);
//Ethernet object to client conections
EthernetClient client;
//Humidity and Temperature
String H,T;
//Flag that allows only one message to be sent
bool messageSent = false;

Step 9: Arduino Code [Setup]

Again, we will initialize the serial, define the pins, and configure the Ethernet client.

void setup()
{
  //initialize the Serial with 9600b per second
  Serial.begin(9600);</p><p>  //while the serial is not started, wait
  while (!Serial);</p><p>  //show message
  Serial.println("Serial ok");
    
  //set the green led pin as output
  pinMode(GREENLED,OUTPUT);
  //set the red led pin as output
  pinMode(REDLED,OUTPUT);</p><p>  //function responsible for initializing and connecting the ethernet client
  Ethernet.begin(mac, ip);
  //give to Ethernet Shield a second to be initialize
  delay(1000);
  
  //light up green led
  digitalWrite(GREENLED,HIGH); 
}

We have determined that the green LED should flash if Ethernet is not initialized.

else<br>      {
        Serial.println("Connecting failed...");
        digitalWrite(GREENLED,HIGH);
        delay(500);
        digitalWrite(GREENLED,LOW);
        delay(500);
        digitalWrite(GREENLED,HIGH);
        delay(500);
        digitalWrite(GREENLED,LOW);
      }

Step 10: Arduino Code [startEthernet]

In this part, we will configure the Ethernet client network data and the messages to be displayed on the display.

//function responsible for initializing and connecting the ethernet client
  Ethernet.begin(mac, ip);
  //give to Ethernet Shield a second to be initialize
  delay(1000);

Step 11: Arduino Code [Loop]

In the Loop, we check if there is available data sent by the serial. Also, we verify that the client is connected.

void loop()
{
  //if serial data exists
  if(Serial.available())
  {</p><p>if (client.connected() && client.available()) <br>  {
    char c = client.read();
    Serial.print(c);
  }</p><p>  //if client disconnected 
  if (!client.connected()) 
  {
    //stop client
    client.stop();
    delay(1);
  }
}

If the client is connected, it reads the message sent by the serial.

//read the message
    String msg = Serial.readString();
    
	//if the substring "ALARM" exists in the message and the message has no sent yet
    if(strstr(msg.c_str(),"ALARM")!=NULL && !messageSent)
    {
		//split the message and obtains the humidity and temperature values
      splitString(msg);</p><p>      Serial.println("Packet: "+msg);
      
      if (client.connect(gateway, 80)) 
      {
        //shows message
        Serial.println("connected");
        //send sms
        client.println("GET /script/sms/my_script_sms.php?humidity="+H+"&temperature="+T+" HTTP/1.1");
        client.println("Host: 111.11.111.1");
        client.println();
        
        //shows message
        Serial.println("Message sent!");
		//light up red led to indicate the message has been sent
        digitalWrite(REDLED,HIGH);</p><p>//set true to flag, it blocks multiples sends
      messageSent = true;
    }
  }

In the case that the client is disconnected, the disconnection will be signaled and the green LED will be erased.

//if client disconnected
  if (!client.connected()) 
  {
    //stop client
    client.stop();
    delay(1);
  }
}

Step 12: Arduino Code [splitString]

In this function, we assign the values to variables such as humidity and temperature, for example.

//Message example: ALARM|30.12|27.82°C<br>//split the message, obtaining the H and T values
void splitString(String msg)
{
  //sets strings to ""
  H = T = "";

  int i;

  //finds the delimiter "|" and ignores the "ALARM" substring
  for(i=0; i< msg.length() && msg.charAt(i)!='|'; i++);

  i++;

  //finds the next delimiter obtaining the humidity value
  while(i< msg.length() && msg.charAt(i)!='|')
  {
    H+=msg.charAt(i);
    i++;
  }
  i++;
  
  //finds the "°" symbol obtaining the temperature value
  while(i< msg.length() && msg.charAt(i)!='°')
  {
    T+=msg.charAt(i);
    i++;
  }
}

Step 13: SMS Messaging Script

* You need an SMS gateway for the script to work! Why did I choose to use a PHP script? Because, regardless if you want to send SMS, call, send email, among others, you take your data and put it on a SQL database. This is your base, so you won’t need to pay for a company, as you’ll have a rented server, which is cheaper. It’s possible to store many terabytes of information for cheap.

It’s important to point out that Gateway-SMS is a company that I pay for sending messages, and this can be per month or per unit.

I also remind you that you’ll need to make two changes in this code to make this assembly: in the customer ID that you’ll receive from the company that manages SMS sending and in the mobile number where you’ll put your telephone number.

<?php</p><p><?php <br-->$umidade = $_GET['umidade'];
$temperatura = $_GET['temperatura'];
header ('Content-type: text/html; charset=UTF-8');
function post_to_url($url, $data) 
{
 $fields = http_build_query($data);
 $post = curl_init();
 $url = $url.'?'.$fields;
 curl_setopt($post, CURLOPT_URL, $url);
 curl_setopt($post, CURLOPT_POST, 1);
 curl_setopt($post, CURLOPT_POSTFIELDS, $fields);
 $result = curl_exec($post);
 if($result == false)
 {
  die('Curl error: ' . curl_error($post));
 }
 curl_close($post);
}
$url = "https://GateWay-SMS";
$data = array
(
  'content' => 'Gás detectado!!!Umidade do ar:'.$umidade.' -Temperatura:'.$temperatura.' C',
  'sender' => 'ID',  'receivers' => '18900000000'
);
    post_to_url($url, $data);
?>

Step 14: SMS Gateway

https://sms.comtele.com.br/

This is the Gateway company I use. It guarantees the sending of the message to the operator.

Se more on my site: www.fernandok.com