Planta IoT com ESP8266 NodeMCU – Parte 4 12

Hoje vamos dar continuidade a série de posts sobre a Planta IoT com ESP8266 NodeMCU, uma planta conectada à internet que avisa no seu celular quando precisa ser regada. Nesta continuação, a planta não vai somente avisar quando precisa ser regada, mas sim vai se regar sozinha! Ou seja, através de conceitos IoT, a planta irá reportar a situação da umidade de solo e, sem você precisar tomar ação alguma, ela irá se regar se necessário. Portanto, trata-se de uma solução ideal para você que precisa se ausentar de sua casa com frequência e quer que suas plantas fiquem bem cuidadas.

Planta IoT Parte 4

Se você perdeu os “episódios anteriores” do projeto Planta IoT com ESP8266 NodeMCU, acesse os links abaixo:

Como a planta IoT vai se auto regar?

Para a planta IoT se auto regar, iremos utilizar um hardware adicional ao projeto: a Válvula de Vazão Solenóide Água 12VDC. Esta válvula permite, através de um sinal de controle de 12V, liberar ou restringir o fluxo de água por ela. Em outras palavras, é como uma “torneira acionada eletricamente”. Portanto, em termos de hardware, iremos precisar utilizar tal válvula e um circuito para permitir o acionamento da mesma sem danificar o NodeMCU (para mais informações sobre os limites elétricos do NodeMCU, leia este nosso post).

A regra para a planta se auto regar é simples: de trinta em trinta segundos (período de envio da umidade do solo ao ThingSpeak) é verificada se a umidade do solo é menor ou igual que o limite para regar (valor configurável no código, mas com default 30%). Em caso positivo, a válvula de vazão solenóide de água é acionada no tempo configurado (default de dois segundos).

Lista de componentes e circuito esquemático

O circuito completo do projeto utilizará os seguintes componentes:

O circuito esquemático pode ser visto abaixo:

Planta IoT - auto-regagem

Atenção: fazer as ligações da fonte 12V conforme ilustra a imagem a seguir. Observar que a ligação deve ser feita em rede 110V e que em L deve ser ligada a fase e em N o neutro (do ponto de energia / tomada que você estiver ligando a fonte).

Detalhe conexão fonte

Código-fonte

O código fonte do projeto planta IoT com ESP8266 NodeMCU pode ser visto a seguir. Observe com atenção os defines LIMITE_UMIDADE_PARA_REGAR (este valor determina qual será o limite percentual inferior da umidade do solo para a planta se regar) e TEMPO_PARA_REGAR (aqui é determinado por quanto tempo a válvula de vazão solenóide de água será acionada). Altere-os conforme seu gosto e necessidade.

//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 - mapeamento de pinos do NodeMCU
#define D0    16
#define D1    5
#define D2    4
#define D3    0
#define D4    2
#define D5    14
#define D6    12
#define D7    13
#define D8    15
#define D9    3
#define D10   1
 
//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)
#define LIMITE_UMIDADE_PARA_REGAR   30     //limite percentual inferior para a planta se auto regar
#define TEMPO_PARA_REGAR            2000   //tempo (em ms) ao qual a válvula de vazão solenóide de água será acionada quando for necessário regar a planta 
#define SAIDA_COMANDO_VALVULA       D0     //saída do NodeMCU que acionará a válvula de vazão solenóide de água
  
//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, 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();
    pinMode(SAIDA_COMANDO_VALVULA,OUTPUT);
    digitalWrite(SAIDA_COMANDO_VALVULA,LOW);  //por default, a válvula de vazão solenóide de água começa fechada    
    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();
    }

    //verifica se a planta deve ser regada
    if (UmidadePercentualTruncada <= LIMITE_UMIDADE_PARA_REGAR)
    {
        //em caso positivo, a planta é regada no tempo contido no define TEMPO_PARA_REGAR
        digitalWrite(SAIDA_COMANDO_VALVULA,HIGH);  //abre a válvula de vazão solenóide de água
        delay(TEMPO_PARA_REGAR);
        digitalWrite(SAIDA_COMANDO_VALVULA,LOW);  //fecha a válvula de vazão solenóide de água
    }
     
    delay(1000);
}

Abaixo você confere o projeto da Planta IoT em ação!

Projeto Finalizado

Gostou? Deixe seu comentário logo abaixo.

Faça seu comentário

Acesse sua conta e participe

12 Comentários

  1. a valvula nunca ativa, consegue me ajudar?

    1. Olá Miguel,

      A válvula está conectada no pino D0 do ESP? O transistor utilizado é um BC337 ou compatível?

      Você pode colocar um LED no pino D0 no lugar da válvula para ver se o comando está sendo enviado corretamente, se o LED acender, quer dizer que o comando está saindo do ESP corretamente.

      Abraços!
      Vinícius – Equipe MakerHero

  2. #include
    uint8_t temperature, humidity, icalor;
    ThingSpeak.setField( 1, temperature);
    ThingSpeak.setField( 2, indicecalor);
    ThingSpeak.setField( 3, humidity);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

    consegui utilizar o ThingSpeak por meio desta biblioteca contudo quando uso dela minha função de callback não funciona
    void setup() {
    // put your setup code here, to run once:
    dht.begin();
    Serial.begin(115200);
    initWiFi();
    //iniciando MQTT , adeno client poderia ser substituido por qualquer outra nome pois este é uma classe
    MQTT.setServer(BROKER_MQTT, SERVERPORT);
    MQTT.setCallback(mqtt_callback);
    ThingSpeak.begin(espClient);

    }

    void loop() {
    VerificaConexoesWiFIEMQTT();
    LerPubSensor();
    MQTT.loop();
    // delay (1800);
    }

    //Funções da WiFi

    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
    }

    void initWiFi()
    {
    delay(10);
    Serial.println(“——Conexao WI-FI——“);
    Serial.print(“Conectando-se na rede: “);
    Serial.println(SSID);
    Serial.println(“Aguarde”);
    reconectWiFi();
    }
    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, PASSWORD); // Conecta na rede WI-FI
    while (WiFi.status() != WL_CONNECTED)
    {
    delay(100);
    Serial.print(“.”);
    }
    Serial.println();
    Serial.print(“[STATUS] Conectado com sucesso na rede “);
    Serial.print(SSID);
    Serial.println(” IP obtido: “);
    Serial.println(WiFi.localIP());
    }

    void mqtt_callback(char* topic, byte* payload, unsigned int length)
    {
    String msg;
    for (int i = 0; i < length; i++)
    {
    char c = (char)payload[i];
    msg += c;
    }
    Serial.println(msg);
    char carray[msg.length() + 1];
    msg.toCharArray(carray, sizeof(carray));
    TempIdeal = atof(carray);
    Serial.println("—————————————–");
    Serial.print("Temperatura Ideal é: ");
    Serial.print(TempIdeal);
    Serial.println("\n—————————————–");
    }

    void reconnectMQTT()
    {
    while (!MQTT.connected())
    {
    Serial.print("Tentando Conectar ao Broker MQTT: ");
    Serial.println(BROKER_MQTT);
    if (MQTT.connect(USERNAME, MQTTUSER, MQTTSENHA))
    {
    Serial.println("[STATUS] Conectado com sucesso ao broker MQTT! ");
    Serial.println("[STATUS] Se Inscrevendo no Topico: ");
    MQTT.subscribe(TOPICO_SUBSCRIBE);
    }
    else
    {
    Serial.print("falhou, rc=");
    Serial.print(MQTT.state());
    Serial.println("[STATUS] Falha ao reconectar no broker.");
    Serial.println("Havera nova tentatica de conexao em 2s");
    delay(2000);

    }
    }
    }

    void LerPubSensor(void) {
    float h = dht.readHumidity(); //ler humidade
    float t = dht.readTemperature(); //ler temperatura
    float t_f = (t * 9) / 5 + 32;//tranforma em Farenheit
    double a = -42.379 + 2.04901523 * t_f + 10.14333127 * h – 0.22475541 * t_f * h
    – 0.00683783 * pow(t_f, 2) – 0.05481717 * pow(h, 2) + 0.00122874 *
    pow(t_f, 2) *
    h + 0.000885282 * t_f * pow(h, 2) – 0.00000199 * pow(t_f, 2) *
    pow(h, 2);
    double ic = 0.5556 * ( a – 32);
    char data1[8];
    char data2[5];
    // dtostrif converte um float para char
    char *IC = dtostrf(ic, 5, 2, data1); //convertendo em para enviar
    char *T = dtostrf(t, 4, 2, data2); ////convertendo em para enviar
    Serial.println("[STATUS] Publicando no Topico: ");
    Serial.println(TOPICO_PUBLISH_IC);
    Serial.println("Indice de Calor = ");
    Serial.println(IC);
    MQTT.publish(TOPICO_PUBLISH_IC, IC);
    Serial.println("[STATUS] Publicando no Topico: ");
    Serial.println("Temperatura = ");
    Serial.println(T);
    MQTT.publish(TOPICO_PUBLISH_TEMP, T);
    Serial.println("[STATUS] Temperatura enviada!");
    Serial.println("—————————————–");
    temperature = t;
    humidity = h;
    icalor = ic;
    Serial.println("Umidade = ");
    Serial.println(h);
    Serial.println("—————————————–");
    if (WiFi.status() == WL_CONNECTED)
    {
    ThingSpeak.setField( 1, temperature);
    ThingSpeak.setField( 2, icalor);
    ThingSpeak.setField( 3, humidity);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    }
    else
    {
    reconectWiFi();
    ThingSpeak.setField( 1, temperature);
    ThingSpeak.setField( 2, icalor);
    ThingSpeak.setField( 3, humidity);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

    }
    delay(60000);

  3. Olá meu camarada, tudo bem?
    Gostaria de saber como colocar a bomba ou válvula solenóide de 12V no relé de 5V?
    Eu até tenho uma placa Arduino, porém, não tenho um Internet Shield. Como a minha mãe já está com 70 anos e nem sempre tem disposição para ir colocar água nas plantinhas dela gostaria de automatizar essa pequena tarefa usando um NodeMCU ESP8266.
    Só nisso estou me enrolando.
    Desde já agradeço pela sua atenção!

    1. Bom dia, Maurício.

      Depende do seu relé. Caso ele aguente uma carga de 12V, basta você jogar uma tensão de 5V na entrada dele, usando uma fonte por exemplo.

      Abraços!
      Diogo – Equipe MakerHero

  4. Bom dia Pedro.
    Pretendo utilizar esta aplicação “Planta IoT” como base para um projeto simples
    que conecta alguns sensores na internet, estou usando um PIC para leitura e pretendo
    conectar com o modulo ESP8266 12F via UART (RX – TX ).
    Como sou novato nesta área, no código acima, a IDE citada, é Arduino?
    Posso transferir o código de execução via UART direto do microcontrolador? ,
    sem a necessidade do IDE, uma vez já desenvolvido o Firmware ? pretendo usar o modulo sem o conversor USB-RS232…
    Tem algum caminho para acelerar meu aprendizado?

    Grato.
    Carlos.

    1. Olá Carlos,

      A IDE utilizada é Arduino. Creio que não seja possível utilizar com PIC.
      O código também não servirá para PIC, mas você pode tomar a lógica do programa como base para seu programa em PIC.
      A melhor forma é procurar tutoriais para programação de PIC e leitura de sensores com PIC.

      Veja como programar PIC no tutorial:
      https://www.makerhero.com/blog/como-utilizar-gravador-pic-pickit-3.html

      Veja como utilizar ESP8266 com PIC no tutorial:
      https://www.dobitaobyte.com.br/esp8266-com-pic/

  5. A ligação seria a mesma caso usasse o arduino uno ?

    1. Na válvula de vazão solenoide Água 12VDC

      1. Rudyer, boa tarde.

        Quanto ao acionamento do solenoide (circuito para acioná-lo) com Arduino UNO, você pode usar o mesmo circuito deste artigo sim.

        Atenciosamente,
        Pedro Bertoleti

        1. Boa tarde!
          Estou tentando aplicar esse projeto na minha escola estadual pública, gostaria de saber se vocês tem o fluxograma, desenho ou planta desse projeto, pelo que observei o código fonte está completo, mas fiquei com um pouco de dúvida no desenho, tipo a ligação dos componentes. Muito obrigado

          1. Olá.

            O conteúdo seria o que está no post mesmo. O mesmo possui o esquema elétrico.

            Caso queira outra opção de planta IOT, nós temos um produto específico para isso: https://www.makerhero.com/produto/kit-plantinha-iot/. Ele acompanha os materiais e curso/tutorial para montar o projeto.

            Att.
            Vitor Mattos.
            Suporte Técnico MakerHero.