Planta IoT com ESP8266 NodeMCU – Parte 3 16

Dando continuidade ao projeto da planta IoT (Planta IoT com ESP8266 NodeMCU e Planta IoT com ESP8266 NodeMCU – Parte 2), agora chegamos à parte 3 do projeto: avisos de umidade de solo via MQTT.

Planta IoT com NodeMCU

Agora, além de sua planta enviar dados de umidade do solo para o ThingSpeak e utilizar o Twitter, sua planta irá enviar esses mesmos dados através de MQTT para qualquer smartphone, computador ou tablet ligado à internet!

MQTT e NodeMCU: onde encontro mais informações?

Para obter mais informações sobre como utilizar o NodeMCU junto com MQTT, leia estes artigos do BLog FilipeFlop:

ThingSpeak e MQTT ao mesmo tempo no NodeMCU

Pode parecer estranho à primeira vista, mas é perfeitamente possível utilizar  em um mesmo programa (inclusive, ao mesmo tempo) o envio de dados ao ThingSpeak e a um broker MQTT.

Isto é possível pois o NodeMCU utiliza o ESP8266 12-E, um módulo Wi-Fi que suporta até quatro sockets TCP simultaneamente. Ou seja, a grosso modo, no projeto deste post será utilizada metade da “conectividade” máxima do módulo.

Desta forma, conclui-se que um mesmo NodeMCU pode enviar dados a até 4 plataformas distintas simultaneamente, o que pode ser útil em algumas soluções e/ou protótipos IoT.

Como receber as mensagens via MQTT?

Via MQTT serão enviados alertas textuais (de 10 em 10 segundos) informando a atual situação da umidade de solo. Ou seja, com o MQTT será possível saber, a praticamente qualquer instante, a umidade de solo da planta.

<imagem Planta IoT MQTT – Celular>

Para receber as mensagens MQTT enviadas pelo NodeMCU, pode-se utilizar quaisquer clientes MQTT disponíveis. Segue abaixo algumas sugestões:

  • Se você utiliza o navegador Google Chrome no computador, uma boa alternativa é utilizar o aplicativo MQTTLens
  • Se você utiliza smartphone ou tablet com sistema operacional Android, um dos melhores clientes MQTT para ele é o MyMQTT

Código planta IoT com esp8266 nodemcu e mqtt

Segue abaixo o código-fonte do projeto:

//Programa: Planta IoT com ESP8266 NodeMCU e MQTT
#include <ESP8266WiFi.h>  //essa biblioteca já vem com a IDE. Portanto, não é preciso baixar nenhuma biblioteca adicional
#include <PubSubClient.h> // Importa a Biblioteca PubSubClient

//defines
#define SSID_REDE     " "  //coloque aqui o nome da rede que se deseja conectar
#define SENHA_REDE    " "  //coloque aqui a senha da rede que se deseja conectar
#define INTERVALO_ENVIO_THINGSPEAK  30000  //intervalo entre envios de dados ao ThingSpeak (em ms)
#define INTERVALO_ENVIO_MQTT        10000  //intervalo entre envios de dados via MQTT (em ms)
 
//defines de id mqtt e tópicos para publicação e subscribe
#define TOPICO_SUBSCRIBE "MQTTFFPlantaIoTEnvia"     //tópico MQTT de escuta
#define TOPICO_PUBLISH   "MQTTFFPlantaIoTRecebe"    //tópico MQTT de envio de informações para Broker
                                                  //IMPORTANTE: recomendamos fortemente alterar os nomes
                                                  //            desses tópicos. Caso contrário, há grandes
                                                  //            chances de você controlar e monitorar o NodeMCU
                                                  //            de outra pessoa.
#define ID_MQTT  "PlantaIotParte3"     //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).
 
//constantes e variáveis globais
const char* BROKER_MQTT = "iot.eclipse.org"; //URL do broker MQTT que se deseja utilizar
int BROKER_PORT = 1883;                      // Porta do Broker MQTT
char EnderecoAPIThingSpeak[] = "api.thingspeak.com";
String ChaveEscritaThingSpeak = " ";        //coloque aqui sua chave de escrita do seu canal no ThingSpeak
long lastConnectionTime; 
long lastMQTTSendTime;
WiFiClient client;
WiFiClient clientMQTT;
PubSubClient MQTT(clientMQTT); // Instancia o Cliente MQTT passando o objeto clientMQTT
 
//prototypes
void EnviaInformacoesThingspeak(String StringDados);
float FazLeituraUmidade(void);
void initWiFi(void);
void initMQTT(void);
void reconectWiFi(void); 
void mqtt_callback(char* topic, byte* payload, unsigned int length);
void VerificaConexoesWiFIEMQTT(void); 

/*
 * Implementações
 */
 
//Função: envia informações ao ThingSpeak
//Parâmetros: String com a  informação a ser enviada
//Retorno: nenhum
void EnviaInformacoesThingspeak(String StringDados)
{
    if (client.connect(EnderecoAPIThingSpeak, 80))
    {         
        //faz a requisição HTTP ao ThingSpeak
        client.print("POST /update HTTP/1.1n");
        client.print("Host: api.thingspeak.comn");
        client.print("Connection: closen");
        client.print("X-THINGSPEAKAPIKEY: "+ChaveEscritaThingSpeak+"n");
        client.print("Content-Type: application/x-www-form-urlencodedn");
        client.print("Content-Length: ");
        client.print(StringDados.length());
        client.print("nn");
        client.print(StringDados);
   
        lastConnectionTime = millis();
        Serial.println("- Informações enviadas ao ThingSpeak!");
     }   
}
 
//Função: inicializa e conecta-se na rede WI-FI desejada
//Parâmetros: nenhum
//Retorno: nenhum
void initWiFi() 
{
    delay(10);
    Serial.println("------Conexao WI-FI------");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID_REDE);
    Serial.println("Aguarde");
     
    reconectWiFi();
}
  
//Função: inicializa parâmetros de conexão MQTT(endereço do 
//        broker, porta e seta função de callback)
//Parâmetros: nenhum
//Retorno: nenhum
void initMQTT() 
{
    MQTT.setServer(BROKER_MQTT, BROKER_PORT);   //informa qual broker e porta deve ser conectado
    MQTT.setCallback(mqtt_callback);            //atribui função de callback (função chamada quando qualquer informação de um dos tópicos subescritos chega)
}
  
//Função: função de callback 
//        esta função é chamada toda vez que uma informação de 
//        um dos tópicos subescritos chega)
//Parâmetros: nenhum
//Retorno: nenhum
void mqtt_callback(char* topic, byte* payload, unsigned int length) 
{
        
}
  
//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 reconnectMQTT() 
{
    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!");
            MQTT.subscribe(TOPICO_SUBSCRIBE); 
        } 
        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 reconectWiFi() 
{
    //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_REDE, SENHA_REDE); // 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_REDE);
    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 VerificaConexoesWiFIEMQTT(void)
{
    if (!MQTT.connected()) 
        reconnectMQTT(); //se não há conexão com o Broker, a conexão é refeita
     
     reconectWiFi(); //se não há conexão com o WiFI, a conexão é refeita
}
 
//Função: faz a leitura do nível de umidade
//Parâmetros: nenhum
//Retorno: umidade percentual (0-100)
//Observação: o ADC do NodeMCU permite até, no máximo, 3,3V. Dessa forma,
//            para 3,3V, obtem-se (empiricamente) 978 como leitura de ADC
float FazLeituraUmidade(void)
{
    int ValorADC;
    float UmidadePercentual;
 
     ValorADC = analogRead(0);   //978 -> 3,3V
     Serial.print("[Leitura ADC] ");
     Serial.println(ValorADC);
 
     //Quanto maior o numero lido do ADC, menor a umidade.
     //Sendo assim, calcula-se a porcentagem de umidade por:
     //      
     //   Valor lido                 Umidade percentual
     //      _    0                           _ 100
     //      |                                |   
     //      |                                |   
     //      -   ValorADC                     - UmidadePercentual 
     //      |                                |   
     //      |                                |   
     //     _|_  978                         _|_ 0
     //
     //   (UmidadePercentual-0) / (100-0)  =  (ValorADC - 978) / (-978)
     //      Logo:
     //      UmidadePercentual = 100 * ((418-ValorADC) / 978)  
      
     UmidadePercentual = 100 * ((978-(float)ValorADC) / 978);
     Serial.print("[Umidade Percentual] ");
     Serial.print(UmidadePercentual);
     Serial.println("%");
 
     return UmidadePercentual;
}
void setup()
{  
    Serial.begin(9600);
    lastConnectionTime = 0; 
    lastMQTTSendTime = 0;
    initWiFi();
    initMQTT();
    Serial.println("Planta IoT com ESP8266 NodeMCU");
}
 
//loop principal
void loop()
{
    float UmidadePercentualLida;
    int UmidadePercentualTruncada;
    char FieldUmidade[11];
    char MsgUmidadeMQTT[50];
     
    VerificaConexoesWiFIEMQTT(); 
     
    //Força desconexão ao ThingSpeak (se ainda estiver desconectado)
    if (client.connected())
    {
        client.stop();
        Serial.println("- Desconectado do ThingSpeak");
        Serial.println();
    }
 
    UmidadePercentualLida = FazLeituraUmidade();
    UmidadePercentualTruncada = (int)UmidadePercentualLida; //trunca umidade como número inteiro
     
    //verifica se está conectado no WiFi e se é o momento de enviar dados ao ThingSpeak
    if(!client.connected() && 
      ((millis() - lastConnectionTime) > INTERVALO_ENVIO_THINGSPEAK))
    {
        sprintf(FieldUmidade,"field1=%d",UmidadePercentualTruncada);
        EnviaInformacoesThingspeak(FieldUmidade);
    }
 
    //verifica se é o momento de enviar informações via MQTT
    if ((millis() - lastMQTTSendTime) > INTERVALO_ENVIO_MQTT)
    {
        sprintf(MsgUmidadeMQTT,"- Umidade do solo: %d porcento.",UmidadePercentualTruncada);
        MQTT.publish(TOPICO_PUBLISH, MsgUmidadeMQTT);
        lastMQTTSendTime = millis();
    }
    
    delay(1000);
}

Execução – MQTT

Abaixo segue duas figuras de clientes MQTT distintos exibindo as informações enviadas pelo NodeMCU. Ambos clientes estavam rodando simultanemente no momento da geração da figura/screenshot.

Na primeira imagem, temos o MQTTLens rodando no browser Google Chrome no PC:

Tela Planta IoT com ESP8266 NodeMCU

E nesta, um celular android rodando o MyMQTT:

Planta IoT MQTT Celular

Gostou? Deixe seu comentário logo abaixo. Em caso de dúvidas, caso queira trocar uma ideia, ou até mesmo dividir seu projeto, acesse nosso Fórum!

Posts Relacionados

Deixe uma resposta

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

16 Comentários

  1. Parabéns pelo post, rodou direitinho, para fazer acionamentos de led via MQTT e pegar posição aberto fechado é possível? Tem algum exemplo ?
    Obrigado

    1. Darci, bom dia.

      Primeiramente, muito obrigado pela leitura e elogio! Quanto ao que você solicitou (entendo que seja interação com I/Os via MQTT), temos este post aqui no blog sobre isso: http://blog.filipeflop.com/wireless/controle-monitoramento-iot-nodemcu-e-mqtt.html

      Por favor, verifica se é isso mesmo que deseja.

      Atenciosamente,
      Pedro Bertoleti

  2. Excelente conteúdo, muito bom Pedro, parabéns.

    1. Douglas, muito obrigado!

  3. Salve Pedro Bertoleti! Parabéns pelo Artigo! Muito didático e esclarecedor!

    Uma dúvida é se este código funciona com o Arduino (Uno ou Mega) mais o ESP8266-01, pois preciso de mais portas analógicas e tenho um projeto já todo baseado em Arduino Uno para Aquisição de Dados de Placas Solares Fotovoltaicas (temperatura do ar, da costa da placa, tensão e corrente) e como sou iniciante em IoT, ainda não estou seguro em migrar tudo para NodeMCU.

    Obrigado!

    Andrew

    1. Andrew, bom dia.

      Muito obrigado pela leitura e elogios!

      Seria sim possível fazer uma adaptação para este projeto funcionar conforme deseja. Para isso, você precisaria programar o ESP8266-01 com a IDE Arduino (assim portará quase que integralmente o código deste artigo) e se comunicar com um Arduino qualquer via UART.
      Essas partes de programação do ESP8266-01 via Arduino IDE e comunicação entre ESP e Arduino por UART pode ser vista nestes artigos aqui:

      https://www.embarcados.com.br/estacao-de-medicao-de-temperatura-com-arduino-e-iot-configuracao/
      https://www.embarcados.com.br/estacao-de-medicao-de-temperatura-com-arduino-e-iot-comunicacao/
      https://www.embarcados.com.br/medicao-de-temperatura-open-source-com-arduino-e-iot-publicacao-dos-dados/

      Atenciosamente,
      Pedro Bertoleti

  4. Beleza Pedro Bertoleti, gostaria de te fazer uma pergunta, mas não é em relação essa artigo não é em relação a esse artigo: https://www.embarcados.com.br/estacao-de-medicao-de-temperatura-com-arduino-e-iot-comunicacao/, desculpa sei que não é bom fazer uma pegunta aqui de um outro artigo seu, mas é que realmente eu estou com muitas dúvidas. Eu estou tendo dificuldades para fazer o meu ESP8266 conectar na rede Wi-Fi daqui de casa eu informo o SSID e a senha conforme o você fez no seu código, mas quando eu abro o monitor serial do Arduino a única coisa que ele me mostra é: “wi-fi evt: 7”. o que isso significa? Eu tenho que configurar o meu roteador? por favor me ajuda estou perdido.

  5. Parabéns pelo artigo Pedro, mais e se eu quisesse salvar estes dados? Como proceder?

    1. Adriano, boa noite.

      Muito obrigado pela leitura e feedback!
      Quando você diz salvar os dados, se refere a salvar informações no próprio NodeMCU ou em um servidor ou computador externo? Pergunto pois ambos caminhos são possíveis, porém são respostas totalmente diferentes.

      Atenciosamente,
      Pedro Bertoleti

      1. Olá Pedro, achei que tinha publicado uma explicação da minha pergunta, já que em nosso post não é possível editar as mensagens, mais tudo bem.

        O objetivo da minha pergunta se refere à segunda opção, enviar dados para meu servidor local ou web. Porém, agora fiquei extremamente CURIOSO quando citou que é possível salvar os dados no próprio NodeMCU :O

        Infelizmente ainda não se encontra muitos tutoriais sobre NodeMCU, se puder me dar um rumo, meu TCC agradece :_(

        Desculpe as longas palavras. Atenciosamente,
        Adriano Matos

        1. Adriano, na questão de enviar dados e salvar em um banco de dados remoto, existem muitas soluções possíveis. Porém, recomendo fortemente a você ver esta solução aqui: https://douglaszuqueto.com/artigos/integrando-a-aplicacao-web-com-banco-de-dados . Ela foi Feita pelo meu amigo Douglas Zuqueto e creio que vá de encontro ao que você deseja.

          Quanto a gravar dados no próprio NodeMCU (no caso, na memória flash do próprio ESP8266 12-E), recomendo que leia o seguinte post do pedro minatel: http://pedrominatel.com.br/pt/esp8266/utilizando-eeprom-do-esp8266/ .
          Ele explica exatamente como fazer estas gravações (já testei na SparkFun Blynk Board e funcionou perfeitamente).

  6. Excelente conteúdo, muito bom Pedro, parabéns.

    1. Muito obrigado!

  7. Excelente conteúdo, muito bom Pedro, parabéns. vou provar.

  8. Boas tardes ….desde ja parabens pelo projeto….muito simples e exclaressedor….mas penso ter encontrado um erro k nao consuigo resolver…..
    Sempre que a net “cai”…. a ligação ao MQTT nao reinicia…..fico com net,com o thingspak a funcionar mas o mqtt nao….

    Sera erro meu….? Forte abraço e obrigado