banner

Ir para o Forum

ESP32 LORA: Sensor de Gás, Umidade e Temperatura por SMS - Pt3



Dando continuidade ao assunto que tratamos na última sexta-feira, no vídeo e no artigo de hoje vamos retomar a possibilidade de criar dispositivos bastante uteis no que diz respeito à Internet das Coisas. Utilizando o nosso exemplo, você poderá usar sensores destinados à segurança, envolvendo gás, temperatura e umidade, por exemplo, com um ESP32 Lora. Estes vão te possibilitar a montagem de um alarme que vai enviar mensagem SMS para o seu smartphone em caso de algum tipo de problema, como um vazamento de gás, por exemplo.

Esp32 Lora: sensor de gás, umidade e temperatura por SMS com Sender e Receiver

Na 1ª parte deste vídeo: ESP32 LORA: SENSOR DE GÁS, UMIDADE E TEMPERATURA POR SMS - Pt1, utilizamos, então, um módulo sensor de gás MQ2 e um sensor de temperatura e umidade DHT22 (AM2302). Como você pode ver na imagem abaixo, ambos são lidos por um primeiro ESP32 Lora, que funcionará como Sender, e enviará alerta para um segundo ESP32 Lora, que estará como Receiver, caso haja alguma intercorrência.
Via UART, o Receiver vai mandar as informações para o Arduino Nano, que via SPI faz comunicação de cabo como a rede interna, te deixando independente da um rede WiFi 2.4. Então, a partir da comunicação com o Server, este ativa um gateway que vai enviar um SMS para o seu celular.


Funcionamento da Transmissão de Dados

Agora, nesta 3ª e última parte, vamos fazer uma breve revisão do funcionamento do protótipo com ESP32 Lora e partiremos para o código .INO do Receiver, bem como do Arduino Nano.

Código Receiver

Receiver – Organização do código

Organização do código - Receiver

1. Setup
2. Loop
2.1. readPacket: Função responsável por ler os bytes do pacote recebido e atribuir para uma String.
2.1.1. showDisplay: Função responsável por exibir uma mensagem no display com as fontes e alinhamentos já configurados.
2.1.2.   Alarm: Função responsável por ativar o buzzer durante 1 segundo.

Código Receiver[Includes e Defines]

Assim, como no Sender, neste início do código do Receiver, vamos incluir as bibliotecas e fazer a definição dos pinos. Ainda, vamos selecionar a frequência de rádio, adicionar parâmetros e apontar detalhes do pacote de dados e do buzzer.

#include <SPI.h> //responsável pela comunicação serial
#include <LoRa.h> //responsável pela comunicação com o WIFI Lora
#include <Wire.h>  //responsável pela comunicação i2c
#include "SSD1306.h" //responsável pela comunicação com o display

// Definição dos pinos 
#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  //Frequencia do radio - podemos utilizar ainda : 433E6, 868E6, 915E6

//parametros: address,SDA,SCL 
SSD1306 display(0x3c, 4, 15); //construtor do objeto que controlaremos o display

String packSize; //tamanho do pacote convertido em String
String packet; //pacote recebido
const int buzzerpin = 13; //buzzer

Código Receiver [Setup]

Setup

No Setup, vamos inicializar a serial, configurar o buzzer e o funcionamento do display.

void setup() 
{
  //inicia serial com 9600 bits por segundo
  Serial.begin(9600);
  //configura buzzer como saída
  pinMode(buzzerpin, OUTPUT);    
  //configura RST do oled como saida
  pinMode(16,OUTPUT);
  //reseta o OLED
  digitalWrite(16, LOW);   
  //aguarda 50ms
  delay(50); 
  //enquanto o OLED estiver ligado, GPIO16 deve estar HIGH
  digitalWrite(16, HIGH);
  //inicializa display
  display.init();
  //inverte a tela verticalmente (de ponta cabeça)
  display.flipScreenVertically();  
  //configura a fonte do display
  display.setFont(ArialMT_Plain_10);
  //aguarda 1500ms
  delay(1500);


Na sequência, iniciamos a serial com o Lora, configuramos os pinos que serão utilizados pela biblioteca e inicializamos o Lora com a frequência específica. Habilitamos o mesmo para receber dados.

//limpa display
  display.clear();
  //inicia a comunicação serial com o Lora
  SPI.begin(SCK,MISO,MOSI,SS); 
  //configura os pinos que serão utlizados pela biblioteca (deve ser chamado antes do LoRa.begin)
  LoRa.setPins(SS,RST,DI00); 
  //inicializa o Lora com a frequencia específica.
  if (!LoRa.begin(BAND)) 
  {
    //escreve na pos 0,0 a mensagem em aspas
    display.drawString(0, 0, "Starting LoRa failed!");
    //exibe no display
    display.display();
    //deixa em loop infinito até que o ESP seja reiniciado
    while (1);
  }
  //habilita o Lora para receber dados
  LoRa.receive(); 
}


Código Receiver [Loop]

Loop

Aqui no Loop, fazemos novas definições sobre o display.

void loop() 
{
  //limpa display
  display.clear();
  //configura alinhamento de texto à esquerda
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  //configura fonte do texto
  display.setFont(ArialMT_Plain_16);
  //escreve na pos 0,10 a mensagem entre aspas
  display.drawString(0, 0, "Running...");
  //exibe no display
  display.display();

  //parsePacket: checa se um pacote foi recebido
  //retorno: tamanho do pacote em bytes. Se retornar 0 (ZERO) nenhum pacote foi recebido
  int packetSize = LoRa.parsePacket();
  //caso tenha recebido pacote 
  if (packetSize) 
  { 
    //chama a função responsável por recuperar o conteúdo do pacote recebido
    readPacket(packetSize);  
  }
  //aguarda 10ms
  delay(10);
}


Código Receiver [readPacket]

readPacket

Definimos a função que trata do recebimento de conteúdo do pacote, exibição de dados no display e disparo do buzzer.

//função responsável por recuperar o conteúdo do pacote recebido
//parametro: tamanho do pacote (bytes)
void readPacket(int packetSize) 
{
  //deixa string com valor vazio
  packet ="";

  //lê byte a byte do pacote e atribui à string "packet"
  for (int i = 0; i < packetSize; i++) 
  { 
    packet += (char) LoRa.read(); //recupera o dado recebido e concatena na variável "packet"
  }  
  
  //se a mensagem recebida contem "alarm", então soa o buzzer
  if(strstr(packet.c_str(),"ALARM")!=NULL)
  {
    //exibe pacote
    Serial.println(packet);
    //exibe no display
    showDisplay("Gas Detected!");
    //soa o buzzer
    alarm();
  }
}


Código Receiver [alarm e showDisplay]

showDisplay e alarm

Nesta parte do código, tratamos da ativação do alarme, bem como a exibição de dados relacionados a esta medida no display.

void alarm()
{
  //ativa buzzer
  digitalWrite(buzzerpin, HIGH);
  //aguarda 1 segundo
  delay(1000);  
  //desativa buzzer
  digitalWrite(buzzerpin, LOW);
}

//exibe mensagem recebida como parâmetro
void showDisplay(String msg)
{
  //limpa o display
  display.clear();
  //configura alinhamento de texto à esquerda
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  //configura fonte do texto
  display.setFont(ArialMT_Plain_16);
  //escreve na pos 0,25 a mensagem
  display.drawString(0 , 25 , msg); 
  //exibe no display
  display.display();  
}


Código Arduino Nano

Arduino – Organização do código

Neste nosso projeto, utilizamos o arduino como uma espécie de ponte.

Funções Setup e Loop

Setup startEthernet: Função responsável por iniciar a conexão do client ethernet.
Loop splitString: Função responsável por “retirar” os valores de umidade e temperatura da string recebida pela serial.

Código Arduino[Includes e Defines]

Primeiramente vamos incluir a lib SPI, assim como a biblioteca Ethernet para o módulo ENC28J60. Abordamos a configuração dos leds, da estrutura para abrigar o MAC Address, gateway de envio de SMS, bem como IP da rede destinada ao módulo Ethernet. Identificamos a rede interna e o objeto Client. Utilizamos uma Flag, que permite apenas um envio de mensagem.

#include <SPI.h> //lib para a Serial Peripheral Interface (SPI)
#include <UIPEthernet.h> //lib Ethernet para o módulo ENC28J60

#define GREENLED 7 //pino led verde
#define REDLED 8   //pino led vermelho

//endereço mac (1,2,3,4,5) para a configuração ethernet
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};

//gateway de envio de SMS 
char gateway[] = "111.11.111.1";   

//ip da rede destinado ao módulo ethernet (conectado por cabo)
IPAddress ip(111,11,111,11);

//objeto Ethernet para conexões de clientes
EthernetClient client;

//Humidade e Temperatura
String H,T;

//Flag que permite apenas um envio de mensagem
//O envio fica dentro do  "loop()" , assim que o arduino recebe dados na porta serial ele envia a mensagem
//Caso esta flag não exista, um número descontrolado de mensagens será enviado
bool messageSent = false;


Código Arduino[Setup]

Setup

Novamente vamos inicializar a serial e definir os pinos, além de configurar o client ethernet.

void setup()
{
  //inicializa Serial com 9600 bits por segundo
  Serial.begin(9600);

  //enquanto a serial não for inicializada, aguarda
  while (!Serial);

  //exibe mensagem
  Serial.println("Serial ok");
    
  //define pino do led verde como saída
  pinMode(GREENLED,OUTPUT);
  //define pino do led vermelho como saída
  pinMode(REDLED,OUTPUT);

  //inicializa e configura o client ethernet
  if(startEthernet())
  {
    //acende o led verde
    digitalWrite(GREENLED,HIGH);
  }


Definimos que o led verde deverá piscar caso a ethernet não seja inicializada.

 else
  {
    //se a ethernet não for inicializada
    //pisca led vermelho
    digitalWrite(GREENLED,HIGH);
    delay(500);
    digitalWrite(GREENLED,LOW);
    delay(500);
    digitalWrite(GREENLED,HIGH);
    delay(500);
    digitalWrite(GREENLED,LOW);
  }
}


Código Arduino[startEthernet]

startEthernet

Nesta parte, vamos configurar os dados de rede do cliente ethernet e as mensagens a serem exibidas no display.

//Obs: As exibições na serial (Serial.println) são apenas para verificações, ao serem retiradas do código não mudarão o funcionamento do protótipo
//função responsável por inicializar e conectar o client ethernet
//este booleano pode ser retirado! pois sempre retornará true
bool startEthernet()
{
  //configura dados de rede
  Ethernet.begin(mac, ip);
  //dá ao Ethernet Shield um segundo para inicializar
  delay(1000);
  return true;
  
}


Código Arduino[Loop]

Loop

No Loop, verificamos se existem dados disponíveis enviados pela serial. Ainda, verificamos se o cliente está conectado.

void loop()
{
  //se existem dados enviados pela serial
  if(Serial.available())
  {

  if (client.connected() && client.available()) 
  {
    char c = client.read();
    Serial.print(c);
  }

  //se o client está desconectado
  if (!client.connected()) 
  {
    //desconecta client
    client.stop();
    delay(1);
  }
}


Caso o cliente esteja conectado, este lê mensagem enviada pela serial.

//lê mensagem enviada pela serial
    String msg = Serial.readString();
    
    //se na mensagem existir a palavra "ALARM" e o SMS ainda não estiver sido enviado
    if(strstr(msg.c_str(),"ALARM")!=NULL && !messageSent)
    {
      //"desmembra" mensagem e atribui para as variáveis os valores de Humidade e Temperatura
      splitString(msg);

      Serial.println("Packet: "+msg);
      
      if (client.connect(gateway, 80)) 
      {
        //exibe mensagem
        Serial.println("connected");
        //envia sms
        client.println("GET /script/sms/meu_script_sms.php?umidade="+H+"&temperatura="+T+" HTTP/1.1");
        client.println("Host: 111.11.111.1");
        client.println();
        
        //exibe mensagem enviada
        Serial.println("Message sent!");
        //sinaliza que enviou acendendo o led vermelho
        digitalWrite(REDLED,HIGH);
  //atribui true para a flag, evitando múltiplos envios
      messageSent = true;
    }
  }


Já no caso do cliente estar desconectado, será sinalizada a desconexão e o led verde será apagado.

 //se o client está desconectado
  if (!client.connected()) 
  {
    //desconecta client
    client.stop();
    delay(1);
  }


Código Arduino[splitString]

splitString

Nesta função, atribuímos os valores às variáveis, como umidade e temperatura, por exemplo.

//Exemplo de mensagem: ALARM|30.12|27.82°C
//"desmembra" mensagem atribuindo os valores às variáveis
void splitString(String msg)
{
  //inicia variáveis com vazio
  H = T = "";

  int i;

  //percorre string até encontrar o delimitador pipe "|"
  for(i=0; i< msg.length() && msg.charAt(i)!='|'; i++);

  i++;

  //percorre string até o próximo delimitador atribuindo valor de humidade
  while(i< msg.length() && msg.charAt(i)!='|')
  {
    H+=msg.charAt(i);
    i++;
  }

  i++;
  
  //percorre string até o símbolo "°" atribuindo valor de temperatura
  while(i< msg.length() && msg.charAt(i)!='°')
  {
    T+=msg.charAt(i);
    i++;
  }
}


Script de envio de Mensagens SMS

*É preciso um gateway de SMS para que o script funcione! Por que eu escolhi utilizar um script PHP? Porque, independentemente se você quer mandar SMS, fazer ligação, mandar e-mail, entre outros, você pega os seus dados e joga em uma base SQL. Essa base é sua, então, você não vai precisar ficar pagando para uma empresa, pois vai ter um servidor alugado, o que sai mais barato. É possível armazenar muitos Terabytes de informação pagando pouco.
Destaco que o Gateway-SMS é uma empresa que eu pago pelo envio de mensagens, isso por mensalidade ou por unidade.
Lembro ainda que obrigatoriamente você terá que fazer duas alterações neste código para realizar essa montagem: no ID de cliente que você vai receber da empresa que administra o envio de SMSs e no número de celular, onde você vai preencher o seu número de telefone.

<?php
$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);
?>



Gateway SMS

Essa é a empresa de Gateway que utilizo: https://sms.comtele.com.br/Ela garante o envio da mensagem até a operadora.

Site da empresa Gateway



Faça o download dos arquivos:



6 comentários:

  1. Bom dia Fernando!
    Um dúvida... Você já conseguiu usar um modulo SD card que é SPI junto com o Lora?
    Lora usa SPI pra transmissão e a ativação do SS é feito pela biblioteca....está difícil alterar as coisas! Tem alguma luz pra me ajudar?

    ResponderExcluir
    Respostas
    1. O contato contato@fernandok.com... É mais trocar uma idéia por lá? :D

      Excluir
  2. Esta com erro o link de download do arquivo .INO

    ResponderExcluir
    Respostas
    1. Olá, Hugo.
      Atualizamos o link. Pode tentar novamente, por favor?
      Abraço

      Excluir
  3. Fernando, você chegou a tentar ligar o ENC28J60 diretamente no ESP32 sem passar pelo Arduino Nano?

    ResponderExcluir
  4. olá, estou a ter computação ubíqua e Internet das coisas, e os teu vídeos estão a decepar todas as minhas duvidas, sou um fan seu.

    ResponderExcluir

Tecnologia do Blogger.