PLANTA IOT COM ESP8266 NODEMCU – PARTE 3

PLANTA IOT COM ESP8266 NODEMCU – PARTE 3

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.1\n");
        client.print("Host: api.thingspeak.com\n");
        client.print("Connection: close\n");
        client.print("X-THINGSPEAKAPIKEY: "+ChaveEscritaThingSpeak+"\n");
        client.print("Content-Type: application/x-www-form-urlencoded\n");
        client.print("Content-Length: ");
        client.print(StringDados.length());
        client.print("\n\n");
        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, 1V. Dessa forma,
//            para 1V, obtem-se (empiricamente) 418 como leitura de ADC
float FazLeituraUmidade(void)
{
    int ValorADC;
    float UmidadePercentual;
 
     ValorADC = analogRead(0);   //418 -> 1.0V
     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 
     //      |                                |   
     //      |                                |   
     //     _|_  418                         _|_ 0
     //
     //   (UmidadePercentual-0) / (100-0)  =  (ValorADC - 418) / (-418)
     //      Logo:
     //      UmidadePercentual = 100 * ((418-ValorADC) / 418)  
      
     UmidadePercentual = 100 * ((418-(float)ValorADC) / 418);
     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 do nosso projeto de planta IoT com ESP8266 NodeMCU? Ajude-nos a melhorar o blog atribuindo uma nota a este tutorial (estrelas no final do artigo), comente e visite nossa loja FILIPEFLOP!

4
PLANTA IOT COM ESP8266 NODEMCU – PARTE 3
11 votos, 5.00 classificação média (100% pontuação)

Engenheiro eletricista formado pela Faculdade de Engenharia de Guaratinguetá (FEG - UNESP), trabalha com desenvolvimento de firmware. Colaborador do site FILIPEFLOP.

Compartilhe este Post

15 Comentários

  1. pepeto - 26 de abril de 2017

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

  2. pepeto - 26 de abril de 2017

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

  3. Adriano - 27 de fevereiro de 2017

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

    • Pedro Bertoleti - 27 de fevereiro de 2017

      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

      • Adriano - 1 de março de 2017

        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

  4. Marcel Philippe - 20 de dezembro de 2016

    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. Andrew Devlin - 12 de dezembro de 2016

    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

  6. Douglas Vieira - 1 de dezembro de 2016

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

  7. Darci - 1 de dezembro de 2016

    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

Deixe uma resposta