Conforme vemos no artigo MIC218 , o módulo WiFi LoRa 32(V2) consiste numa placa de desenvolvimento completa, pois conta com o ESP32 (o que confere grande poder computacional, conectividade WiFi e conectividade Bluetooth) e com um rádio LoRa (utilizando o chip SX1276), podendo portanto ser aplicada facilmente em projetos IoT, sobretudo os que exigem que haja comunicação entre módulos distantes até alguns quilômetros entre si.

 

Um projeto com interessante aplicação deste módulo e de funcionamento tanto local quanto inserido no conceito de Internet das Coisas é a medição de temperatura ambiente e umidade relativa do ar, afinal tais informações podem ser usadas desde para simples conhecimento até para garantir que normas de temperatura e umidade estão sendo respeitadas em determinados ambientes. Para o caso de monitoramento de ambientes como Centros de Processamento de Dados e ambientes refrigerados, esse tipo de informação é fundamental.

 E é isso que faremos neste artigo: um medidor de temperatura e umidade relativa do ar, com possibilidade de enviar as medições tanto por MQTT quanto via LoRa (neste caso, para serem lidas por outro módulo WiFi LoRa 32(V2), distante até alguns quilômetros do módulo medidor). Ou seja, faremos um projeto três em um, podendo ser usado tanto em escopo local quanto via Internet ou com rádio LoRa.

 

 

Material necessário

 Para fazer este projeto, você precisará de:

  •  Um módulo WiFi LoRa 32(V2) (para funcionamento local e/ou enviando informações via MQTT para a Internet) ou dois módulos WiFi LoRa 32(V2) (no caso de se desejar enviar as medições de um módulo para outro, numa grande distância, segundo o rádio LoRa permite).
  • Um sensor DHT22
  • Duas fontes chaveadas micro-USB de 5V/2A
  • Um resistor de 10k / 0,25W
  • Um protoboard (qualquer modelo de 400 pontos ou maior)
  • Alguns jumpers do tipo macho-macho
  • Um cabo micro-USB comum (programação e alimentação do módulo WiFi LoRa 32(V2))

 

 

Sensor DHT22

 O sensor DHT22 é capaz de mensurar temperatura e umidade relativa do ar. Este sensor, também conhecido como AM2302, é facilmente encontrado para compra em lojas on-line (sobretudo em lojas on-line para hobbistas / makers) e possui vasto material de apoio na Internet, além de ter um custo bastante acessível. A figura 1 ilustra o sensor.

 

 

Figura 1 - sensor DHT22
Figura 1 - sensor DHT22

 

 

 Em linhas gerais, suas principais características são:

  • Tensão de operação: de 3,3 a 5,5V (DC)
  • Range de operação de temperatura: -40 até +80ºC
  • Range de operação de umidade relativa do ar: 0 até 100%
  • Exatidão de +-0,5ºC na medição de temperatura
  • Exatidão de +- 2% na medição de umidade relativa
  • Protocolo de comunicação: 1-wire

 

Para mais informações do sensor DHT22, consulte o datasheet dele acessando este link.

 

 

MQTT - informações gerais

 O MQTT (Message Queue Telemetry Transport) é em um protocolo de mensagens leve / light-weight criado em 1999. O objetivo original dele era ser um protocolo adequado para comunicação entre máquinas em rede (tanto local como Internet). Este tipo de comunicação é referenciada na literatura técnica como M2M (Machine to Machine). Pelo fato de não utilizar alto poder computacional (processamento e uso de memória RAM), assim como não utilizar alta banda de Internet, o MQTT é um dos protocolos mais adequados para comunicação M2M e telemetria em dispositivos embarcados de forma geral. Justamente por isso, o MQTT é famoso no conceito IoT (Internet of Things).

 

Uma comunicação MQTT é composta das seguintes partes:

 Publishers: o(s) dispositivo(s) que irá (irão) disponibilizar informações.

 Subscribers: o(s) dispositivo(s) que irá (irão) receber as informações.

 Broker: este é o servidor da comunicação MQTT. Ele fica “na nuvem” (é acessível de qualquer lugar do mundo com conexão com à Internet). Teoricamente, não há limites máximo e mínimo especificados de subscribers e publishers em uma mesma comunicação MQTT, portanto a escalabilidade de uma comunicação MQTT pode ser altíssima.

 

IMPORTANTE: apesar da distinção entre publisher e subscriber, um dispositivo pode publicar (fazer publish) em N tópicos diferentes e se subscrever (ser subscriber) em X tópicos distintos. Ou seja, um mesmo dispositivo pode ser publisher e subscriber, o que significa que todos podem enviar e receber informações.

 

Dizendo em outras palavras: os dispositivos publishers enviam informações para o Broker. Por sua vez, os dispositivos subscribers recebem tais informações do Broker e ele gerencia a troca de mensagens. Ou seja, o “trabalho pesado” de sincronizar o envio e recebimento fica sob inteira responsabilidade do Broker, o que faz com que os sistemas embarcados (publishers e subscribers) fiquem livre para gerenciar outras coisas. Então além de utilizar poucos recursos computacionais, é possível afirmar que o MQTT leva a uma redução de consumo energético (se comparado a alguns outros protocolos de comunicação).

Observe o diagrama da comunicação MQTT mostrado na figura 2.

 

 

Figura 2 - diagrama de comunicação MQTT (fonte: https://www.filipeflop.com/blog/controle-monitoramento-iot-nodemcu-e-mqtt/)
Figura 2 - diagrama de comunicação MQTT (fonte: https://www.filipeflop.com/blog/controle-monitoramento-iot-nodemcu-e-mqtt/)

 

 

 

Sem entrar no mérito da especificação oficial do protocolo MQTT, uma mensagem MQTT publicada / enviada possui duas partes importantes:

 Tópico: “chave” / identificação da informação publicada. É usado para direcionar a informação publicada / enviada a quem assina (quem “dá subscribe”) no tópico. O tópico consiste de uma string (por exemplo: MQTTTesteTopico)

 Payload: informação que deseja enviar (propriamente dita).

Um publisher, conectado ao Broker (servidor MQTT) , envia/publica as informações em um dado momento. Os subscribers, assim como os publishers, também estão conectados aos brokers e “escutando” mensagens trafegadas com o tópico-alvo. Quando uma mensagem com o tópico alvo é publicada, automaticamente são direcionadas aos subscribers.

Em outras palavras: uma solução em IoT que usa MQTT possui somente um servidor (Broker), sendo todo o restante composto de clients MQTT.

 

 

Ligando o sensor DHT22 ao módulo WiFi LoRa 32(V2)

Para ligar o sensor DHT22 ao módulo WiFi LoRa 32(V2), vamos seguir o circuito esquemático mostrado na figura 3. Lembre-se que a alimentação do módulo WiFi LoRa 32(V2) deve ser feita através de seu conector micro-USB, utilizando para isso o computador com o cabo micro-USB ou a fonte chaveada 5V/2A. 

 

Figura 3 - circuito esquemático do módulo medidor
Figura 3 - circuito esquemático do módulo medidor

 

  

IMPORTANTE: conforme vimos no artigo sobre o módulo WiFi LoRa 32(V2) (http://www.newtoncbraga.com.br/index.php/microcontrolador/143-tecnologia/16326-moduloesp32-heltech-mec218) , este módulo não é tolerante a 5V em suas entradas. Portanto, para utilizar este sensor com o módulo, obrigatoriamente o sensor deve ser alimentado com 3,3V.

 

Instalação da biblioteca para comunicação MQTT

Agora chegou a hora de instalarmos a biblioteca PubSubClient, biblioteca na qual permitirá com que o módulo WiFi LoRa 32(V2) se comunique com a Internet utilizando o protocolo MQTT. Tal biblioteca é open-source, podendo ser obtida gratuitamente em: https://github.com/knolleary/pubsubclient 

 

Para instalar esta biblioteca, vamos seguir o procedimento abaixo:

 1. Acesse o repositório da biblioteca ( https://github.com/knolleary/pubsubclient ) e baixe-a clicando em “Clone or Download” e depois em “Download ZIP” , conforme mostra a figura 4.

 

 

Figura 4 - obtenção da biblioteca PubSubClient diretamente do repositório oficial
Figura 4 - obtenção da biblioteca PubSubClient diretamente do repositório oficial

 

 

Guarde o arquivo ZIP baixado em uma pasta conhecida / de fácil acesso para você

 

2. Agora, na Arduino IDE, vamos instalar a biblioteca que acabamos de baixar. Para isso, vamos clicar no menu “Sketch”, depois em “Incluir Biblioteca” e, por fim, clicar em “Adicionar biblioteca .ZIP”, conforme a figura 5.

 

 

Figura 5 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado
Figura 5 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado

 

 

 3. Na janela que abrir, procure pela arquivo da biblioteca que você baixou (conforme passo 1 deste procedimento) e clique em “Abrir”. Desta forma, concluímos a instalação da biblioteca PubSubClient!

 

 

Instalação da biblioteca para utilização do sensor com Arduino

Por razões de maior material de apoio disponível na Internet, iremos programar o módulo WiFi LoRa 32(V2) exatamente como faríamos no caso de um Arduino comum. Portanto, para esse sensor ser utilizado no programa deste projeto, a melhor maneira é ser utilizada a biblioteca para Arduino dele.

 Tal biblioteca é open-source, podendo ser obtida gratuitamente em: https://github.com/adafruit/DHT-sensor-library  .

 Para baixar e instalar a biblioteca e suas dependências, vamos seguir o procedimento abaixo:

 

1. Acesse o repositório da biblioteca ( https://github.com/adafruit/DHT-sensor-library ) e baixe-a clicando em “Clone or Download” e depois em “Download ZIP” , conforme mostra a figura 6.

  

Figura 6 - obtenção da biblioteca do sensor DHT22 diretamente do repositório oficial
Figura 6 - obtenção da biblioteca do sensor DHT22 diretamente do repositório oficial

 

 Guarde o arquivo ZIP baixado em uma pasta conhecida / de fácil acesso para você

 

2. Agora, na Arduino IDE, vamos instalar a biblioteca baixada. Para isso, vamos clicar no menu “Sketch”, depois em “Incluir Biblioteca” e, por fim, locar em “Adicionar biblioteca .ZIP”, conforme a figura 7.

 

Figura 7 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado
Figura 7 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado

 

 

 

3. Na janela que abrir, procure pelo arquivo da biblioteca que você baixou (conforme passo 1 deste procedimento) e clique em “Abrir”. Desta forma, instalamos a biblioteca para comunicação com o sensor DHT22!

4. Ainda há uma biblioteca a ser instalada: a biblioteca Adafruit Unified Sensor Driver.

Esta biblioteca é uma dependência da biblioteca o sensor DHT22 (ou seja, ela é necessária para o funcionamento da biblioteca do DHT22).

Portanto, primeiramente, devemos baixar a biblioteca no repositório oficial da mesma: https://github.com/adafruit/Adafruit_Sensor  . A forma de baixar é a mesma vista no passo 1 deste procedimento.

5. Uma vez baixada, esta biblioteca deve ser instalada da mesma forma que foi explicada nos passos 2 e 3 deste procedimento.

6. Pronto! Todas as bibliotecas necessárias estão agora instaladas!

 

 

Projeto em escopo local - medidor de temperatura e umidade relativa do ar

A partir deste ponto, está tudo pronto para desenvolvermos o projeto de medição de temperatura e umidade relativa do ar usando o sensor DHT22, na sua versão de escopo local (exibição das informações/medições no display OLED do módulo).

De modo geral, as funcionalidades deste projeto são:

 Medição da temperatura (ºC) e umidade relativa do ar a cada cinco segundos.

 Contabilização da máxima e mínima temperatura medidas em todo o período de funcionamento.

 As medições (temperatura e umidade relativa do ar atuais e máximas e mínimas registradas) serão formatadas em strings. Tais mensagens / strings com as medições poderão ser lidas pelo monitor serial da própria Arduino IDE (ou seja, enviada pela USB-CDC) e, além disso, serão escritas no display OLED do módulo.

 

Abaixo, segue o código-fonte do projeto. Leia com atenção seus comentários para total compreensão do mesmo.

 

 

#include <WiFi.h>#include <DHT.h>#include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>/* * Defines do projeto *//* GPIO do módulo WiFi LoRa 32(V2) que o pino de comunicação do sensor está ligado. */#define DHTPIN    13 /* (GPIO 13) *//* Endereço I2C do display */#define OLED_ADDR 0x3c/* distancia, em pixels, de cada linha em relacao ao topo do display */#define OLED_LINE1 0#define OLED_LINE2 10#define OLED_LINE3 20#define OLED_LINE4 30#define OLED_LINE5 40#define OLED_LINE6 50/* Configuração da resolucao do display (este modulo possui display 128x64) */#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64/*A biblioteca serve para os sensores DHT11, DHT22 e DHT21. No nosso caso, usaremos o DHT22, porém se você desejar utilizar algum dos outros disponíveis, basta descomentar a linha correspondente.*///#define DHTTYPE DHT11   // DHT 11#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321//#define DHTTYPE DHT21   // DHT 21 (AM2301)/* * Variáveis e objetos globais *//* objeto para comunicação com sensor DHT22 */
DHT dht(DHTPIN, DHTTYPE);/* objeto do display */
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 16);/* variáveis que armazenam os valores máximo e mínimo de temperatura registrados. */float temperatura_max;float temperatura_min;/* prototypes */void atualiza_temperatura_max_e_minima(float temp_lida);void envia_medicoes_para_serial(float temp_lida, float umid_lida);void escreve_temperatura_umidade_display(float temp_lida, float umid_lida);/* * Implementações */
 /* Função: verifica se os valores de temperatura máxima e mínima devem ser atualizados * Parâmetros: temperatura lida * Retorno: nenhum */  void atualiza_temperatura_max_e_minima(float temp_lida)
{
  if (temp_lida > temperatura_max)
    temperatura_max = temp_lida;
  if (temp_lida < temperatura_min)
    temperatura_min = temp_lida;  
}
 /* Função: envia, na forma de mensagens textuais, as medições para a serial * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida *             - Máxima temperatura registrada *             - Mínima temperatura registrada * Retorno: nenhum*/ void envia_medicoes_para_serial(float temp_lida, float umid_lida) 
{
  char mensagem[200];
  char i;
  /* pula 80 linhas, de forma que no monitor serial seja exibida somente as mensagens atuais (impressao de refresh de tela) */
  for(i=0; i<80; i++)
      Serial.println(" ");
  /* constrói mensagens e as envia */
  /* - temperatura atual */
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura: %.2f C", temp_lida);
  Serial.println(mensagem);
  
  //- umidade relativa do ar atual
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Umidade atual: %.2f \\%",umid_lida);
  Serial.println(mensagem);
  
  //- temperatura maxima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura maxima: %.2f C", temperatura_max);
  Serial.println(mensagem); 
  
  //- temperatura minima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura minima: %.2f C", temperatura_min);
  Serial.println(mensagem);
}/* Função: escreve no display OLED a temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum*/ void escreve_temperatura_umidade_display(float temp_lida, float umid_lida)
{
    char str_temp[10] = {0};
    char str_umid[10] = {0};
    char str_temp_max_min[20] = {0};
    /* formata para o display as strings de temperatura e umidade */
    sprintf(str_temp, "%.2fC", temp_lida);
    sprintf(str_umid, "%.2f/100", umid_lida);
    sprintf(str_temp_max_min, "%.2fC / %.2fC", temperatura_min, temperatura_max);
    
    display.clearDisplay();
    display.setCursor(0, OLED_LINE1);
    display.println("Temperatura:");
    display.setCursor(0, OLED_LINE2);
    display.println(str_temp);
    display.setCursor(0, OLED_LINE3);
    display.println("Umidade:");
    display.setCursor(0, OLED_LINE4);
    display.print(str_umid);
    display.setCursor(0, OLED_LINE5);
    display.println("Temp. min / max:");
    display.setCursor(0, OLED_LINE6);
    display.print(str_temp_max_min);
    display.display();
}void setup() {
  /* configura comunicação serial (para enviar mensgens com as medições)    e inicializa comunicação com o sensor.    */
  Serial.begin(115200);  
  dht.begin();
  /* inicializa temperaturas máxima e mínima com a leitura inicial do sensor */
  temperatura_max = dht.readTemperature();
  temperatura_min = temperatura_max;
   /* inicializa display OLED */
   Wire.begin(4, 15);
   
   if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
       Serial.println("Display OLED: falha ao inicializar");
   else
   {
       Serial.println("Display OLED: inicializacao ok");
  
       /* Limpa display e configura tamanho de fonte */
       display.clearDisplay();
       display.setTextSize(1);
       display.setTextColor(WHITE);
   }
}/* * Programa principal */void loop() {
  float temperatura_lida;
  float umidade_lida;
  
  /* Faz a leitura de temperatura e umidade do sensor */
  temperatura_lida = dht.readTemperature();
  umidade_lida = dht.readHumidity();
  /* se houve falha na leitura do sensor, escreve mensagem de erro na serial */
  if ( isnan(temperatura_lida) || isnan(umidade_lida) ) 
    Serial.println("Erro ao ler sensor DHT22!");
  else
  {
    /*Se a leitura foi bem sucedida, ocorre o seguinte:       - Os valores mínimos e máximos são verificados e comparados à medição atual de temperatura         se a temperatura atual for menor que a mínima ou maior que a máxima até então         registrada, os limites máximo ou mínimo são atualizados.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviados pela serial na forma de mensagem textual. Tais mensagens podem ser vistas         no monitor serial.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         escritas no display OLED     */
    atualiza_temperatura_max_e_minima(temperatura_lida);
    envia_medicoes_para_serial(temperatura_lida, umidade_lida);
    escreve_temperatura_umidade_display(temperatura_lida, umidade_lida);
  }  
  
  /* espera cinco segundos até a próxima leitura  */
  delay(5000);
}

 

Para compilar, enviar o software compilado ao módulo, basta fazer da mesma forma como se faz no Arduino convencional, ou seja, clique sobre o ícone em forma de “V” (em laranja na figura 5) para compilar e, para gravar o software no módulo, basta clicar no ícone em forma de seta para a direita (em amarelo na figura 8).

  

Figura 8 - botões da Arduino IDE para compilação e gravação de software
Figura 8 - botões da Arduino IDE para compilação e gravação de software

  

 

Assim que o Upload for feito para o módulo WiFi LoRa 32(V2), siga o passo-a-passo abaixo para ver o projeto funcionar.

 

Atenção: o passo-a-passo deve ser feito ainda com o módulo WiFi LoRa 32(V2) conectado ao computador via cabo micro-USB.

 

1. Na Arduino IDE, clique em “Ferramentas” e depois em “Monitor serial”, conforme ilustra a figura 9. Se preferir, pode utilizar o atalho de teclado Ctrl + Shift + M.

 

Figura 9 - caminho para acessar monitor serial
Figura 9 - caminho para acessar monitor serial

 

 

2. Na janela do monitor serial, vamos ajustar a velocidade em 115200bps, conforme mostra a figura 10.

 

 

Figura 10 - configuração da velocidade de comunicação entre monitor serial e módulo WiFi LoRa 32(V2)
Figura 10 - configuração da velocidade de comunicação entre monitor serial e módulo WiFi LoRa 32(V2)

 

 

 

3. Pronto! Agora basta observar as mensagem com as medições aparecendo de cinco em cinco segundos no monitor serial, conforme ilustrado na figura 11

 

 

Figura 11 - medições no monitor serial
Figura 11 - medições no monitor serial

 

 

 

 

 

Projeto com envio das medições via MQTT - medidor de temperatura e umidade relativa do ar

 Aqui, o projeto evolui em direção à Internet das Coisas. Como uma extensão do anterior (projeto que roda localmente), este apresenta como diferencial a disponibilização dos dados coletados pelos sensores na internet utilizando o protocolo MQTT.

Logo, o algoritmo usado para coletar as medições de temperatura ambiente é o mesmo, sendo acrescentada, portanto, apenas a funcionalidade de publicar as informações via MQTT.

 Sendo assim, as funcionalidades deste projeto são:

 Medição da temperatura (ºC) e umidade relativa do ar a cada cinco segundos.

Em complemento, o projeto contabilizará a máxima e mínima temperatura medidas em todo o período de funcionamento.

As medições (temperatura e umidade relativa do ar atuais e máximas e mínimas registradas) serão formatadas em strings. Tais mensagens / strings com as medições poderão ser lidas pelo monitor serial da própria Arduino IDE (ou seja, enviada pela USB-CDC) e, além disso, serão escritas no display OLED do módulo.

Disponibilização das medições de temperatura ambiente instantânea, umidade relativa do ar instantânea, temperatura máxima e temperatura mínima via MQTT.

 

Observações:

a) Será utilizado o Broker público (e gratuito) iot.eclipse.org

b) As informações via MQTT poderão ser lidas utilizando um client MQTT qualquer. Uma sugestão de client MQTT é o MQTTLens, que pode ser obtido gratuitamente no endereço: https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=pt-BR 

 

 Abaixo, segue o código-fonte do projeto. Leia com atenção seus comentários para total compreensão do mesmo. Conforme explicado nos comentários, não se esqueça de colocar em SSID e PASSWORD o nome de sua rede WI-FI e a senha dela, respectivamente.

  

#include <WiFi.h>#include <DHT.h>#include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>#include <PubSubClient.h>/* * Defines do projeto *//* GPIO do módulo WiFi LoRa 32(V2) que o pino de comunicação do sensor está ligado. */#define DHTPIN    13 /* (GPIO 13) *//* Endereço I2C do display */#define OLED_ADDR 0x3c/* distancia, em pixels, de cada linha em relacao ao topo do display */#define OLED_LINE1 0#define OLED_LINE2 10#define OLED_LINE3 20#define OLED_LINE4 30#define OLED_LINE5 40#define OLED_LINE6 50/* Configuração da resolucao do display (este modulo possui display 128x64) */#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64/*A biblioteca serve para os sensores DHT11, DHT22 e DHT21. No nosso caso, usaremos o DHT22, porém se você desejar utilizar algum dos outros disponíveis, basta descomentar a linha correspondente.*///#define DHTTYPE DHT11   // DHT 11#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321//#define DHTTYPE DHT21   // DHT 21 (AM2301)/* defines de id mqtt e tópicos para publicação e subscribe */#define TOPICO_PUBLISH   "MQTTINCBTempUmid"    /*tópico MQTT de envio de informações para Broker                                                 IMPORTANTE: recomenda-se fortemente alterar os nomes                                                             desses tópicos. Caso contrário, há grandes                                                             chances de você controlar e monitorar o módulo                                                             de outra pessoa (pois o broker utilizado contém                                                              dispositivos do mundo todo). Altere-o para algo                                                              o mais único possível para você. */#define ID_MQTT  "INCBTempUmid"     /* id mqtt (para identificação de sessão)                                       IMPORTANTE: este deve ser único no broker (ou seja,                                                    se um client MQTT tentar entrar com o mesmo                                                    id de outro já conectado ao broker, o broker                                                    irá fechar a conexão de um deles). Pelo fato                                                   do broker utilizado conter  dispositivos do mundo                                                    todo, recomenda-se fortemente que seja alterado                                                    para algo o mais único possível para você.*/
                                                   /* Constantes */const char* SSID = " "; // coloque aqui o SSID / nome da rede WI-FI que deseja se conectarconst char* PASSWORD = " "; // coloque aqui a senha da rede WI-FI que deseja se conectarconst char* BROKER_MQTT = "iot.eclipse.org"; //URL do broker MQTT que se deseja utilizarint BROKER_PORT = 1883; // Porta do Broker MQTT
  /* Variáveis e objetos globais*/
WiFiClient espClient; // Cria o objeto espClient
PubSubClient MQTT(espClient); // Instancia o Cliente MQTT passando o objeto espClient/* * Variáveis e objetos globais *//* objeto para comunicação com sensor DHT22 */
DHT dht(DHTPIN, DHTTYPE);/* objeto do display */
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 16);/* variáveis que armazenam os valores máximo e mínimo de temperatura registrados. */float temperatura_max;float temperatura_min;/* prototypes */void atualiza_temperatura_max_e_minima(float temp_lida);void envia_medicoes_para_serial(float temp_lida, float umid_lida);void escreve_temperatura_umidade_display(float temp_lida, float umid_lida);void init_wifi(void);void init_MQTT(void);void reconnect_wifi(void); void reconnect_MQTT(void);void verifica_conexoes_wifi_e_MQTT(void);void envia_informacoes_por_mqtt(float temp_lida, float umid_lida);/* * Implementações *//* Função: inicializa e conecta-se na rede WI-FI desejada * Parâmetros: nenhum *Retorno: nenhum*/void init_wifi(void) 
{
    delay(10);
    Serial.println("------Conexao WI-FI------");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID);
    Serial.println("Aguarde");    
    reconnect_wifi();
}
 /* Função: inicializa parâmetros de conexão MQTT(endereço do broker e porta) * Parâmetros: nenhum * Retorno: nenhum*/void init_MQTT(void) 
{
    //informa qual broker e porta deve ser conectado
    MQTT.setServer(BROKER_MQTT, BROKER_PORT);   
}/* Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair) *         em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito. * Parâmetros: nenhum * Retorno: nenhum*/void reconnect_MQTT(void) 
{
    while (!MQTT.connected()) 
    {
        Serial.print("* Tentando se conectar ao Broker MQTT: ");
        Serial.println(BROKER_MQTT);
        if (MQTT.connect(ID_MQTT)) 
            Serial.println("Conectado com sucesso ao broker MQTT!");
        else 
        {
            Serial.println("Falha ao reconectar no broker.");
            Serial.println("Havera nova tentatica de conexao em 2s");
            delay(2000);
        }
    }
}
 /* Função: reconecta-se ao WiFi * Parâmetros: nenhum * Retorno: nenhum*/void reconnect_wifi(void) 
{
    /* se já está conectado a rede WI-FI, nada é feito.        Caso contrário, são efetuadas tentativas de conexão */
    if (WiFi.status() == WL_CONNECTED)
        return;
        
    WiFi.begin(SSID, PASSWORD); // Conecta na rede WI-FI
    
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(100);
        Serial.print(".");
    }
  
    Serial.println();
    Serial.print("Conectado com sucesso na rede ");
    Serial.print(SSID);
    Serial.println("IP obtido: ");
    Serial.println(WiFi.localIP());
}
 /* Função: verifica o estado das conexões WiFI e ao broker MQTT.  *         Em caso de desconexão (qualquer uma das duas), a conexão *        é refeita. * Parâmetros: nenhum * Retorno: nenhum*/void verifica_conexoes_wifi_e_MQTT(void)
{
    /* se não há conexão com o WiFI, a conexão é refeita */ 
    reconnect_wifi(); 
    /* se não há conexão com o Broker, a conexão é refeita  */ 
    if (!MQTT.connected()) 
        reconnect_MQTT(); 
}
 /* Função: verifica se os valores de temperatura máxima e mínima devem ser atualizados * Parâmetros: temperatura lida * Retorno: nenhum */  void atualiza_temperatura_max_e_minima(float temp_lida)
{
  if (temp_lida > temperatura_max)
    temperatura_max = temp_lida;
  if (temp_lida < temperatura_min)
    temperatura_min = temp_lida;  
}
 /* Função: envia, na forma de mensagens textuais, as medições para a serial * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida *             - Máxima temperatura registrada *             - Mínima temperatura registrada * Retorno: nenhum*/ void envia_medicoes_para_serial(float temp_lida, float umid_lida) 
{
  char mensagem[200];
  char i;
  /* pula 80 linhas, de forma que no monitor serial seja exibida somente as mensagens atuais (impressao de refresh de tela) */
  for(i=0; i<80; i++)
      Serial.println(" ");
  /* constrói mensagens e as envia */
  /* - temperatura atual */
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura: %.2f C", temp_lida);
  Serial.println(mensagem);
  
  //- umidade relativa do ar atual
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Umidade atual: %.2f/100",umid_lida);
  Serial.println(mensagem);
  
  //- temperatura maxima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura maxima: %.2f C", temperatura_max);
  Serial.println(mensagem); 
  
  //- temperatura minima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura minima: %.2f C", temperatura_min);
  Serial.println(mensagem);
}/* Função: escreve no display OLED a temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum*/ void escreve_temperatura_umidade_display(float temp_lida, float umid_lida)
{
    char str_temp[10] = {0};
    char str_umid[10] = {0};
    char str_temp_max_min[20] = {0};
    /* formata para o display as strings de temperatura e umidade */
    sprintf(str_temp, "%.2fC", temp_lida);
    sprintf(str_umid, "%.2f/100", umid_lida);
    sprintf(str_temp_max_min, "%.2fC / %.2fC", temperatura_min, temperatura_max);
    
    display.clearDisplay();
    display.setCursor(0, OLED_LINE1);
    display.println("Temperatura:");
    display.setCursor(0, OLED_LINE2);
    display.println(str_temp);
    display.setCursor(0, OLED_LINE3);
    display.println("Umidade:");
    display.setCursor(0, OLED_LINE4);
    display.print(str_umid);
    display.setCursor(0, OLED_LINE5);
    display.println("Temp. min / max:");
    display.setCursor(0, OLED_LINE6);
    display.print(str_temp_max_min);
    display.display();
}/*  * Função: envia por MQTT as informações de temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum */void envia_informacoes_por_mqtt(float temp_lida, float umid_lida)
{
  char mensagem_MQTT[200] = {0};
  //constrói mensagens e as envia
  //- temperatura atual
  sprintf(mensagem_MQTT,"Temperatura: %.2f C, Umidade atual: %.2f/100, Temperatura maxima: %.2f C, Temperatura minima: %.2f C", temp_lida, 
                                                                                                                              umid_lida,
                                                                                                                              temperatura_max,
                                                                                                                              temperatura_min);
                                                                                                                              
  MQTT.publish(TOPICO_PUBLISH, mensagem_MQTT);  
}void setup() {
  /* configura comunicação serial (para enviar mensgens com as medições)    e inicializa comunicação com o sensor.    */
  Serial.begin(115200);  
  dht.begin();
  /* inicializa temperaturas máxima e mínima com a leitura inicial do sensor */
  temperatura_max = dht.readTemperature();
  temperatura_min = temperatura_max;
   /* inicializa display OLED */
   Wire.begin(4, 15);
   
   if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
       Serial.println("Display OLED: falha ao inicializar");
   else
   {
       Serial.println("Display OLED: inicializacao ok");
  
       /* Limpa display e configura tamanho de fonte */
       display.clearDisplay();
       display.setTextSize(1);
       display.setTextColor(WHITE);
   }
  /* inicializações do WI-FI e MQTT */
  init_wifi();
  init_MQTT();
}/* * Programa principal */void loop() {
  float temperatura_lida;
  float umidade_lida;
  /* Verifica se as conexões MQTT e wi-fi estão ativas      Se alguma delas não estiver ativa, a reconexão é feita */
  verifica_conexoes_wifi_e_MQTT();
  
  /* Faz a leitura de temperatura e umidade do sensor */
  temperatura_lida = dht.readTemperature();
  umidade_lida = dht.readHumidity();
  /* se houve falha na leitura do sensor, escreve mensagem de erro na serial */
  if ( isnan(temperatura_lida) || isnan(umidade_lida) ) 
    Serial.println("Erro ao ler sensor DHT22!");
  else
  {
    /*Se a leitura foi bem sucedida, ocorre o seguinte:       - Os valores mínimos e máximos são verificados e comparados à medição atual de temperatura         se a temperatura atual for menor que a mínima ou maior que a máxima até então         registrada, os limites máximo ou mínimo são atualizados.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviados pela serial na forma de mensagem textual. Tais mensagens podem ser vistas         no monitor serial.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         escritas no display OLED       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviadas por MQTT     */
    atualiza_temperatura_max_e_minima(temperatura_lida);
    envia_medicoes_para_serial(temperatura_lida, umidade_lida);
    escreve_temperatura_umidade_display(temperatura_lida, umidade_lida);
    envia_informacoes_por_mqtt(temperatura_lida, umidade_lida);
  }  
  /* Faz o keep-alive do MQTT */
  MQTT.loop();
  
  /* espera cinco segundos até a próxima leitura  */
  delay(5000);
}

 

 

Para compilar, enviar o software compilado ao módulo, basta fazer da mesma forma como se faz no Arduino convencional, ou seja, clique sobre o ícone em forma de “V” (em laranja na figura 5) para compilar e, para gravar o software no módulo, basta clicar no ícone em forma de seta para a direita (em amarelo na figura 8).

 

Para visualizar as informações enviadas por MQTT, siga o procedimento abaixo:

 1. Assumindo que vamos utilizar o MQTTLens como cliente de MQTT, abra-o e clique em “Connections +”.

 2. Agora, vamos preencher os campos “Connection name” e “Hostname” da janela “Add a new Connection” conforme a figura 12. Deixe os demais campos como estão.

  

Figura 12 - Dados de conexão MQTT (configuração do cliente MQTTLens)
Figura 12 - Dados de conexão MQTT (configuração do cliente MQTTLens)

 

 

3. No final da tela “Add a new Connection”, devemos agora clicar em “CREATE CONNECTION”.

4. Automaticamente, o cliente MQTTLens irá se conectar ao broker. No campo Subscribe, vamos preencher com o TOPICO_PUBLISH utilizado no código-fonte do projeto (para o exemplo dado: MQTTINCBTempUmid). Em seguida, clicaremos no botão SUBSCRIBE (em verde, à direita do campo).

5. Se o módulo WiFi LoRa 32(V2) estiver funcionando / ligado, iremos ver as mensagens com as medições, conforme mostra a figura 13.

 

 

Figura 13 - mensagens MQTT enviadas
Figura 13 - mensagens MQTT enviadas

 

 

6. Pronto! Usando um client MQTT é possível, de qualquer lugar do mundo, saber quais são as medições de temperatura do ar e umidade relativa do ar feitas pelo projeto.

 

 

Projeto para envio das medições a outro módulo usando LoRa - medidor de temperatura e umidade relativa do ar

 Aqui, o projeto ganha a funcionalidade de envio das informações usando o rádio LoRa, o que o permite enviar as informações de temperatura e umidade para outro módulo WiFi LoRa 32(V2) distante até alguns quilômetros do módulo medidor.

Logo, tanto o algoritmo usado para coletar as medições de temperatura ambiente quanto a funcionalidade MQTT serão mantidas, sendo adicionada somente a funcionalidade de transmissão LoRa, portanto.

Sendo assim, as funcionalidades deste projeto são:

 Medição da temperatura (ºC) e umidade relativa do ar a cada cinco segundos.

Em complemento, o projeto contabilizará a máxima e mínima temperatura medidas em todo o período de funcionamento.

As medições (temperatura e umidade relativa do ar atuais e máximas e mínimas registradas) serão formatadas em strings. Tais mensagens / strings com as medições poderão ser lidas pelo monitor serial da própria Arduino IDE (ou seja, enviada pela USB-CDC) e, além disso, serão escritas no display OLED do módulo.

Disponibilização das medições de temperatura ambiente instantânea, umidade relativa do ar instantânea, temperatura máxima e temperatura mínima via MQTT.

Disponibilização das medições de temperatura ambiente instantânea, umidade relativa do ar instantânea, temperatura máxima e temperatura mínima via LoRa para outro módulo WiFi LoRa 32(V2).

 

IMPORTANTE: a comunicação entre os dois módulos WiFi LoRa 32(V2) (módulo medidor e receptor) é dada na topologia ponto-a-ponto.

 

Como o LoRa possui um baixo throughput (velocidade de transmissão), é uma boa prática que as informações enviadas sejam as menores possíveis, de forma a não gerar atrasos na comunicação. Sendo assim, as informações de temperatura ambiente instantânea, umidade relativa do ar instantânea, temperatura máxima e temperatura mínima serão todas empacotadas numa única estrutura de dados (de tamanho fixo) e enviadas para o destinatário LoRa.

Essa forma é muito mais econômica em termos de tamanho se comparada a forma textual simples (informações mais verbosas, em ASCII). A estrutura na qual as informações serão empacotadas pode ser vista a seguir.

 

 

typedef struct __attribute__((__packed__))  
{
    float temperatura;
    float umidade;
    float temperatura_min;
    float temperatura_max;
}TDadosLora;

 

Note que a estrutura de dados em questão possui o atributo __attribute__((__packed__)). Este atributo é de fundamental importância em se tratando de estruturas de dados a serem transmitidas via LoRa, pois este faz com que a estrutura tenha como tamanho exatamente a soma dos tamanhos individuais de seus campos. Se isto não for especificado, o tamanho da estrutura será sempre um múltiplo do tamanho da palavra do processador (neste caso, 32 bits) e o compilador irá fazer uso de padding (preenchimento) para completar os bits (ou bytes) remanescentes até que o tamanho da estrutura seja um múltiplo do tamanho da palavra do processador. Logo, não utilizar o atributo __attribute__((__packed__)) pode resultar em aumento desnecessário de bytes utilizados pela estrutura, o que pode gerar atrasos maiores na transmissão LoRa.

Abaixo, segue o código-fonte do módulo medidor (transmissor). Leia com atenção seus comentários para total compreensão do mesmo. Conforme explicado nos comentários, não se esqueça de colocar em SSID e PASSWORD o nome de sua rede WI-FI e a senha dela, respectivamente.

 

 

#include <WiFi.h>#include <DHT.h>#include <Wire.h>#include <LoRa.h>#include <SPI.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>#include <PubSubClient.h>/* * Defines do projeto *//* GPIO do módulo WiFi LoRa 32(V2) que o pino de comunicação do sensor está ligado. */#define DHTPIN    13 /* (GPIO 13) *//* Endereço I2C do display */#define OLED_ADDR 0x3c/* distancia, em pixels, de cada linha em relacao ao topo do display */#define OLED_LINE1 0#define OLED_LINE2 10#define OLED_LINE3 20#define OLED_LINE4 30#define OLED_LINE5 40#define OLED_LINE6 50/* Configuração da resolucao do display (este modulo possui display 128x64) */#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64/*A biblioteca serve para os sensores DHT11, DHT22 e DHT21. No nosso caso, usaremos o DHT22, porém se você desejar utilizar algum dos outros disponíveis, basta descomentar a linha correspondente.*///#define DHTTYPE DHT11   // DHT 11#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321//#define DHTTYPE DHT21   // DHT 21 (AM2301)/* defines de id mqtt e tópicos para publicação e subscribe */#define TOPICO_PUBLISH   "MQTTINCBTempUmid"    /*tópico MQTT de envio de informações para Broker                                                 IMPORTANTE: recomenda-se fortemente alterar os nomes                                                             desses tópicos. Caso contrário, há grandes                                                             chances de você controlar e monitorar o módulo                                                             de outra pessoa (pois o broker utilizado contém                                                              dispositivos do mundo todo). Altere-o para algo                                                              o mais único possível para você. */#define ID_MQTT  "INCBTempUmid"     /* id mqtt (para identificação de sessão)                                       IMPORTANTE: este deve ser único no broker (ou seja,                                                    se um client MQTT tentar entrar com o mesmo                                                    id de outro já conectado ao broker, o broker                                                    irá fechar a conexão de um deles). Pelo fato                                                   do broker utilizado conter  dispositivos do mundo                                                    todo, recomenda-se fortemente que seja alterado                                                    para algo o mais único possível para você.*//* Definicoes para comunicação com radio LoRa */#define SCK_LORA           5#define MISO_LORA          19#define MOSI_LORA          27#define RESET_PIN_LORA     14#define SS_PIN_LORA        18#define HIGH_GAIN_LORA     20  /* dBm */#define BAND               915E6  /* 915MHz de frequencia *//* Constantes */const char* SSID = " "; // coloque aqui o SSID / nome da rede WI-FI que deseja se conectarconst char* PASSWORD = " "; // coloque aqui a senha da rede WI-FI que deseja se conectarconst char* BROKER_MQTT = "iot.eclipse.org"; //URL do broker MQTT que se deseja utilizarint BROKER_PORT = 1883; // Porta do Broker MQTT
  /* Variáveis e objetos globais*/
WiFiClient espClient; // Cria o objeto espClient
PubSubClient MQTT(espClient); // Instancia o Cliente MQTT passando o objeto espClient/* * Variáveis e objetos globais *//* objeto para comunicação com sensor DHT22 */
DHT dht(DHTPIN, DHTTYPE);/* objeto do display */
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 16);/* variáveis que armazenam os valores máximo e mínimo de temperatura registrados. */float temperatura_max;float temperatura_min;/* typedefs */typedef struct __attribute__((__packed__))  
{
  float temperatura;
  float umidade;
  float temperatura_min;
  float temperatura_max;
}TDadosLora;/* prototypes */void atualiza_temperatura_max_e_minima(float temp_lida);void escreve_temperatura_umidade_display(float temp_lida, float umid_lida);void envia_medicoes_para_serial(float temp_lida, float umid_lida);void envia_informacoes_por_mqtt(float temp_lida, float umid_lida);void envia_informacoes_lora(float temp_lida, float umid_lida);void init_wifi(void);void init_MQTT(void);void reconnect_wifi(void); void reconnect_MQTT(void);void verifica_conexoes_wifi_e_MQTT(void);bool init_comunicacao_lora(void);/* * Implementações *//* Função: inicializa e conecta-se na rede WI-FI desejada * Parâmetros: nenhum *Retorno: nenhum*/void init_wifi(void) 
{
    delay(10);
    Serial.println("------Conexao WI-FI------");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID);
    Serial.println("Aguarde");    
    reconnect_wifi();
}
 /* Função: inicializa parâmetros de conexão MQTT(endereço do broker e porta) * Parâmetros: nenhum * Retorno: nenhum*/void init_MQTT(void) 
{
    //informa qual broker e porta deve ser conectado
    MQTT.setServer(BROKER_MQTT, BROKER_PORT);   
}/* Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair) *         em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito. * Parâmetros: nenhum * Retorno: nenhum*/void reconnect_MQTT(void) 
{
    while (!MQTT.connected()) 
    {
        Serial.print("* Tentando se conectar ao Broker MQTT: ");
        Serial.println(BROKER_MQTT);
        if (MQTT.connect(ID_MQTT)) 
            Serial.println("Conectado com sucesso ao broker MQTT!");
        else 
        {
            Serial.println("Falha ao reconectar no broker.");
            Serial.println("Havera nova tentatica de conexao em 2s");
            delay(2000);
        }
    }
}
 /* Função: reconecta-se ao WiFi * Parâmetros: nenhum * Retorno: nenhum*/void reconnect_wifi(void) 
{
    /* se já está conectado a rede WI-FI, nada é feito.        Caso contrário, são efetuadas tentativas de conexão */
    if (WiFi.status() == WL_CONNECTED)
        return;
        
    WiFi.begin(SSID, PASSWORD); // Conecta na rede WI-FI
    
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(100);
        Serial.print(".");
    }
  
    Serial.println();
    Serial.print("Conectado com sucesso na rede ");
    Serial.print(SSID);
    Serial.println("IP obtido: ");
    Serial.println(WiFi.localIP());
}
 /* Função: verifica o estado das conexões WiFI e ao broker MQTT.  *         Em caso de desconexão (qualquer uma das duas), a conexão *        é refeita. * Parâmetros: nenhum * Retorno: nenhum*/void verifica_conexoes_wifi_e_MQTT(void)
{
    /* se não há conexão com o WiFI, a conexão é refeita */ 
    reconnect_wifi(); 
    /* se não há conexão com o Broker, a conexão é refeita  */ 
    if (!MQTT.connected()) 
        reconnect_MQTT(); 
}
 /* Função: verifica se os valores de temperatura máxima e mínima devem ser atualizados * Parâmetros: temperatura lida * Retorno: nenhum */  void atualiza_temperatura_max_e_minima(float temp_lida)
{
  if (temp_lida > temperatura_max)
    temperatura_max = temp_lida;
  if (temp_lida < temperatura_min)
    temperatura_min = temp_lida;  
}
 /* Função: envia, na forma de mensagens textuais, as medições para a serial * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida *             - Máxima temperatura registrada *             - Mínima temperatura registrada * Retorno: nenhum*/ void envia_medicoes_para_serial(float temp_lida, float umid_lida) 
{
  char mensagem[200];
  char i;
  /* pula 80 linhas, de forma que no monitor serial seja exibida somente as mensagens atuais (impressao de refresh de tela) */
  for(i=0; i<80; i++)
      Serial.println(" ");
  /* constrói mensagens e as envia */
  /* - temperatura atual */
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura: %.2f C", temp_lida);
  Serial.println(mensagem);
  
  //- umidade relativa do ar atual
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Umidade atual: %.2f/100",umid_lida);
  Serial.println(mensagem);
  
  //- temperatura maxima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura maxima: %.2f C", temperatura_max);
  Serial.println(mensagem); 
  
  //- temperatura minima
  memset(mensagem,0,sizeof(mensagem));
  sprintf(mensagem,"- Temperatura minima: %.2f C", temperatura_min);
  Serial.println(mensagem);
}/* Função: escreve no display OLED a temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum*/ void escreve_temperatura_umidade_display(float temp_lida, float umid_lida)
{
    char str_temp[10] = {0};
    char str_umid[10] = {0};
    char str_temp_max_min[20] = {0};
    /* formata para o display as strings de temperatura e umidade */
    sprintf(str_temp, "%.2fC", temp_lida);
    sprintf(str_umid, "%.2f/100", umid_lida);
    sprintf(str_temp_max_min, "%.2fC / %.2fC", temperatura_min, temperatura_max);
    
    display.clearDisplay();
    display.setCursor(0, OLED_LINE1);
    display.println("Temperatura:");
    display.setCursor(0, OLED_LINE2);
    display.println(str_temp);
    display.setCursor(0, OLED_LINE3);
    display.println("Umidade:");
    display.setCursor(0, OLED_LINE4);
    display.print(str_umid);
    display.setCursor(0, OLED_LINE5);
    display.println("Temp. min / max:");
    display.setCursor(0, OLED_LINE6);
    display.print(str_temp_max_min);
    display.display();
}/*  * Função: envia por MQTT as informações de temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum */void envia_informacoes_por_mqtt(float temp_lida, float umid_lida)
{
  char mensagem_MQTT[200] = {0};
  //constrói mensagens e as envia
  //- temperatura atual
  sprintf(mensagem_MQTT,"Temperatura: %.2f C, Umidade atual: %.2f/100, Temperatura maxima: %.2f C, Temperatura minima: %.2f C", temp_lida, 
                                                                                                                              umid_lida,
                                                                                                                              temperatura_max,
                                                                                                                              temperatura_min);
                                                                                                                              
  MQTT.publish(TOPICO_PUBLISH, mensagem_MQTT);  
}/*  * Função: envia por LoRa as informações de temperatura e umidade lidas, assim como as temperaturas máxima e mínima * Parâmetros: - Temperatura lida *             - Umidade relativa do ar lida * Retorno: nenhum */void envia_informacoes_lora(float temp_lida, float umid_lida)
{
    TDadosLora dados_lora;
    dados_lora.temperatura = temp_lida;
    dados_lora.umidade = umid_lida;
    dados_lora.temperatura_min = temperatura_min;
    dados_lora.temperatura_max = temperatura_max;
    LoRa.beginPacket();
    LoRa.write((unsigned char *)&dados_lora, sizeof(TDadosLora));
    LoRa.endPacket();
}/* Funcao: inicia comunicação com chip LoRa * Parametros: nenhum * Retorno: true: comunicacao ok *          false: falha na comunicacao*/bool init_comunicacao_lora(void)
{
    bool status_init = false;
    Serial.println("[LoRa Sender] Tentando iniciar comunicacao com o radio LoRa...");
    SPI.begin(SCK_LORA, MISO_LORA, MOSI_LORA, SS_PIN_LORA);
    LoRa.setPins(SS_PIN_LORA, RESET_PIN_LORA, LORA_DEFAULT_DIO0_PIN);
    
    if (!LoRa.begin(BAND)) 
    {
        Serial.println("[LoRa Sender] Comunicacao com o radio LoRa falhou. Nova tentativa em 1 segundo...");        
        delay(1000);
        status_init = false;
    }
    else
    {
        /* Configura o ganho do receptor LoRa para 20dBm, o maior ganho possível (visando maior alcance possível) */ 
        LoRa.setTxPower(HIGH_GAIN_LORA); 
        Serial.println("[LoRa Sender] Comunicacao com o radio LoRa ok");
        status_init = true;
    }
    return status_init;
}void setup() {
  /* configura comunicação serial (para enviar mensgens com as medições)    e inicializa comunicação com o sensor.    */
  Serial.begin(115200);  
  dht.begin();
  /* inicializa temperaturas máxima e mínima com a leitura inicial do sensor */
  temperatura_max = dht.readTemperature();
  temperatura_min = temperatura_max;
   /* inicializa display OLED */
   Wire.begin(4, 15);
   
   if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
       Serial.println("Display OLED: falha ao inicializar");
   else
   {
       Serial.println("Display OLED: inicializacao ok");
  
       /* Limpa display e configura tamanho de fonte */
       display.clearDisplay();
       display.setTextSize(1);
       display.setTextColor(WHITE);
   }
  /* Tenta, até obter sucesso, comunicacao com o chip LoRa */
  while(init_comunicacao_lora() == false);    
  /* inicializações do WI-FI e MQTT */
  init_wifi();
  init_MQTT();
}/* * Programa principal */void loop() {
  float temperatura_lida;
  float umidade_lida;
  /* Verifica se as conexões MQTT e wi-fi estão ativas      Se alguma delas não estiver ativa, a reconexão é feita */
  verifica_conexoes_wifi_e_MQTT();
  
  /* Faz a leitura de temperatura e umidade do sensor */
  temperatura_lida = dht.readTemperature();
  umidade_lida = dht.readHumidity();
  /* se houve falha na leitura do sensor, escreve mensagem de erro na serial */
  if ( isnan(temperatura_lida) || isnan(umidade_lida) ) 
    Serial.println("Erro ao ler sensor DHT22!");
  else
  {
    /*Se a leitura foi bem sucedida, ocorre o seguinte:       - Os valores mínimos e máximos são verificados e comparados à medição atual de temperatura         se a temperatura atual for menor que a mínima ou maior que a máxima até então         registrada, os limites máximo ou mínimo são atualizados.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviados pela serial na forma de mensagem textual. Tais mensagens podem ser vistas         no monitor serial.       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         escritas no display OLED       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviadas por MQTT       - As medições (temperatura, umidade, máxima temperatura e mínima temperatura) são         enviadas por LoRa para um módulo receptor     */
    atualiza_temperatura_max_e_minima(temperatura_lida);
    envia_medicoes_para_serial(temperatura_lida, umidade_lida);
    escreve_temperatura_umidade_display(temperatura_lida, umidade_lida);
    envia_informacoes_por_mqtt(temperatura_lida, umidade_lida);
    envia_informacoes_lora(temperatura_lida, umidade_lida);
  }  
  /* Faz o keep-alive do MQTT */
  MQTT.loop();
  
  /* espera cinco segundos até a próxima leitura  */
  delay(5000);
}

 

 

No módulo receptor, é importante que a estrutura de dados esperada seja idêntica à enviada. Dessa forma, garante-se que o que for enviado será corretamente recebido / terá coerência. Portanto, a mesma estrutura de dados definida no transmissor deve ser aqui também definida:

 

typedef struct __attribute__((__packed__))  
{
    float temperatura;
    float umidade;
    float temperatura_min;
    float temperatura_max;
}TDadosLora;

 

Abaixo, segue o código-fonte do módulo receptor. Leia com atenção seus comentários para total compreensão do mesmo.

 

#include <LoRa.h>#include <SPI.h>#include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>/* Definicoes para comunicação com radio LoRa */#define SCK_LORA           5#define MISO_LORA          19#define MOSI_LORA          27#define RESET_PIN_LORA     14#define SS_PIN_LORA        18#define HIGH_GAIN_LORA     20  /* dBm */#define BAND               915E6  /* 915MHz de frequencia *//* Definicoes do OLED */#define OLED_SDA_PIN    4#define OLED_SCL_PIN    15#define SCREEN_WIDTH    128 #define SCREEN_HEIGHT   64  #define OLED_ADDR       0x3C #define OLED_RESET      16/* Offset de linhas no display OLED */#define OLED_LINE1     0#define OLED_LINE2     10#define OLED_LINE3     20#define OLED_LINE4     30#define OLED_LINE5     40#define OLED_LINE6     50/* Definicoes gerais */#define DEBUG_SERIAL_BAUDRATE    115200/* Variaveis e objetos globais */
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);/* typedefs */typedef struct __attribute__((__packed__))  
{
    float temperatura;
    float umidade;
    float temperatura_min;
    float temperatura_max;
}TDadosLora;/* Local prototypes */void display_init(void);bool init_comunicacao_lora(void);/* Funcao: inicializa comunicacao com o display OLED * Parametros: nenhnum * Retorno: nenhnum*/ void display_init(void)
{
    if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) 
    {
        Serial.println("[LoRa Receiver] Falha ao inicializar comunicacao com OLED");        
    }
    else
    {
        Serial.println("[LoRa Receiver] Comunicacao com OLED inicializada com sucesso");
    
        /* Limpa display e configura tamanho de fonte */
        display.clearDisplay();
        display.setTextSize(1);
        display.setTextColor(WHITE);
    }
}/* Funcao: inicia comunicação com chip LoRa * Parametros: nenhum * Retorno: true: comunicacao ok *          false: falha na comunicacao*/bool init_comunicacao_lora(void)
{
    bool status_init = false;
    Serial.println("[LoRa Receiver] Tentando iniciar comunicacao com o radio LoRa...");
    SPI.begin(SCK_LORA, MISO_LORA, MOSI_LORA, SS_PIN_LORA);
    LoRa.setPins(SS_PIN_LORA, RESET_PIN_LORA, LORA_DEFAULT_DIO0_PIN);
    
    if (!LoRa.begin(BAND)) 
    {
        Serial.println("[LoRa Receiver] Comunicacao com o radio LoRa falhou. Nova tentativa em 1 segundo...");        
        delay(1000);
        status_init = false;
    }
    else
    {
        /* Configura o ganho do receptor LoRa para 20dBm, o maior ganho possível (visando maior alcance possível) */ 
        LoRa.setTxPower(HIGH_GAIN_LORA); 
        Serial.println("[LoRa Receiver] Comunicacao com o radio LoRa ok");
        status_init = true;
    }
    return status_init;
}/* Funcao de setup */void setup() 
{
    /* Configuracao da I²C para o display OLED */
    Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
    /* Display init */
    display_init();
    /* Print message telling to wait */
    display.clearDisplay();    
    display.setCursor(0, OLED_LINE1);
    display.print("Aguarde...");
    display.display();
    
    Serial.begin(DEBUG_SERIAL_BAUDRATE);
    while (!Serial);
    /* Tenta, até obter sucesso, comunicacao com o chip LoRa */
    while(init_comunicacao_lora() == false);       
}/* Programa principal */void loop() 
{
    char byte_recebido;
    int packet_size = 0;
    int lora_rssi = 0;
    TDadosLora dados_lora;
    char * pt_dados_lora = NULL;
    char str_temp[10] = {0};
    char str_umid[10] = {0};
    char str_temp_max_minima[20] = {0};
  
    /* Verifica se chegou alguma informação do tamanho esperado */
    packet_size = LoRa.parsePacket();
    
    if (packet_size == sizeof(TDadosLora)) 
    {
        Serial.print("[LoRa Receiver] Há dados a serem lidos");
        
        /* Recebe os dados conforme protocolo */               
        pt_dados_lora = (char *)&dados_lora;  
        while (LoRa.available()) 
        {
            byte_recebido = (char)LoRa.read();
            *pt_dados_lora = byte_recebido;
            pt_dados_lora++;
        }
        /* Formata strings para exibição no display */
        sprintf(str_temp, "%.2fC", dados_lora.temperatura);
        sprintf(str_umid, "%.2f/100", dados_lora.umidade);
        sprintf(str_temp_max_minima, "%.2fC / %.2fC", dados_lora.temperatura_min, dados_lora.temperatura_max);
        /* Escreve RSSI de recepção e informações recebidas */
        lora_rssi = LoRa.packetRssi();
        display.clearDisplay();   
        display.setCursor(30, OLED_LINE1);
        display.print("RSSI: ");
        display.println(lora_rssi);
        
        display.setCursor(0, OLED_LINE1);
        display.print("Temp:");
        display.setCursor(0, OLED_LINE2);
        display.println(str_temp);
        display.setCursor(0, OLED_LINE3);
        display.print("Umidade: ");
        display.setCursor(0, OLED_LINE4);
        display.println(str_umid);
        display.setCursor(0, OLED_LINE5);
        display.print("Temp. min/max: ");
        display.setCursor(0, OLED_LINE6);
        display.println(str_temp_max_minima);
        
        display.display();      
    }
}

 

 

 Para compilar, enviar o software compilado ao módulo, basta fazer da mesma forma como se faz no Arduino convencional, ou seja, clique sobre o ícone em forma de “V” (em laranja na figura 5) para compilar e, para gravar o software no módulo, basta clicar no ícone em forma de seta para a direita (em amarelo na figura 8).

 

 

Conclusão

Neste artigo for apresentado como medir, utilizando o sensor DHT22, a temperatura e umidade relativa do ar. Ainda, foram disponibilizados três projetos (projeto três em um) que, além de fazer esta medição e mostrar localmente (no display OLED do módulo WiFi LoRa 32(V2)), disponibilizam tais medições via MQTT e as enviam pelo rádio LoRa a outro módulo WiFi LoRa 32(V2), podendo este estar localizado a até alguns quilômetros distância.

Portanto, tomando como base tais projetos aqui apresentados, é possível fazer projetos nos contextos de IoT e Smart Cities.