WiFi com LoRa – ESP32 LoRa

,

Olá, como estão? No post passado falamos sobre o ESP32 LoRa e a Rede LoRa, caso não tenha lido clique aqui, nele demos um exemplo de uso, um alarme de incêndio florestal. Entretanto caso quisesse supervisionar, porém você está em outra cidade ou fora do alcance do sinal LoRa. Nesse caso podemos utilizar a internet ao nosso favor, utilizando a rede LoRa com WiFi já que o ESP32 LoRa tem conectividade com outros dois tipos de rede sendo elas Bluetooth e WiFi.

ESP32 com LoRa - WJ Componentes
Icone WiFi

Componentes Utilizados


Funcionamento do Projeto WiFi com LoRa


Não iremos abordar muito afundo referente a WiFi nem LoRa pois já tivemos posts focados neles. Nesse projeto iremos utilizar a mesma lógica que utilizamos nos projetos de WiFi e iremos incrementar o LoRa que vimos no post passado, para assim poder utilizar as duas ao nosso favor.

Montagem do Projeto WiFi com LoRa


Então agora iremos utilizar o mesmo circuito do post passado.

Contudo segue abaixo uma imagem que demonstrando a montagem do circuito.

Montagem do Circuito Eletrônico na Protoboard - LoRa

Diagrama Esquemático do Projeto WiFi com LoRa


Diagrama do Circuito Eletrico - LoRa

Preparando a Arduíno IDE


Antes de mais nada na Arduíno IDE clique em Preferências e cole o link abaixo em “URLs Adicionais para Gerenciadores de Placas “e dê um OK.
URL: https://dl.espressif.com/dl/package_esp32_index.json

Em seguida, clique em Ferramentas -> Placas -> Gerenciador de placas, pesquise ESP32, selecione e clique em instalar.

Instalação ESP32 no Gerenciador de Placas

Logo após ser instalado, vá em Ferramentas -> Placas e selecione a placa Heltec WIFI LoRa 32(v2).

Assim que selecionar a placa clique em Ferramentas -> Gerenciar Bibliotecas, pesquise heltec, selecione Heltec ESP32 Dev-Boards.

Instalação da Biblioteca Heltec - LoRa

Assim que selecionar a placa clique em Ferramentas -> Gerenciar Bibliotecas, pesquise heltec, selecione Heltec ESP32 Dev-Boards.

Instalação da Biblioteca DHT Sensor

Código-fonte do Projeto WiFi com LoRa


Então agora iremos programar 2 ESP32 LoRa, um deles sendo o Sender o que envia os “pacotes”, e Reciver o que recebe os “pacotes”.

Programação Sender

Contudo o código do Sender foi dividido em três funções e dois arquivos. Entretanto sendo um arquivo o código e outro a imagem.

//Biblioteca -----------------------------------------------------------------------------------------
#include <heltec.h>                                                 // Responsável pelo display e LoRa
#include <DHT.h>                                                    // Responsável pelo DHT
#include <DHT_U.h>                                                  // Responsável pelo DHT
#include "images.h"                                                 // Responsável pela imagem

//LoRa - Variáveis Globais e Define ------------------------------------------------------------------
#define BAND 915E6                                                  // Frequência de banda
#define KEY  0xF3                                                   // Chave para receber pacote

//Variáveis Globais ----------------------------------------------------------------------------------
unsigned int counter = 0;                                           // Contador de pacotes
float temp = 0;                                                     // Temperatura
float umid = 0;                                                     // Umidade

//DHT11 - Variáveis Globais e Define -----------------------------------------------------------------
#define DHTPIN 32                                                   // Define o pino
#define DHTTYPE DHT11                                               // Define o sensor de temperatura
DHT dht(DHTPIN,DHTTYPE);                                            // Criando um objeto dht

//Função Auxiliares ----------------------------------------------------------------------------------
void logo();                                                        // Responsável por imprimir a logo

//Setup ----------------------------------------------------------------------------------------------
void setup(){
    dht.begin();                                                    // Inicializa o DHT11
    //Abaixo inicializa Display, LoRa, Serial, PABOOST, BAND
    Heltec.begin(true, true, true, true, BAND);
    LoRa.setSyncWord(KEY);                                          // Chave para receber o pacote
    Heltec.display->init();                                         // Inicializa o display
    Heltec.display->flipScreenVertically();                         // Vira na vertical
    Heltec.display->setFont(ArialMT_Plain_10);                      //Escolhe a fonte
    logo();                                                         // Chama função que imprime logo
    Heltec.display->drawString(0, 0, "ESP32 LoRa Iniciou");         // Escreve que foi Inicializado
    Heltec.display->drawString(0, 11, "com Sucesso!");
    Heltec.display->display();
    delay(1000);                                                    // Espera 1s
}

//Void -----------------------------------------------------------------------------------------------
void loop(){
    temp = dht.readTemperature();                                   // Leitura da Temperatura
    umid = dht.readHumidity();                                      // Leitura da Humidade
    Heltec.display->clear();                                        // Limpa o display 
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);              // Alinha o texto na esquerda
    Heltec.display->setFont(ArialMT_Plain_10);                      // Escolhe a fonte
    Heltec.display->drawString(0, 0, "Envio do Pacote: ");          // Imprime informação do pacote
    Heltec.display->drawString(90, 0, String(counter));             // Imprime numero do pacote
    Heltec.display->drawString(0, 11, "Temperatura: " + String(temp)); // Imprime informação
    Heltec.display->drawString(0, 22, "Umidade: " + String(umid));  // Imprime informação da umidade
    Heltec.display->display();

    /* LoRa.setTxPower(txPower,RFOUT_pin);
    * txPower -- 0 ~ 20
    * RFOUT_pin could be RF_PACONFIG_PASELECT_PABOOST ou RF_PACONFIG_PASELECT_RFO
    *  - RF_PACONFIG_PASELECT_PABOOST -- LoRa single saida via PABOOST, maxima saida 20dBm
    *  - RF_PACONFIG_PASELECT_RFO     -- LoRa single saida via RFO_HF / RFO_LF, maxima saida 14dBm */
  
    //Envio dos Pacotes
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("p");                                                // Informa que ira enviar o pacote
    LoRa.print(counter);                                            // Envia informação do pacote
    LoRa.endPacket();                                               // Fecha o pacote
    delay(10);                                                      // Espera 0,01s
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("t");                                                // Informa o envio da temperatura
    LoRa.print(temp);                                               // Envia informação da temperatura
    LoRa.endPacket();                                               // Fecha o pacote
    delay(10);                                                      // Espera 0,01s
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("u");                                                // Informa o envio da humidade
    LoRa.print(umid);                                               // Envia informação da humidade
    LoRa.endPacket();                                               // Fecha o pacote
    counter++;
    digitalWrite(LED, HIGH);                                        // Acende o LED da placa
    delay(500);                                                     // Espera 0,5s
    digitalWrite(LED, LOW);                                         // Apaga o LED da placa
    delay(500);                                                     // Espera 0,5s
}

//Logo -----------------------------------------------------------------------------------------------
void logo(){
    Heltec.display->clear();                                        // Limpa o display 
    Heltec.display->drawXbm(0,10,logo_width,logo_height,logo_bits); // Imprime imagem
    Heltec.display->display();
    delay(1500);                                                    // Espera 1,5s 
    Heltec.display->clear();                                        // Limpa o display
}

Vamos dar uma olhada mais de perto no código:

Incluindo Bibliotecas

Primeiramente temos que incluir as bibliotecas que usamos em nosso projeto.

//Biblioteca -----------------------------------------------------------------------------------------
#include <heltec.h>                                                 // Responsável pelo display e LoRa
#include <DHT.h>                                                    // Responsável pelo DHT
#include <DHT_U.h>                                                  // Responsável pelo DHT
#include "images.h"                                                 // Responsável pela imagem

Definições LoRa

Em seguida definimos a frequência e a chave (para garantir o recebimento receba apenas pacotes de seu remetente, para pode-se definir uma palavra de sincronização (entre 0 a 0xFF)) que usaremos no LoRa.

//LoRa - Variáveis Globais e Define ------------------------------------------------------------------
#define BAND 915E6                                                  // Frequência de banda
#define KEY  0xF3                                                   // Chave para receber pacote

Variáveis Globais

Logo após declaramos as variáveis globais que será o contador de pacotes, temperatura e umidade.

//Variáveis Globais ----------------------------------------------------------------------------------
unsigned int counter = 0;                                           // Contador de pacotes
float temp = 0;                                                     // Temperatura
float umid = 0;                                                     // Umidade

Definições DHT11

Então definimos o pino e o tipo do DHT (no nosso caso é o DHT11).

//DHT11 - Variáveis Globais e Define -----------------------------------------------------------------
#define DHTPIN 32                                                   // Define o pino
#define DHTTYPE DHT11                                               // Define o sensor de temperatura
DHT dht(DHTPIN,DHTTYPE);                                            // Criando um objeto dht

Funções Auxiliares

Logo após declaramos 1 função auxiliar que usamos no projeto.

//Funções Auxiliares ---------------------------------------------------------------------------------
void logo();                                                        // Responsável por imprimir a logo

Funções Setup

No setup primeiramente iremos inicializar o DHT e heltec com o display ligado, LoRa ligado, Serial ligado, PABOOST e com a frequência. Logo após isso sincronizamos o LoRa com a nossa chave.

//Setup ----------------------------------------------------------------------------------------------
void setup(){
    dht.begin();                                                    // Inicializa o DHT11
    //Abaixo inicializa Display, LoRa, Serial, PABOOST, BAND
    Heltec.begin(true, true, true, true, BAND);
    LoRa.setSyncWord(KEY);                                          // Chave para receber o pacote

Em seguida inicializamos também o display, viramos na vertical e escolhemos a fonte juntamente com o tamanho e chamamos a função para imprimir a logo no display. Logo após isso escrevemos no display que o ESP32 LoRa inicializou e esperamos 1s.

    Heltec.display->init();                                         // Inicializa o display
    Heltec.display->flipScreenVertically();                         // Vira na vertical
    Heltec.display->setFont(ArialMT_Plain_10);                      //Escolhe a fonte
    logo();                                                         // Chama função que imprime logo
    Heltec.display->drawString(0, 0, "ESP32 LoRa Iniciou");         // Escreve que foi Inicializado
    Heltec.display->drawString(0, 11, "com Sucesso!");
    Heltec.display->display();
    delay(1000);                                                    // Espera 1s
}

Funções Loop

Então agora na função loop, iremos armazenar a temperatura e umidade lida pelo DHT11. Logo depois limpamos o display e imprimimos todas as informações nele. Logo após imprimir, criamos os pacotes, cada pacote enviamos uma letra como referência e enviamos a informação. Então no total enviamos 3 pacotes.

//Void -----------------------------------------------------------------------------------------------
void loop(){
    temp = dht.readTemperature();                                   // Leitura da Temperatura
    umid = dht.readHumidity();                                      // Leitura da Humidade
    Heltec.display->clear();                                        // Limpa o display 
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);              // Alinha o texto na esquerda
    Heltec.display->setFont(ArialMT_Plain_10);                      // Escolhe a fonte
    Heltec.display->drawString(0, 0, "Envio do Pacote: ");          // Imprime informação do pacote
    Heltec.display->drawString(90, 0, String(counter));             // Imprime numero do pacote
    Heltec.display->drawString(0, 11, "Temperatura: " + String(temp)); // Imprime informação
    Heltec.display->drawString(0, 22, "Umidade: " + String(umid));  // Imprime informação da umidade
    Heltec.display->display();

    /* LoRa.setTxPower(txPower,RFOUT_pin);
    * txPower -- 0 ~ 20
    * RFOUT_pin could be RF_PACONFIG_PASELECT_PABOOST ou RF_PACONFIG_PASELECT_RFO
    *  - RF_PACONFIG_PASELECT_PABOOST -- LoRa single saida via PABOOST, maxima saida 20dBm
    *  - RF_PACONFIG_PASELECT_RFO     -- LoRa single saida via RFO_HF / RFO_LF, maxima saida 14dBm */
  
    //Envio dos Pacotes
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("p");                                                // Informa que ira enviar o pacote
    LoRa.print(counter);                                            // Envia informação do pacote
    LoRa.endPacket();                                               // Fecha o pacote
    delay(10);                                                      // Espera 0,01s
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("t");                                                // Informa o envio da temperatura
    LoRa.print(temp);                                               // Envia informação da temperatura
    LoRa.endPacket();                                               // Fecha o pacote
    delay(10);                                                      // Espera 0,01s
    LoRa.beginPacket();                                             // Cria pacote
    LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
    LoRa.print("u");                                                // Informa o envio da humidade
    LoRa.print(umid);                                               // Envia informação da humidade
    LoRa.endPacket();                                               // Fecha o pacote

Continuação Função Loop

Contudo como foi enviado o pacote acrescentamos +1 no contador e para sinalizar piscamos 1 vez o LED.

    counter++;
    digitalWrite(LED, HIGH);                                        // Acende o LED da placa
    delay(500);                                                     // Espera 0,5s
    digitalWrite(LED, LOW);                                         // Apaga o LED da placa
    delay(500);                                                     // Espera 0,5s
}

Função Logo

Então agora na função logo, será onde iremos limpar a tela e desenhamos a logo.

//Logo -----------------------------------------------------------------------------------------------
void logo(){
    Heltec.display->clear();                                        // Limpa o display 
    Heltec.display->drawXbm(0,10,logo_width,logo_height,logo_bits); // Imprime imagem
    Heltec.display->display();
    delay(1500);                                                    // Espera 1,5s 
    Heltec.display->clear();                                        // Limpa o display
}

E assim finalizamos todo código do Sender.

Programação Reciver

Contudo código do Reciver também foi dividido em cinco funções e dois arquivos. Entretanto sendo um arquivo o código e outro a imagem.

//Biblioteca ------------------------------------------------------------------------------------------
#include <WiFi.h>                                           // Responsável pelo WiFi
#include <heltec.h>                                         // Responsável pelo display e LoRa
#include "images.h"                                         // Responsável pelo imagem

//LoRa ------------------------------------------------------------------------------------------------
#define BAND 915E6                                          // Frequência de banda
#define KEY  0xF3                                           // Chave para receber pacote

//WiFi ------------------------------------------------------------------------------------------------
const char* SSID     = "<NOME-DA-REDE>";                    // Nome da rede WiFi
const char* password = "<SENHA-DA-REDE>";                   // Senha do WiFi
WiFiServer server(80);                                      // Declaração do servidor junto a sua porta

//Variáveis Globais -----------------------------------------------------------------------------------
String rssi = "RSSI --";                                    // Sinal
String packSize = "--";                                     // Tamanho do Pacote
String packet;                                              // Pacote
String temp;                                                // Temperatura
String umid;                                                // Umidade
 
//Função Auxiliares -----------------------------------------------------------------------------------
void logo();                                                // Responsável por imprimir a logo
void LoRaData();                                            // Responsável por imprimir no display
void cbk(int packetSize);                                   // Responsável pelas informações

//Setup -----------------------------------------------------------------------------------------------
void setup() { 
    //Abaixo inicializa Display, LoRa, Serial, PABOOST, BAND
    Heltec.begin(true, true, true, true, BAND);
    LoRa.setSyncWord(KEY);                                  // Chave para receber o pacote
    Heltec.display->init();                                 // Inicializa o display
    Heltec.display->flipScreenVertically();                 // Vira na vertical
    Heltec.display->setFont(ArialMT_Plain_10);              // Escolhe a fonte
    logo();                                                 // Chama função que imprime logo

    //WiFi
    WiFi.begin(SSID, password);                             // Tenta se conectar no WiFi
    while (WiFi.status() != WL_CONNECTED) {                 // Verifica se a Conexão foi realizada
        delay(500);                                         // Espera 0,5s
    }
    Serial.println(WiFi.localIP());                         // Mostra o IP do ESP32
    server.begin();                                         // Inicia o servidor

    Heltec.display->drawStri  ng(0, 0, "Esperando Pacote..."); // Escreve que foi Inicializado
    Heltec.display->display();
    delay(1000);                                            // Espera 1s
    LoRa.receive();                                         // Recebe Informação do LoRa
}

//Loop ------------------------------------------------------------------------------------------------
void loop() {
    int packetSize = LoRa.parsePacket();                    // Armazena a informação
    if (packetSize) { cbk(packetSize);  }                   // Chama a função para armazenar
    delay(10);                                              // Espera 0,1s
    WiFiClient cliente = server.available();
    if(cliente){
        Serial.println("Novo Cliente");
        String currentLine="";                              // Declara variável vazia
        while(cliente.connected()){                         // Faz loop enquanto tiver cliente conectado
            if(cliente.available()){                        // Verifica se tem algum dado sendo passado
                char c = cliente.read();                    // Atribui a C as informações do cliente
                if(c == '\n'){
                    if(currentLine.length() == 0){
                        cliente.println("HTTP/1.1 200 OK"); // Retorna para o Cliente que a solicitação dele deu certo
                        cliente.println("Content-type:text/html"); // Informa o iremos fazer um HTML
                        cliente.println("Connection: close");
                        cliente.println("");
                        
                        //HTML
                        cliente.println("<!DOCTYPE html><html lang=\"pt-br\">");
                        cliente.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
                        cliente.println("<title>ESP32 LoRa - WIFI</title>");

                        //CSS
                        cliente.println("<style>html { background-color: #edf2f9; font-size: 20px; font-family: cursive; display: inline-block; margin: 0px auto; text-align: center;}");
                        cliente.println(".card { background-color: white; margin: 10px; padding: 10px; border-radius: 10px; width: 50%; display: flex;}");
                        cliente.println(".text { width: 70%;}");
                        cliente.println(".image { padding-top: 10%;}");
                        cliente.println("#grid { display: inline-flex;}</style>");
                        cliente.println("");

                        //Body
                        cliente.println("<body><h1>ESP32 LoRa - Web Server</h1>");
                        cliente.println("<div id=\"grid\">");

                        //Pacote
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Pacote: ");
                        cliente.print(packet);
                        cliente.println("</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://cdn.icon-icons.com/icons2/1465/PNG/512/724package_100522.png\" width=\"50px\"></div></div>");

                        //Temperatura
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Temperatura: ");
                        cliente.print(temp);
                        cliente.println(" C</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://1.bp.blogspot.com/-ZlYO13BMP-Y/WTRMcflEZ9I/AAAAAAAAXKM/ihxY2eyfZ1E6iRaBxof4RX54EbxXhJZMwCLcB/s1600/over_temperature_80_85.png\" width=\"50px\"></div></div>");

                        //Umidade
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Umidade: ");
                        cliente.print(umid);
                        cliente.println("%</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://cdn-icons-png.flaticon.com/512/728/728093.png\" width=\"50px\"></div></div>");
                        cliente.println("</body></html>"); //Finialização do body e HTML
                        cliente.println();
                        break;
                    } else{
                        currentLine = "";                   // Limpa a variável
                    }
                } else if(c != '\r'){                       // Indica retorno atribui o C a currentLine
                    currentLine += c;
                }
            }
        }
        cliente.stop();                                     // Desconecta do Servidor
        Serial.println("Cliente Desconectou.");
        Serial.println("");
    }
}

//Logo ------------------------------------------------------------------------------------------------
void logo(){
    Heltec.display->clear();                                // Limpa o display 
    Heltec.display->drawXbm(0,10,logo_width,logo_height,logo_bits);
    Heltec.display->display();
    delay(1500);                                            // Espera 1,5s
    Heltec.display->clear();                                // Limpa o display 
}

//LoRaData --------------------------------------------------------------------------------------------
void LoRaData(){
    Heltec.display->clear();                                // Limpa o display 
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);      // Alinha o texto na esquerda
    Heltec.display->setFont(ArialMT_Plain_10);              // Escolhe a fonte
    Heltec.display->drawString(0, 0, rssi + " dBm");        // Imprime informação do sinal
    Heltec.display->drawString(0 , 13 , "Received "+ packSize + " bytes"); // Imprime tamanho
    Heltec.display->drawString(0 , 26, "Pacote: " + packet); // Imprime pacote
    Heltec.display->drawString(0 , 39, "Temperatura: "+ temp + "°C");  // Imprime temperatura
    Heltec.display->drawString(0 , 52 , "Umidade: "+ umid + "%"); // Imprime umidade
    Heltec.display->display();
}

//cbk -------------------------------------------------------------------------------------------------
void cbk(int packetSize) {
    packSize = String(packetSize,DEC);
    char l = (char) LoRa.read();                            // Pega a primeira letra
    if(l == 'p'){                                           // Verifica qual é a letra
        packet = "";                                        // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            packet += (char) LoRa.read();                   // Armazena o valor do Pacote
        }
        rssi = "RSSI " + String(LoRa.packetRssi(), DEC);
    }
    else if(l == 't'){
        temp   = "";                                        // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            temp += (char) LoRa.read();                     // Armazena o valor da Temperatura
        }
    }
    else if(l == 'u'){
        umid   = "";                                        // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            umid += (char) LoRa.read();                     // Armazena o valor da Humidade
        }
    }
    LoRaData();                                             // Chama função para imprimir no display
}

Vamos dar uma olhada mais de perto no código:

Incluindo Bibliotecas

Primeiramente temos que incluir as bibliotecas que usamos em nosso projeto.

//Biblioteca -----------------------------------------------------------------------------------------
#include <WiFi.h>                                           // Responsável pelo WiFi
#include <heltec.h>                                         // Responsável pelo display e LoRa
#include "images.h"                                         // Responsável pelo imagem

Definições LoRa

Em seguida definimos a frequência e a chave (para garantir o recebimento receba apenas pacotes de seu remetente, para pode-se definir uma palavra de sincronização (entre 0 a 0xFF)) que usaremos no LoRa.

//LoRa -----------------------------------------------------------------------------------------------
#define BAND 915E6                                         // Frequência de banda
#define KEY  0xF3                                          // Chave para receber pacote

Definições WiFi

Logo após isso declaramos duas constantes o SSID (nome da rede wifi) e password (senha da rede), também inicializamos um objeto chamado server.

//WiFi -----------------------------------------------------------------------------------------------
const char* SSID     = "<NOME-DA-REDE>";                   // Nome da rede WiFi
const char* password = "<SENHA-DA-REDE>";                  // Senha do WiFi
WiFiServer server(80);                                     // Declaração do servidor junto a sua porta

Variáveis Globais

Então declaramos as variáveis globais que será o contador de pacotes, temperatura, umidade e sinal.

//Variáveis Globais ----------------------------------------------------------------------------------
String rssi = "RSSI --";                                    // Sinal
String packSize = "--";                                     // Tamanho do Pacote
String packet;                                              // Pacote
String temp;                                                // Temperatura
String umid;                                                // Umidade

Funções Auxiliares

Logo após declaramos 3 funções auxiliares que usamos no projeto.

//Função Auxiliares ----------------------------------------------------------------------------------
void logo();                                                // Responsável por imprimir a logo
void LoRaData();                                            // Responsável por imprimir no display
void cbk(int packetSize);                                   // Responsável pelas informações

Funções Setup

Então agora na função setup, primeiramente iremos inicializar o heltec com o display, LoRa, Serial, PABOOST e sincronizamos o LoRa. Em seguida inicializamos também o display, viramos na vertical e escolhemos a fonte juntamente com o tamanho e chamamos a função para imprimir a logo.

//Setup ----------------------------------------------------------------------------------------------
void setup() { 
    //Abaixo inicializa Display, LoRa, Serial, PABOOST, BAND
    Heltec.begin(true, true, true, true, BAND);
    LoRa.setSyncWord(KEY);                                  // Chave para receber o pacote
    Heltec.display->init();                                 // Inicializa o display
    Heltec.display->flipScreenVertically();                 // Vira na vertical
    Heltec.display->setFont(ArialMT_Plain_10);              // Escolhe a fonte
    logo();                                                 // Chama função que imprime logo

Logo após inicializamos o wifi com o SSID e o password, também inicializamos o objeto server. Então escrevemos no display “Esperando Pacote…”, esperamos 1s e recebemos informação do LoRa.

    //WiFi
    WiFi.begin(SSID, password);                             // Tenta se conectar no WiFi
    while (WiFi.status() != WL_CONNECTED) {                 // Verifica se a Conexão foi realizada
        delay(500);                                         // Espera 0,5s
    }
    Serial.println(WiFi.localIP());                         // Mostra o IP do ESP32
    server.begin();                                         // Inicia o servidor

    Heltec.display->drawStri  ng(0, 0, "Esperando Pacote..."); // Escreve que foi Inicializado
    Heltec.display->display();
    delay(1000);                                            // Espera 1s
    LoRa.receive();                                         // Recebe Informação do LoRa
}

Funções Loop

Em seguida na função loop armazenamos a informação que chegou pelo LoRa e chama a função cbk. Logo após verificamos se algum cliente se conectou, caso tenha criamos um loop até que o cliente se desconecte. Então verificamos se tem algum dado sendo passado, lê as informações do cliente e atribui a c. Em seguida verificamos se c é igual a “\n” se for verdadeiro, ele retorna ao cliente que a solicitação foi concluída com sucesso. Logo depois retornarmos uma pagina HTML para o cliente. Entretanto caso seja falso, realizamos outra verificação se é diferente de “\r” incrementamos C em currentLine. Contudo quando o cliente se desconectar, nos desconectamos o cliente do server e imprimimos no serial.

//Loop -----------------------------------------------------------------------------------------------
void loop() {
    int packetSize = LoRa.parsePacket();                    // Armazena a informação
    if (packetSize) { cbk(packetSize);  }                   // Chama a função para armazenar
    delay(10);                                              // Espera 0,1s
    WiFiClient cliente = server.available();
    if(cliente){
        Serial.println("Novo Cliente");
        String currentLine="";                              // Declara variável vazia
        while(cliente.connected()){                         // Faz loop enquanto tiver cliente conectado
            if(cliente.available()){                        // Verifica se tem algum dado sendo passado
                char c = cliente.read();                    // Atribui a C as informações do cliente
                if(c == '\n'){
                    if(currentLine.length() == 0){
                        cliente.println("HTTP/1.1 200 OK"); // Retorna para o Cliente que a solicitação dele deu certo
                        cliente.println("Content-type:text/html"); // Informa o iremos fazer um HTML
                        cliente.println("Connection: close");
                        cliente.println("");
                        
                        //HTML
                        cliente.println("<!DOCTYPE html><html lang=\"pt-br\">");
                        cliente.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
                        cliente.println("<title>ESP32 LoRa - WIFI</title>");

                        //CSS
                        cliente.println("<style>html { background-color: #edf2f9; font-size: 20px; font-family: cursive; display: inline-block; margin: 0px auto; text-align: center;}");
                        cliente.println(".card { background-color: white; margin: 10px; padding: 10px; border-radius: 10px; width: 50%; display: flex;}");
                        cliente.println(".text { width: 70%;}");
                        cliente.println(".image { padding-top: 10%;}");
                        cliente.println("#grid { display: inline-flex;}</style>");
                        cliente.println("");

                        //Body
                        cliente.println("<body><h1>ESP32 LoRa - Web Server</h1>");
                        cliente.println("<div id=\"grid\">");

                        //Pacote
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Pacote: ");
                        cliente.print(packet);
                        cliente.println("</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://cdn.icon-icons.com/icons2/1465/PNG/512/724package_100522.png\" width=\"50px\"></div></div>");

                        //Temperatura
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Temperatura: ");
                        cliente.print(temp);
                        cliente.println(" C</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://1.bp.blogspot.com/-ZlYO13BMP-Y/WTRMcflEZ9I/AAAAAAAAXKM/ihxY2eyfZ1E6iRaBxof4RX54EbxXhJZMwCLcB/s1600/over_temperature_80_85.png\" width=\"50px\"></div></div>");

                        //Umidade
                        cliente.println("<div class=\"card\"><div class=\"text\">");
                        cliente.print("<p>Umidade: ");
                        cliente.print(umid);
                        cliente.println("%</p>");
                        cliente.println("</div><div class=\"image\"><img src=\"https://cdn-icons-png.flaticon.com/512/728/728093.png\" width=\"50px\"></div></div>");
                        cliente.println("</body></html>"); //Finialização do body e HTML
                        cliente.println();
                        break;
                    } else{
                        currentLine = "";                   // Limpa a variável
                    }
                } else if(c != '\r'){                       // Indica retorno atribui o C a currentLine
                    currentLine += c;
                }
            }
        }
        cliente.stop();                                     // Desconecta do Servidor
        Serial.println("Cliente Desconectou.");
        Serial.println("");
    }
}

Função Logo

Então na função logo, limpamos o display e desenhamos a logo.

//Logo -----------------------------------------------------------------------------------------------
void logo(){
    Heltec.display->clear();                                    // Limpa o display 
    Heltec.display->drawXbm(0,10,logo_width,logo_height,logo_bits);
    Heltec.display->display();
    delay(1500);                                                // Espera 1,5s
    Heltec.display->clear();                                    // Limpa o display 
}

Função LoRa Data

Logo após temos a função LoRaData, limpamos o display e escrevemos todas as informações sobre sinal, tamanho do pacote, numero do pacote, temperatura e umidade nele.

//LoRaData -------------------------------------------------------------------------------------------
void LoRaData(){
    Heltec.display->clear();                                    // Limpa o display 
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);          // Alinha o texto na esquerda
    Heltec.display->setFont(ArialMT_Plain_10);                  // Escolhe a fonte
    Heltec.display->drawString(0, 0, rssi + " dBm");            // Imprime informação do sinal
    Heltec.display->drawString(0 , 13 , "Received "+ packSize + " bytes"); // Imprime tamanho
    Heltec.display->drawString(0 , 26, "Pacote: " + packet);    // Imprime numero do pacote
    Heltec.display->drawString(0 , 39, "Temperatura: "+ temp + "°C");  // Imprime temperatura
    Heltec.display->drawString(0 , 52 , "Umidade: "+ umid + "%"); // Imprime umidade
    Heltec.display->display();
}

Função cbk

Agora na função cbk, é um pouquinho mais complexo pois primeiramente iremos armazenar em packSize a string em decimal. Em seguida lemos a primeira letra do pacote para que assim possamos saber sobre a qual pacote se refere. Logo após fazemos uma verificação se a primeira letra é “p”. Entretanto se for conseguimos identificar que o pacote enviado é referente ao número do pacote. Então sabendo disso limpamos a variável packet e fazemos um for para armazenar letra por letra no pacote.

//cbk ------------------------------------------------------------------------------------------------
void cbk(int packetSize) {
    packSize = String(packetSize,DEC);
    char l = (char) LoRa.read();                                // Pega a primeira letra
    if(l == 'p'){                                               // Verifica qual é a letra
        packet = "";                                            // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            packet += (char) LoRa.read();                       // Armazena o valor do Pacote
        }
        rssi = "RSSI " + String(LoRa.packetRssi(), DEC);
    }

Continuação da Função cbk

Entretanto caso não seja iremos realizar novamente o mesmo procedimento para os demais. Após isso podemos chamar a função LoRaData para assim possamos imprimir as informações no display.

    else if(l == 't'){
        temp   = "";                                            // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            temp += (char) LoRa.read();                         // Armazena o valor da Temperatura
        }    
    }
    else if(l == 'u'){
        umid   = "";                                            // Limpa a variável
        for (int i = 1; i < packetSize; i++){ 
            umid += (char) LoRa.read();                         // Armazena o valor da Humidade
        }
    }
    LoRaData();                                                 // Chama função LoRaData()
}

E assim finalizamos todo código do Reciver.

Arquivo images.h

#define logo_width 124
#define logo_height 44
const unsigned char logo_bits[] = {
  0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x90, 
  0x4A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x10, 0x20, 0x01, 0x42, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 
  0x0F, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x4A, 0x0A, 0x48, 0x12, 0x00, 0xE0, 
  0x0F, 0xE0, 0x0F, 0xE0, 0x07, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x0A, 0x00, 
  0x44, 0x05, 0x00, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x07, 0x00, 0xF8, 0x03, 
  0x00, 0x40, 0x50, 0x55, 0x21, 0x90, 0x00, 0xC0, 0x1F, 0xF0, 0x1F, 0xF0, 
  0x07, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0x86, 0x01, 0xC0, 
  0x1F, 0xF0, 0x1F, 0xF0, 0x03, 0x00, 0xF8, 0x03, 0x80, 0x07, 0x01, 0x00, 
  0x00, 0x10, 0x00, 0x80, 0x1F, 0xF8, 0x1F, 0xF0, 0x03, 0x00, 0xF8, 0x01, 
  0x80, 0xFC, 0xFF, 0xF1, 0x07, 0x12, 0x00, 0x80, 0x1F, 0xF8, 0x3F, 0xF8, 
  0x03, 0x00, 0xF8, 0x01, 0x80, 0xFC, 0x7F, 0xFC, 0x1F, 0x48, 0x00, 0x80, 
  0x1F, 0xF8, 0x3F, 0xF8, 0x01, 0x00, 0xF8, 0x03, 0x80, 0x87, 0x7F, 0xAE, 
  0x36, 0x54, 0x00, 0x00, 0x1F, 0xFC, 0x3E, 0xF8, 0x01, 0x00, 0xF8, 0x03, 
  0x00, 0x80, 0x3F, 0x93, 0xE4, 0x00, 0x00, 0x00, 0x0F, 0x7C, 0x7E, 0xFC, 
  0x01, 0x00, 0xF8, 0x01, 0x00, 0x80, 0x9C, 0x91, 0xCC, 0x04, 0x00, 0x00, 
  0x0F, 0x7C, 0x7C, 0xFC, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x9A, 0xFF, 
  0xFF, 0x51, 0x02, 0x00, 0x0F, 0x7E, 0x7C, 0xFC, 0x00, 0x00, 0xF8, 0x01, 
  0x02, 0x00, 0xDB, 0x88, 0x10, 0x41, 0x00, 0x00, 0x06, 0x3E, 0xFC, 0xFE, 
  0xF0, 0x03, 0xF8, 0x03, 0x4E, 0x2A, 0x48, 0x88, 0x10, 0x11, 0x09, 0x00, 
  0x06, 0x3F, 0xFC, 0x7E, 0xF0, 0x03, 0xF8, 0x01, 0xF9, 0xFF, 0x4F, 0x88, 
  0x10, 0x13, 0x08, 0x00, 0x02, 0x3F, 0xF8, 0x7E, 0xF0, 0x03, 0xF8, 0x03, 
  0xFB, 0xFF, 0xCC, 0xDF, 0x57, 0x83, 0x01, 0x00, 0x00, 0x1F, 0xF8, 0x7F, 
  0xF0, 0x07, 0xFC, 0x01, 0x0E, 0x00, 0xC9, 0xA9, 0x75, 0x53, 0x1A, 0x00, 
  0x80, 0x1F, 0xF0, 0x3F, 0xF0, 0xEF, 0xFE, 0x03, 0x00, 0x00, 0x4B, 0x88, 
  0x10, 0x03, 0x00, 0x00, 0x80, 0x1F, 0xF0, 0x3F, 0xF0, 0xFF, 0xFF, 0x01, 
  0xC0, 0x1B, 0xC8, 0x88, 0x10, 0x43, 0x02, 0x00, 0x80, 0x0F, 0xF0, 0x3F, 
  0xF0, 0xFF, 0xFF, 0x01, 0x40, 0xFE, 0xCE, 0x88, 0x88, 0x21, 0x08, 0x00, 
  0x80, 0x0F, 0xE0, 0x1F, 0xE0, 0xFF, 0xFF, 0x00, 0xC0, 0xFE, 0x9F, 0xFF, 
  0xFF, 0x01, 0x02, 0x00, 0xC0, 0x0F, 0xE0, 0x1F, 0xC0, 0xFF, 0x7F, 0x00, 
  0x80, 0x83, 0x9F, 0x91, 0xC9, 0x60, 0x00, 0x00, 0xC0, 0x06, 0xC0, 0x1B, 
  0x00, 0xFF, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x93, 0x64, 0x08, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x7F, 0xAE, 
  0x76, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE4, 0xFF, 0xFC, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFF, 0xF1, 0x07, 0x0A, 0x00, 0x48, 
  0x92, 0x24, 0x49, 0x52, 0xAA, 0xAA, 0xAA, 0x0A, 0x00, 0x38, 0x00, 0x00, 
  0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x88, 0x00, 0x52, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x12, 
  0x4A, 0x04, 0x00, 0x48, 0x24, 0x45, 0x54, 0x42, 0x48, 0x12, 0x91, 0x00, 
  0x00, 0x00, 0x04, 0xA0, 0x52, 0x0A, 0x00, 0x20, 0x96, 0x08, 0x42, 0x22, 
  0x49, 0x83, 0x08, 0x02, 0x00, 0x00, 0x50, 0x06, 0x08, 0x20, 0x00, 0xC8, 
  0x10, 0x65, 0x55, 0x44, 0x09, 0x5A, 0xD2, 0x04, 0x00, 0x00, 0x04, 0x50, 
  0x42, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };

Observação do Projeto WiFi com LoRa


Do mesmo modo caso você queira colocar uma imagem também, você irá precisar dimensionar ela para 128 x 58 no máximo podendo ser menor. Contudo você pode estar entrando no paint para fazer isso.

Redimensionando - LoRa

Logo após isso acessamos o site da online-utility e importamos a imagem que redimensionamos. Em seguida mudamos de .xbm para .h e colocamos na pasta do nosso código.

Entretanto também indicamos que quando for fazer o HTML utilize o Visual Studio Code.

Tela Visual Studio Code - WJ Componentes

Resultado do Projeto WiFi com LoRa


Esse foi o resultado obtido com nosso projeto.

Agradecemos sua Presença


Por fim, espero que tenham gostado e aprendido. Compartilhe com seus colegas e deixe um comentário de qual projeto deveria ser o próximo aqui no Blog da WJ Componentes!!
Enfim estarei deixando o arquivo Arduíno, software e sites utilizados e deixarei os arquivos os Fritzing dos componentes.
Fique à vontade para tirar suas dúvidas nos comentários.

Software e Sites Utilizados

GitHub das Bibliotecas Utilizadas

Post Relacionados

    Posts mais Recentes

    Julio Cesar Bonow Manoel

    Julio Cesar Bonow Manoel

    Cursando Engenharia da Computação pelo Centro Universitário Facens e atua no desenvolvimento de projetos na WJ Componentes. Participante da equipe de robótica Omegabotz.

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *