Planta IoT com ESP8266 NodeMCU – Parte 4
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.
Se você perdeu os “episódios anteriores” do projeto Planta IoT com ESP8266 NodeMCU, acesse os links abaixo:
- Planta IoT com ESP8266 NodeMCU – Parte 1 (Monitoramento da planta IoT com ThingSpeak)
- Planta IoT com ESP8266 NodeMCU – Parte 2 (Envio de avisos pelo Twitter)
- Planta IoT com ESP8266 NodeMCU – Parte 3 (Integração com MQTT)
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, lesta 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:
- NodeMCU (ou o Kit Controle e Monitoramento IoT com ESP8266)
- Válvula de vazão solenóide água 12VDC
- Fonte DC chaveada 12V 2A (metálica)
- Sensor de umidade do solo higrômetro
- Resistor 1K 1/4W
- Resistor 2K 1/4W
- Protoboard (preferencialmente de 830 pontos)
- Transistor BC337
- Diodo 1N4007
- Jumpers diversos
- Fios e plug para tomada
- Mangueiras e conexões hidráulicas (para ligação da válvula à uma torneira)
O circuito esquemático pode ser visto abaixo:
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).
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.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(); 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!
Gostou ? Ajude-nos a melhorar o blog atribuindo uma nota a este tutorial (estrelas no final do artigo), comente e visite nossa loja FILIPEFLOP!
Site: Blog FILIPEFLOP