“ArduFarmBot 2” – Sistema automático para irrigação e calor, agora com o NodeMCU e Blynk

21 21-03:00 fevereiro 21-03:00 2017 — 30 Comentários

Algum tempo atrás, desenvolvemos aqui o projeto de um sistema de jardinagem totalmente automatizado: “ArduFarmBot: Controlando um tomateiro com a ajuda de um Arduino e Internet das coisas (IoT)“. As principais especificações originais serão mantidas nesta nova versão, o ArduFarmBot 2, porém agora o projeto será baseado nas plataformas de IoT: NodeMCU ESP8266BLYNK.

Com base em dados coletados de uma plantação qualquer tais como, temperatura e umidade, tanto do ar quanto do solo, o ArduFarmBot 2 decidirá a quantidade certa (e quando) o plantio deve receber calor e água. O sistema deverá também permitir a intervenção manual de um operador para controlar uma bomba de água e uma lâmpada elétrica para gerar calor para a plantação. Esta intervenção manual deverá ser possível de ser executada tanto no local como remotamente via Internet.

Em suma, o sistema deve receber como

A. ENTRADA

  • Sensores:
    • Temperatura do ar
    • Umidade Relativa ao Ar
    • Temperatura do solo
    • Umidade do solo
  • Botões:
    • Bomba ON / OFF
    • Lâmpada ON / OFF

B. SAÍDA:

  • Atuadores:
    • Relé para controle da bomba
    • Relé para controle de lâmpada
  • Mensagens automáticas devem ser enviadas na ocorrência de eventos, tais como:
    • Bomba LIGADA
    • Lâmpada LIGADA
    • Sistema off-line
  • Exibição de dados
    • Todos os dados analógicos e digitais devem estar disponíveis para avaliação imediata
  • Armazenamento de dados
    • Dados históricos devem ser armazenados remotamente

O diagrama de blocos abaixo mostra os principais componentes do projeto.

1: Bill of Material (BoM)

  • 4.7K Ohms resistor – ($0.03)
  • 10K Ohms resistor – ($0.03)
  • 220 Ohms resistor – ($0.03)

2: O NodeMCU

Picture of The NodeMCU

O NodeMCU ESP-12E é a versão integrada do popular ESP8266, um Serial to Wi-Fi System On a Chip (SoC), que apareceu pela primeira vez em 2013 e lançado no mercado já no ano seguinte. O ESP8266 foi desenvolvido pela empresa chinesa com sede em Shangai, Espressif Systems, uma fabricante de circuitos integrados focada no desenvolvimento de chips de RF, particularmente Wi-Fi.

Existem vários módulos no mercado que se utilizam do chip ESP8266, Eles são nomeados ESP-NN, onde NN é um número 01, 02, … .. 12, etc. e as vezes seguido de uma letra. Estes módulos tipicamente possuem: o ESP8266 SoC, memória flash, um cristal e na maioria dos casos, uma antena. No link você pode encontrar a lista completa de dispositivos baseados  no ESP8266 encontradas no mercado: Família ESP8266 .

Os 2 módulos mais importantes são sem dúvida, a ESP-01 e o ESP-12E. No ArduFarmBot 2, usaremos o: ESP-12E Development Board (NodeMCU DevKit 1.0)

Para aumentar ainda mais a capacidade de utilização do módulo ESP-12E, foram adicionados regulação de potência e conectividade USB. O ESP-12E inclui:

  • Adaptador USB para UART: Silicon Labs CP2102,
  • NCP1117 3,3VDC Voltage Regulator,
  • Conector micro-USB,
  • Pinos adicionais com GND, Vin, 3,3VDC para facilitar o acesso durante o desenvolvimento.

Em suma, o NodeMCU ESP-12E é um dispositivo pronto para ser usado, bastando que você instale os drivers USB ao seu computador e comece a escrever programas que se conectam à sua rede Wi-Fi !

Especificações Técnicas:

  • Support STA/AP/STA+AP 3 working modes;
  • Built-in TCP/IP protocol stack, support multiple-channel TCP Client connection (max 5);
  • 0~D8, SD1~SD3: used for GPIO, PWM (D1-D8), IIC, ect; the driven ability can be arrived at 15mA;
  • AD0: one-way 10 bits ADC;
  • Power input: 4.5V~9V(10VMAX), support USB powered and USB debug;
  • Working current: ≈70mA(200mA MAX, continue), standby<200uA;
  • Transmission data rate: 110-460800bps;
  • Support UART/GPIO data communication interface;
  • Support update firmware remotely (OTA);
  • Support Smart Link;
  • Working temperature:-40℃~+125℃;
  • Driven mode: double large-power H bridge driven
  • Weight: 7g.

3: Instalando o NodeMCU com o Arduino IDE

Se você já tiver o NodeMCU instalado com o IDE, ignore esta etapa

Se você deseja programar e usar o NodeMCU como se fosse um Arduino, a boa notícia é que é possível escrever-se firmwares personalizados e carregá-los no chip (“flash-it”). É importante lembrar que qualquer novo “firmware personalizado” irá substituir qualquer coisa previamente armazenada na memória flash do chip, incluindo o firmware original carregado em fábrica (aquele que aceita os comandos AT). Embora possamos usar o SDK do fabricante para o desenvolvimento de firmwares personalizados, é muito mais fácil usar o bom e velho Arduino IDE.

Comecemos:

No Arduino IDE,  abra a janela de preferências e digite a URL (marcado em vermelho na foto abaixo) no campo Additional Boards Manager URLs e selecione OK.

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Picture of Installing the NodeMCU board at Arduino IDE

  • Selecione MENU  Tools → Board → Boards Manager…e vá rolando até encontrar a opção: esp8266 by ESP8266 Community , a qual deverá ser o último item da lista e clique INSTALL

arduino_ide_boards_esp8266

  • Instalando USB Drivers: O USB to Serial UART module incluído no dispositivo, é o  Silicon Labs’ CP2102, para o qual deveremos instalar o driver Virtual COM Port (VCP). No caso de meu MAC, o arquivo criado para comunicar com o CP2102 foi:  /dev/cu.SLAB_USBtoUART. Você pode encontrar o driver apropriado ao seu computador no seguinte link: CP210x USB to UART Bridge VCP Drivers
  • Depois de restartar o Arduino IDE , poderemos selecionar a placa no menu: Option Tools → Board → NodeMCU 1.0 (ESP-12E Module). Em seguida, especificar a correta frequência de operação da CPU: (Tools → CPU Frequency: “” → 80MHz) e velocidade de comunicação (Tools → Upload Speed: “” → 115,200). Finalmente, selecionar o port apropriado ao seu computador: (Tools → Port → /dev/cu.SLAB_USBtoUART).

nodemcu-ide-setup-3

Neste ponto estamos prontos para escrever nosso próprio firmware e enviá-lo ao dispositivo, mas vamos primeiramente tentar um dos exemplos incluídos com a biblioteca: File → Examples → ESP8266WiFi → WiFiScan. Após o upload, podemos abrir a janela do Serial Monitor e observar os resultados. Verifique que 115,200 baud é a velocidade selecionada no menu do canto inferior direito do Serial Monitor.

nodemcu-ide-setup-4

4: Instalando o Display OLED

Um grande companheiro para o nosso ESP-12E é o pequeno display do tipo OLED: SSD 1306. Ele será muito útil ao projeto, mostrando localmente os dados capturados, mensagens, etc. O modelo usado é um display de 128 x 64 pixels que se comunica via I2C, o SSD 1306, cujas principais características são:

  • 128 pixels na horizontal por 64 pixels na vertical. Assim se você usar por exemplo, caracteres de  8×8 pixels, obteremos um display de “16X8” (8 linhas de 16 caracteres cada).
  • Comunicação via I2C : se deve conectar ao NodeMCU I2C pins, usando:
    • SCL ==> D1 (equ. Arduino 5)
    • SDA ==> D2 (equ. Arduino 4)

Outra característica importante do SSD1306 é que você pode tanto alimentar-lo com 3.3V gerado diretamente pelo módulo nodeMCU, como via um Power Suppley externo de 5V, que será como faremos no projeto.

Uma vez conectado o display, você deve baixar e instalar sua biblioteca ao Arduino IDE. Nós usaremos a versão ACROBOT abaixo:

SSD1306 Arduino Library

Depois de ter reiniciado o IDE, a biblioteca deverá estar instalada. Carreguemos o sketch abaixo para testar o display OLED:


/***********************************************************************
* NodeMCU and OLED display "Hello World"
* Based on original code developed by: Makerbro at https://acrobotic.com/
* MJRoBot 12Oct16
************************************************************************/

#include 
#include 

void setup()
{
 Wire.begin(); 
 oled.init(); // Initialze SSD1306 OLED display
 oled.clearDisplay(); // Clear screen
 oled.setTextXY(0,0); // Set cursor position, start of line 0
 oled.putString(" MJRoBot.org");
 oled.setTextXY(4,0); // Set cursor position, start of line 4
 oled.putString(" HELLO, WORLD");
}

void loop()
{
}

Observe que quando você não definir um tamanho em pixels para os caracteres de texto, o padrão será 8X8. Para se definir um tamanho diferente, por exemplo,5X7, você poderá utilizar: oled.setFont(font5x7);

Abaixo o código para o “Hello World”:

5: Capturing Air Temperature and Humidity

Um dos sensores mais utilizados para a captura de dados meteorológicos é o DHT22 (ou seu irmão, o  DHT11), um sensor digital de humidade relativa do ar e temperatura. Ele usa internamente um sensor capacitivo de humidade e um termistor para medir o ar circundante, gerando um sinal digital em sua saída de dados. 

De acordo com a sua folha de dados (Datasheet), o sensor deve ser alimentado entre 3.3V e 5V (algumas especificações falam em até 6V max). Ele trabalha a partir de -40  a + 80 graus centígraods (algumas especs falam em + 125 ° C) com uma precisão de +/- 0,5 ° C de temperatura e +/-2% de umidade relativa. É importante ter em mente que o seu (“sencing period”) é em média de dois segundo (tempo mínimo entre leituras).

O site da Adafruit fornece uma série de informações sobre ambos, DHT22 e seu irmão DHT11. Para mais detalhes, visite a página:  Tutorial DHT22 / 11 .

O DHT22 tem 4 pinos (de frente para o sensor, o pino 1 é o mais esquerda):

    1. VCC (5V externo)
    2. Saída de dados
    3. Não conectado
    4. GND (Terra)

Uma vez que normalmente você usará o sensor em distâncias inferiores a 20m, um resistor de 10K deve ser conectado entre os pinos de dados e o VCC. O pino de saída deve ser conectado ao pino D3 do ESP-12E (veja o diagrama acima).

Uma vez que o sensor esteja instalado fisicamente no NodeMCU, baixe a biblioteca DHT a partir do repositório de programas:  Adafruit github e a instale junto as outras  bibliotecas de seu IDE (ambiente de desenvolvimento de programas do Arduino).

Uma vez que você recarregue o IDE, a biblioteca para o  sensor de DHT deverá aparecer como instalada. Execute o código abaixo para verificar se tudo está funcionando OK:

6: Capturando a humidade do solo

  • LM393 A0:    ao NodeMCU A0
  • LM393 VCC:  ao  VCC  5V externo (ou ao NodeMCU D8) Vide Nota abaixo *
  • LM393 GND: ao NodeMCU GND
  • LM393 D0:    Não conectado

(*) É importante destacar que o correto é conectar-se o VCC do Sensor a um Pino Digital do NodeMCU, definido como saída, de maneira a que o LM393 seja “alimentado” somente quando precisemos de uma leitura. Isto é importante não apenas para economizar energia, mas também para evitar a corrosão das sondas. Utilizando-se um sensor caseiro como foi o caso no projeto ArduFarmBot original, o sensor funcionaría sem problemas, mas tendo-se que alimentar o módulo comparador, o NodeMCU apresentou problemas com o  “soilMoisterVcc” conectado. Assim, conectei o LM393 direto a VCC (5V) externo como mostrado no diagrama elétrico acima  o código não precisa ser alterado).

Abaixo, rotina para ler o sensor conectado à porta analógica:

/***************************************************
 * Get Soil Moister Sensor data
 **************************************************/
void getSoilMoisterData(void)
{
  soilMoister = 0;
  digitalWrite (soilMoisterVcc, HIGH);
  delay (500);
  int N = 3;
  for(int i = 0; i < N; i++) // read sensor "N" times and get the average
  {
    soilMoister += analogRead(soilMoisterPin);   
    delay(150);
  }
  digitalWrite (soilMoisterVcc, LOW);
  soilMoister = soilMoister/N; 
  Serial.println(soilMoister);
  soilMoister = map(soilMoister, 600, 0, 0, 100); 
}

Alguns comentários sobre a rotina acima:

  • O dado do sensor é capturado 3 vezes, tirando-se uma média das mesmas.
  • Usamos MAP para configurar o intervalo em percentagem. Para definir os valores extremos, procedemos como abaixo:
    • Fazer um “curto-circuito” nas pontas de prova do higrômetro, isso equivalente a “100% de umidade”, o que gerará um valor de cerca de 0 na saída do ADC
    • Colocar o higrômetro”no ar”, se observa que o valor exibido no Serial Monitor, que em meu caso foi em torno de 600.
 Abaixo um codigo parcial para os testes até esta etapa do projeto:

7: Capturando a temperatura do solo

O DS18B20 é um sensor digital, o que o torna ideal para o uso em longas distâncias! Estes sensores digitais de temperatura  tipo “1-Wire” são bastante precisos (± 0,5 ° C em grande parte da gama) e podem fornecer até 12 bits de precisão à partir de seu conversor digital-analógico integrado. Eles funcionam muito bem com o NodeMCU usando um único pino digital, e você pode até mesmo conectar vários sensores no mesmo pino, pois cada um possui um ID único de 64 bits gravado de fábrica, para poder diferenciár-los.

  • O sensor funciona de 3,0 a 5,0V.
  • O sensor tem 3 fios:
    • Preto: GND
    • Vermelho: VCC
    • Amarelo: dados de 1 fio

Aqui, você pode encontrar os dados completos: DS18B20 Datasheet

Para usar o DS18B20 com o IDE do Arduino, importe as bibliotecas abaixo e a s instale em seu IDE:

Para testar o sensor, você pode usar o código “Simple.ino” incluído nos Exemplos da Biblioteca, como mostrado na foto acima. Carregue o código no seu NodeMCU e monitore a temperatura usando o Monitor Serial.

fp44q1eixkpxu98-large

A foto acima mostra o resultado esperado. Segure o sensor em sua mão, você deve ver a temperatura mudar para cerca de 32 / 34oC.

NOTA1: A biblioteca OneWire DEVE ser uma versão especial, modificada para ser usada com o ESP8266, caso contrário você receberá um erro durante a compilação. Você encontrará a última versão no link acima ou no arquivo zip abaixo:

8: Completando o HW

Para verificar se existe um “comando local”, ou seja se um botão foi pressionado, a função readLocalCmd() deve ser executada. Esta função lê cada botão, atualizando o status das variáveis correspondentes aos estados dos atuadores (pumpStatus e lampStatus). Observe que em vez de executar diretamente um comando digitalRead (pin), a função debounce(pin) é chamada. Isso é para evitar leituras falsas do botão. Se você quiser saber mais sobre o “debouncing”, visite o link:  Debouncing Tutorial.

/****************************************************************
* Read local commands (Pump and Lamp buttons are normally "HIGH"):
****************************************************************/
void readLocalCmd() 
{  
  boolean digiValue = debounce(PUMP_ON_BUTTON);
  if (!digiValue) 
  {
    pumpStatus = !pumpStatus;
    aplyCmd();
  }

  digiValue = debounce(LAMP_ON_BUTTON);
  if (!digiValue) 
  {
    lampStatus = !lampStatus;
    aplyCmd();
  }
}

No caso em que um botão é pressionado, outra função será chamada: aplyCmd (). E como o nome diz, esta aplicará o comando correspondente, ativando ou desativando os atuadores:

/***************************************************
* Receive Commands and act on actuators
****************************************************/
void aplyCmd()
{
  if (pumpStatus == 1) 
  {
    digitalWrite(PUMP_PIN, HIGH);
    displayData();
  }
  else
      {
        digitalWrite(PUMP_PIN, LOW);
        displayData();
      }
  
  if (lampStatus == 1) 
  {
    digitalWrite(LAMP_PIN, HIGH);
    displayData();
  }
  else
      {
        digitalWrite(LAMP_PIN, LOW);
        displayData();
      }
}

Considerações acerca do código:

Quando pensamos sobre o 4 grandes “grupo de tarefas” desenvolvidos até agora, podemos resumir-los em:

  • Ler Sensores
  • Ler Botões (comando local)
  • Atuar na bomba / lâmpada
  • Exibir dados

Perceberemos que o momento em que devemos realizar essas tarefas não são necessariamente os mesmos. Por exemplo, para ler os dados de temperatura e umidade do DHT 22, teremos que esperar pelo menos 2 segundos entre uma medida e outra, mas se esperamos alguns minutos, isto não fará diferença no projeto final. Para o sensor de umidade do solo, quanto menos medições fizermos, melhor (diminui a corrosão das sondas geradas por eletrólise). Mas quando pensamos nos atuadores, logo que pressionamos um botão, gostaríamos (e possivelmente precisaremos) de uma reação rápida.

Portanto, devemos usar aqui um “timer” para controlar corretamente o timing correto dessas tarefas. Poderíamos fazer isso usando o millis (), como fizemos no projeto ArdFarmBot original, mas aproveitaremos para conhecer outra ótima ferramenta, o SimpleTimer.h (siga as instruções no link ao lado para instalar a Biblioteca: SimpleTimer)

A biblioteca deve ser incluída no corpo principal do seu código, seguido de uma definição para o Timer do projeto:

  SimpleTimer timer;

Em seguida, defina os temporizadores:

  timer.setInterval(1000L, readLocalCmd);       // Read buttons at every 1 second
  timer.setInterval(2000L, getSoilTempData);    // Read Soil Temp at every 2 seconds
  timer.setInterval(2000L, getDhtData);         // Read DHT Sensor at every 2 seconds
  timer.setInterval(10000, getSoilMoisterData); // Read Soil Humidity at every 10 seconds
  timer.setInterval(10000, displayData);        // Display Data at OLED at every 10 seconds

9: ArduFarmBot 2,  “Contrôle Local”- Concluindo o código

Apresentando o Botão para Leitura dos sensores (“O amarelo”)

Como observamos na última etapa, precisaremos aguardar ciclos longos entre as medições do sensor de umidade do solo. Isto está bem para as nossas necessidades automáticas, mas para uma operação manual não vamos querer “esperar” 10, 15 ou mais segundos (ou mesmo minutos no caso real) para atualizar a leitura de um sensor. Também no mundo real, não faz sentido manter o display OLED “ACESO” ou “ON”, o tempo todo. Assim, o normal será “APAGADO” ou “OFF”.

Introduziremos esse 3 ª botão ao nosso projeto, o qual permitirá exibir os dados de leitura dos sensores a qualquer momento que quisermos, independentemente do tempo das leituras automáticas. Além disso, usaremos este mesmo botão para exibir dados no OLED quando os sensores forem atualizados. Abaixo da função readLocaCmd () alterada para interação com o novo botão:

/**************************************************************************
* Read local commands (Pump, Lamp and Sensor buttons are normally "HIGH"):
**************************************************************************/
void readLocalCmd() 
{  
  boolean digiValue = debounce(PUMP_ON_BUTTON);
  if (!digiValue) 
  {
    pumpStatus = !pumpStatus;
    aplyCmd();
  }

  digiValue = debounce(LAMP_ON_BUTTON);
  if (!digiValue) 
  {
    lampStatus = !lampStatus;
    aplyCmd();
  }

  digiValue = debounce(SENSORS_READ_BUTTON);
  if (!digiValue) 
  {
    turnOffOLED = !turnOffOLED;
    if (!turnOffOLED)
    {
      oled.setTextXY(0,0); oled.putString("UPDATING SENSORS");
      getDhtData();
      getSoilMoisterData();
      getSoilTempData();
      oledStart();
      displayData();
    }else oled.clearDisplay(); //turn off OLED
  }
}

Neste ponto, todo o HW está completado (usando-se LEDs como atuadores) e temos portanto todas as peças de SW à serem montadas.

O vídeo mostra o ArduFarmBot 2, operando em modo Local e Manual:

Você poderá fazer o download do código a ser utilizado na versão “Controle local”, diretamente em meu repositório:  GitHub: ArduFarmBot2_Local_Manual_Ctrl_V1

10: Automatizando nosso sistema de jardinagem

Neste ponto, todos os componentes do HW estão no lugar e como se viu na etapa anterior, o ArduFarmBot 2 pode ser controlado localmente por um operador através dos botões. O que falta agora é definir-se a “lógica” que permitirá ao nosso sistema realizar a tarefa de irrigar a plantação automaticamente! Para isto, precisamos incluir algum “cérebro” ao nosso projeto.

Para começar, definamos o intervalo inicial onde funcionarão os sensores. Esses valores devem ser alterados mais tarde usando-se valores práticos a serem obtidos em uma plantação real:

Umidade do solo:

  • “HÚMIDO”: Mais de 88% (não regar)
  • “IDEAL”: Entre 66% e 88% (Onde queremos trabalhar) e
  • “SECO”: abaixo de 66% (necessário ligar a bomba para aumentar a umidade)

Temperatura do ar:

  • “FRIO”: Abaixo de 12oC (Ligar a lâmpada para gerar calor)
  • “IDEAL”: entre 12oC e 22oC
  • “QUENTE”: Acima d 22oC (não ligar a lâmpada)

Você deve levar em conta que cada tipo de semente possui um intervalo ótimo de temperatura onde germinarão mais rapidamente. Por exemplo, para tomates o tempo mínimo para germinar as sementes será de 6 dias em temperaturas entre 20 e 25 oC, sendo que esta quantidade de dias aumentará para temperaturas inferiores ou superiores (mais de 43 dias para temperaturas inferiores a 10oC e 9 dias para temperaturas superiores a 35oC.

Você poderá verificar mais informações sobre este relacionamento (Temp / dias de germinação) no link abaixo:

The effect of soil temperature on seeds germination

Uma vez de posse desses dados: temperatura do ar, umidade do ar, umidade do solo e temperatura do solo, poderemos construir uma matriz complexa definindo como queremos que o nosso sistema de jardinagem automático funcione. Na Etapa 7 do ArduFarmBot: Part 2 – “Estação Remota” – IoT, se desenvolveu uma abordagem em profundidade sobre a relação Sensor-Matrix. Nesta etapa porém, utlizaremos apenas relações simples para facilidade de entendimento.

Definamos os parâmetros à serem usados em nosso código:

/* Automatic Control Parameters Definition */
#define DRY_SOIL      66
#define WET_SOIL      85
#define COLD_TEMP     12
#define HOT_TEMP      22
#define TIME_PUMP_ON  15
#define TIME_LAMP_ON  15

TIME_PUMP_ON e TIME_LAMP_ON são definidos como o tempo em segundos que a bomba e a lâmpada devem permanecer LIGADAS durante a operação automática.

Com base nos parâmetros acima, pensemos em algumas suposições muito simples a serem implementadas no código:

  • Se o solo estiver seco: (DRY) ==> Ligar a bomba (PUMP = ON)
  • Se a temperatura estiver fria (COLD) ==> Ligar a lâmpada (LAMP = ON)

Manteremos a coisa simples e não exploraremos todas as possíveis combinações bem como o  papel dos demais sensores como a umidade do ar ou temperatura do solo na equação, como fizemos no projeto original. Isto ficará como “lição de casa”! 😉

O código:

Criemos uma nova função, que com base na leitura dos sensores lidará automaticamente com os atuadores, ligando / desligando a bomba e a lâmpada: autoControlPlantation (). Esta função conforme mostrado abaixo, será chamada em todas os ciclos de leitura de sensores:

/**************************************************************
* Automatically Control the Plantation based on sensors reading
**************************************************************/
void autoControlPlantation(void)
{ 
  if (soilMoister < DRY_SOIL) 
  {
    turnPumpOn();
  }

  if (airTemp < COLD_TEMP) 
  {
    turnLampOn();
  }
}

A função tem duas tarefas básicas:

  • Controlar a bomba
  • Controlar a lâmpada

Abaixo as duas funções de controle chamadas a partir da função autoControlPlantation ():

***************************************************
* Turn Pump On for a certain amount of time
****************************************************/
void turnPumpOn()
{
  pumpStatus = 1;
  aplyCmd();
  delay (TIME_PUMP_ON*1000);
  pumpStatus = 0;
  aplyCmd();
}

/***************************************************
* Turn Lamp On for a certain amount of time 
****************************************************/
void turnLampOn()
{
  lampStatus = 1;
  aplyCmd();
  delay (TIME_LAMP_ON*1000);
  lampStatus = 0;
  aplyCmd();
}

Por fim, usemos o botão Sensor Read (“amarelo”) para não só interromper o programa durante um certo tempo durante a inicialização, mas também para exibir os parâmetros iniciais mais importantes, como mostrado na foto acima.

Neste ponto, o ArduFarmBot está totalmente funcional em termos de HW e SW.

O vídeo mostra o ArduFarmBot 2, operando em modo Local e Automático:

O código para a versão  “Local e Automático” do ArduFarmBot2 pode ser descarregada  de meu depositário:  GitHub: ArduFarmBot2_Local_Automatic_Ctrl_V2.

11: Criando a App BLYNK

É realmente muito fácil de se construir projetos IoT usando o BLYNK. A primeira coisa que você precisará, é ter a aplicação BLINK instalada no telefone e sua biblioteca instalada no IDE do Arduino. Se ainda não as tiver, siga os passos abaixo:

Uma vez que o Arduino IDE é recarregado, você deve estar OK para começar a usar BLINK em seu projeto IoT.

Agora, vamos abrir o aplicativo “Blynk”  no smartphone:

  1. Clique na tela Create New Project
  2. De um nome para seu projeto (Por exemplo: “ArduFarmBot 2”)
  3. Selecione o HW apropriado: NodeMCU
  4. Anote seu código do Authorization Token (você pode enviar-lo por e-mail e copiar-lo em seu código):
    char auth[] = "YourAuthToken";
  5. Pressione OK. Uma tela vazia cheia de pontos irá aparecer.
  6. Clique na tela para abrir o Widget Box

OK, vamos tomar um momento e pensar sobre o nosso ArduFarmBot 2 Blynk App e definir quais serão os Widgets a serem instalados. Revisitando a especificação geral descrita na introdução do projeto, podemos resumir que o nosso aplicativo precisará:

  • Ler todos os sensores e verificar o status dos atuadores
  • Tomar ações remotas, como “ligar / desligar” a bomba e a lâmpada
  • Enviar mensagens quando o sistema estiver “off-line” e / ou um atuador for ligado
  • Registrar a história de leitura dos sensores

De maneira a organizar as coisa, vamos dividir as tarefas descritas acima em 3 Tabs:

  • SENSORS
  • ACTUATORS / CONTROL
  • GRAPHICS

“Tabs” será o primeiro Widget a ser instalado. Uma vez selecionado, defina “Tab names” como acima.

Em seguida, entre em cada um dos Tabs criados e instale os Widgets como descritos abaixo:

SENSORS

  • Gauge: “Temp Air [oC]” Blue; input: V10 0 to 50; frequency: 5 sec
  • Gauge: “Humidity Air [%]” Green; input: V11 0 to 100; frequency: 5 sec
  • Gauge: “Soil Humidity [%]” Red; input: V12 0 to 100; frequency: 5 sec
  • Gauge: “Soil Temperature[oC]” Yellow; input: V13 -10 to 50; frequency: 5 sec
  • LED: “PUMP” Red; V0
  • LED: “LAMP” Green; V1

ACTUATORS / CONTROL

  • Button: “PUMP” Red; output: V3 0 to 1; mode: Switch; label: on: ACT, off: OK
  • Button: “LAMP” Green; output: V4 0 to 1; mode: Switch; label: on: ACT, off: OK
  • LED: “PUMP” Red; V0
  • LED: “LAMP” Green; V6
  • Notifications: Notify When HW goes offline: ON

GRAPHICS

  • Data to Show:
  • V10 “Temp Air”
  • V11 “Humidity Air”
  • V12 “Soil Humidity “
  • V13 “Soil Temp”

12: Alterando o código para introduzir as funcionalidades do Blynk

Para executar um aplicativo Blynk juntamente com seu código, você precisará:

  • Incluir a biblioteca BlynkSimpleEsp8266 no início do seu código
  • Durante o setup(), inicie com as credenciais do Blynk: Blynk.begin (auth, ssid, pass);
  • Defina uma temporização para enviar dados locais para o servidor Blynk: timer.setInterval (5000L, sendUptime);
  • Dentro do loop (), execute a função Blynk.run();
  • Crie a função sendUptime (); Onde você introduzirá os dados do sensor a serem enviados ao Blynk Server: Blynk.virtualWrite (VirtualPin, dados do sensor);

O código final deverá incluir agora um novo arquivo: “StationCredentials.h”:

char auth[] = "YOUR PROJECT TOKEN"; // Blynk project: "ArduFarmBot2"
char ssid[] = "YOUR LOCAL WIFI NAME";
char pass[] = "YOUR WIFI PASSWORD";

Other considerations:

Para usar um Widget do tipo: “Virtual LED” na app do Blynk, você necessitará definir-lo no início do código:

WidgetLED PUMPs(V0);  // Echo signal to Sensors Tab at Blynk App
WidgetLED PUMPa(V5); // Echo signal to Actuators Tab at Blynk App
WidgetLED LAMPs(V1);  // Echo signal to Sensors Tab at Blynk App
WidgetLED LAMPa(V6); // Echo signal to Actuators Tab at Blynk App

Para acender ou apagar o LED relacionado com a Bomba (PUMPs LED) que está conectado ao virtual PIN V0 por exemplo, chame as funções correspondentes abaixo:

  • PUMPs.on() ou
  • PUMPs.off()

Incluiremos os comandos na função applyCmd (), de maneira que os LEDs na app Blynk irão imitar os LEDs reais de nosso projeto. Também deveremos incluir o comando: Blynk.notify (“Mensagem a ser enviada”); na mesma função applyCmd (), uma para a Bomba e outra para a Lâmpada. Abaixo, a nova função:

/***************************************************
* Receive Commands and act on actuators
****************************************************/
void aplyCmd()
{
  if (pumpStatus == 1) 
  {
    Blynk.notify("ArduFarmBot2: Warning ==>> Pump ON"); 
    digitalWrite(PUMP_PIN, HIGH);
    if (!turnOffOLED) displayData();
    PUMPs.on();
    PUMPa.on();
  }
  else
      {
        digitalWrite(PUMP_PIN, LOW);
        if (!turnOffOLED) displayData();
        PUMPs.off();
        PUMPa.off();
      }
  
  if (lampStatus == 1) 
  {
    Blynk.notify("ArduFarmBot2: Warning ==>> Lamp ON");
    digitalWrite(LAMP_PIN, HIGH);
    if (!turnOffOLED) displayData();
    LAMPs.on();
    LAMPa.on();
  }
  else
      {
        digitalWrite(LAMP_PIN, LOW);
        if (!turnOffOLED) displayData();
        LAMPs.off();
        LAMPa.off();
      }
}

Para receber um comando a partir de um botão (Widget button) incluído na app Blynk, uma função BLYNK_WRITE () deve ser definida fora de uma função, loop () ou setup (). Para isso foi criado o código abaixo, um para cada Botão Blynk (PUMP e LAMP):

/****************************************************************
* Read remote commands 
****************************************************************/
BLYNK_WRITE(3) // Pump remote control
{
  int i=param.asInt();
  if (i==1) 
  {
    pumpStatus = !pumpStatus;
    aplyCmd();
  }
}

BLYNK_WRITE(4) // Lamp remote control
{
  int i=param.asInt();
  if (i==1) 
  {
    lampStatus = !lampStatus;
    aplyCmd();
  }
}

Abaixo, o vídeo mostra a operação automática do ArduFarmBot 2, agora incluíndo o Blynk:

O código para o ArduFarmBot2 em sua versão “Remote and Automatic control”, usando o Blynk pode ser descarregada de meu repositório:  GitHub: ArduFarmBot2_Ext_Auto_Ctrl__V3_0

13: Relés como atuadores

Como discutido na introdução, nosso objetivo final será cuidar de uma plantação. Com os dados fornecidos pelos sensores, vamos saber a temperatura do ar e do solo, umidade relativa do ar e o mais importante, quão “seco” está o solo. Com esses dados na mão, o nosso programa deve calcular se é necessário irrigar a plantação ligando uma bomba de água ou acender uma lâmpada elétrica para fornecer o calor adequado para a cultura.

Para isso, usaremos um pequeno módulo de relé de 5V tanto para a ativação da bomba quanto da lâmpada.

O circuito do diagrama do módulo de relé pode ser visto abaixo:

Pelo diagrama, devemos conectar :

  • Power Supply 5V ==> (4) “Vcc”
  • NodeMCU D6 ==> (3) “IN1” (Pump)
  • NodeMCU D7 ==> (2) “IN2” (Lamp)
  • NodeMCU GND ==> (1) “GND”

Dependendo do módulo de relés escolhido, os labels podem ser diferentes

Normalmente encontramos como saída, 3 pinos para cada relé: “NO” (“Normal Open“), “Ref” or “COM” (“Reference” or “Common“) and “NC” (“Normal Closed“). Usaremos o NO e o COM para cada relé.

No exemplo abaixo, o “COM” é o terminal para conectar ao pino positivo externo da fonte de alimentação de 5V(no caso da bomba (ou do 220VAC para a lâmpada). O “NO” será conectado à Bomba (ou Lâmpada).

No caso do relé escolhido e confirmado pelo diagrama acima, normalmente o IN1 e o IN2 devem estar em ALTO e sua ativação acontecerá com um nível BAIXO (menos de 2V). Com um nível BAIXO na saída do NodeMCU, a corrente fluirá de VCC para o pino D6 do NodeMCU, ativando a entrada do optoacoplador. O solenóide será acionado, “fechando” a saída NO (normalmente aberta) do relé, o que ligará a bomba.

Em relação a versão V3.0 do código desenvolvida na etapa anterior,  deveremos “inverter”a logica de acionamento dos atuadores (ou pinos digitais como saída). Os pinos D6 e D7 do NodeMCU deverão estar normalmente em HIGH. Assim a função de setup(), deverá ser alterada:

digitalWrite(PUMP_PIN, HIGH); // To be used with Relay module (inverted logic: normally HIGH)
digitalWrite(LAMP_PIN, HIGH); // To be used with Relay module (inverted logic: normally HIGH)

Também deveremos  alterar a função applyCmd():

/***************************************************
* Receive Commands and act on actuators
****************************************************/
void aplyCmd()
{
  if (pumpStatus == 1) 
  {
    Blynk.notify("ArduFarmBot2: Warning ==>> Pump ON"); 
    digitalWrite(PUMP_PIN, LOW); // To be used with Relay module (inverted logic: activate with LOW)
    if (!turnOffOLED) displayData();
    PUMPs.on();
    PUMPa.on();
  }
  else
      {
        digitalWrite(PUMP_PIN, HIGH); // To be used with Relay module (inverted logic: normally HIGH)
        if (!turnOffOLED) displayData();
        PUMPs.off();
        PUMPa.off();
      }
  
  if (lampStatus == 1) 
  {
    Blynk.notify("ArduFarmBot2: Warning ==>> Lamp ON");
    digitalWrite(LAMP_PIN, LOW); // To be used with Relay module (inverted logic: activate with LOW)
    if (!turnOffOLED) displayData();
    LAMPs.on();
    LAMPa.on();
  }
  else
      {
        digitalWrite(LAMP_PIN, HIGH); // To be used with Relay module (inverted logic: normally HIGH)
        if (!turnOffOLED) displayData();
        LAMPs.off();
        LAMPa.off();
      }
}

O código para o ArduFarmBot2 em sua versão “Remote and Automatic control”, usando o Blynk e relés (ativos com “LOW”)pode ser baixado desde meu repositório:  Github: ArduFarmBot2_Ext_Auto_Ctrl__V4_0

14: Teste real com o ArduFarmBot 2

Você pode instalá-lo submerso em água ou “inline”. Usaremos o segundo método.

Ligue um dos fios da bomba ao relé IN1 e o outro ao pino de alimentação externa de 5V (+). Pegue o pino de alimentação (-) e ligue-o ao relé COM1.

O filme abaixo mostra o ArduFarmBot 2 operando em modo manual (local e remoto):

E finalmente, o vídeo abaixo mostra sua operação em modo automático:

15: Conclusão

Como sempre, espero que este projecto possa ajudar outros a encontrarem o seu caminho no emocionante mundo da eletrônica e do IoT!

Para obter os arquivos atualizados, consulte meu repositório: ArduFarmBot2 GitHub

Não deixe de visitar e seguir minha página: MJRoBot.org no Facebook

Saludos desde el sur del mundo!

Nos vemos em meu próximo post!

Obrigado

Marcelo

30 Respostas para “ArduFarmBot 2” – Sistema automático para irrigação e calor, agora com o NodeMCU e Blynk

  1. 

    Parabéns pelo seu magnifico Trabalho, muito claro e didaticamente correto.

    Curtir

  2. 

    Puxa que projeto excelente e bem detalhado. Parabéns!!! Espero que depois de tantos anos ainda esteja por aí. Estou me interessando por programação de microcontroladores e integração com Blynk mas como hobby. Já passei da idade de estudar pra outros fins!!!
    Queria tirar uma dúvida… não encontrei qual a função que faz o pino digital do Sensor de Umidade (com o LM393) acionar o sensor pra fazer a leitura? Faz de quanto em quanto tempo? Sei que tem essa possibilidade via Blynk no “Timer”

    Curtir

  3. 

    Ola Professor ,desculpa mais vai uma pergunta simples mais que estou apanhando ,Qual é o Widget de Grafico ? Nao estou conseguindo achar
    Mais uma vez parabens pelo trabalho, devagarinho estou quase chegando la uhuuuuu

    Curtir

  4. 

    Amigo me perdoe se mandei errado ,copiei o erro da IDE e postei tudo ,A placa esta conectada e estou apenas copilando e da esse erro ai olha .Se puder ajudar agradeço de coraçao e parabens pela iniciativa de ajudar as pessoas

    Erro compilando para a placa NodeMCU 0.9 (ESP-12 Module)

    Curtir

  5. 

    Olá, Marcelo! Parabéns pelo excelente projeto, achei uma maravilha =D.
    Fiquei com uma dúvida com relação a conexão dos relés ao NodeMCU. Nas suas fotos não há transistores e resistores entre o módulo relé e o nodemcu (como há no esquemático do circuito). Por acaso eles já estão inclusos na placa do relé? Pergunto pois na maioria dos posts da internet as pessoas incluem um transistor e um resistor, além do módulo relé. Muito obrigado pela atenção!

    Curtir

  6. 

    Boa Noite,
    Ja estou a mais de 1 mês tentando realizar este projeto e estou muito triste, nao consigo de jeito nenhum.
    Sempre a mesma falha # include ” stationDefines.h ” // Definições do projeto
    fala que nao esta no diretorio,é muito confuso este codigo para que esta começando como eu.
    preciso de ajuda.

    Curtir

  7. 

    Marcelo, parabéns pela sua didática! É perceptível o dom que tens no ensino. Eu que tenho conhecimento apenas de conceitos básicos em programação (não sei escrever código), consegui entender muita coisa por aqui.

    Tenho uma estufa e estou querendo automatiza-la, apesar de não saber programar, graças ao teu compartilhamento, decidi que vou me aventurar a programar meu projeto usando teus códigos.

    Por gentileza você poderia dar uma lida na minha ideia e me direcionar onde terei que atentar para fazer as adaptações nos seus códigos? Se puder me passar referências de onde aprender a fazer essas adaptações agradeço também!

    Segue minha ideia.

    1. Temperatura/Umidade do ar- Desejo acionar um sistema de ventilação quando a temperatura/umidade atingirem um limite superior, mas ao invés de ligar por um tempo determinado como no seu projeto, eu gostaria de manter ligado até que a temperatura voltasse à faixa aceitável e ai sim acionar o desligamento. Pretendo fazer o mesmo com o limite inferior de umidade, ligando/desligando um umidificador de ar, seguindo a mesma lógica.

    2. Luz – Basicamente um timer, controlar o fotoperíodo (luz/escuridão).

    3. Umidade do solo – Exatamente como no seu projeto, no entanto quero encontrar um sensor maior, que seja capaz de monitorar uma área maior do solo.

    Assim como no seu projeto quero automação, monitoramento e controle manual pessoalmente e remotamente, também atrás do Blynk.

    Para o HW usarei as mesma coisas exceto por um rele de 4 canais e outro sensor para umidade do solo.

    Curtir

  8. 

    Hola Marcelo. Excelente trabajo. Parabens. Im only having one problem, Im not getting a proper reading for the soil moisture sensor. Sometimes it says minus something, sometimes it doesn’t change its value when im trying it on differents plant.

    Any clue?

    Curtir

  9. 

    Boa noite, queria usar este projeto junto ao thingSpeak alguma dica ?

    Curtir

  10. 

    Y entonces este directorio hay que contener todos los 6 archivos. Abra el Archivo: ArduFarmBot2_Ext_Auto_Ctrl__V4_0.ino en el Arduino IDE y automáticamente los 6 arquivos estarán conectados.

    Curtir

  11. 

    Hay que crear un directorio con es mismo nombre del arquivo Principal:
    ArduFarmBot2_Ext_Auto_Ctrl__V4_0

    Curtir

  12. 

    mi comentario párese que no se entendió mucho quiero saber cual es código original si me lo podrías dar seria genial por-favor empece hace muy pooco con esto de arduino

    Curtir

  13. 

    hola sabes recién comencé con esto de arduino y quiero hacer este proyecto descargue todo pero aun no entiendo cual es el codigo si me lo pudieras dar seria genial muchas gracias el esquema lo entendi pero el codigo verdadero nose cual es de todos

    Curtir

  14. 

    Marcelo, como ficaria o código(readLocalCmd) para lê interruptores normais(mudança de estado), ao invés de push buttons?
    Obrigado!

    Curtir

  15. 

    Olá Marcelo, parabéns e obrigado por compartilhar seu trabalho!
    Minha dúvida é em relação a leitura dos botões (função debounce), pois a variável state armazena o estado de um único botão, é isso mesmo? Como ficaria para ler vários botões, que no meu caso seria alguns interruptores da minha casa.
    Grato!

    Curtir

    • 

      Oi JOSÉ Carlos. A função debounce é uma só, que é chamada ao se apertar um botão (para “estabilizar” o estado. Mas a cada botão, corresponde uma variável diferente. Obviamente, se considera que os botões não vão ser o o pressionados simultaneamente.

      Curtir

  16. 

    Thank you Marcelo Rovai for your great project.
    – I found your project on the Internet.
    – I’m trying to compile V4.0 version and it’s a bug.

    The error is listed as follows:
    C:\Users\GioLangLe\Desktop\Pump\Pump.ino: In function ‘void setup()’:

    Pump:56: error: ‘oledStart’ was not declared in this scope

    oledStart();

    ^

    Pump:68: error: ‘waitButtonPress’ was not declared in this scope

    waitButtonPress (SHOW_SET_UP); // Wait for Sensor Button to be pressed

    ^

    Pump:70: error: ‘startTimers’ was not declared in this scope

    startTimers();

    ^

    C:\Users\GioLangLe\Desktop\Pump\Pump.ino: In function ‘void readLocalCmd()’:

    Pump:107: error: ‘debounce’ was not declared in this scope

    boolean digiValue = debounce(PUMP_ON_BUTTON);

    ^

    Pump:128: error: ‘getDhtData’ was not declared in this scope

    getDhtData();

    ^

    Pump:129: error: ‘getSoilMoisterData’ was not declared in this scope

    getSoilMoisterData();

    ^

    Pump:130: error: ‘getSoilTempData’ was not declared in this scope

    getSoilTempData();

    ^

    Pump:131: error: ‘oledStart’ was not declared in this scope

    oledStart();

    ^

    Pump:132: error: ‘displayData’ was not declared in this scope

    displayData();

    ^

    C:\Users\GioLangLe\Desktop\Pump\Pump.ino: In function ‘void aplyCmd()’:

    Pump:146: error: ‘displayData’ was not declared in this scope

    if (!turnOffOLED) displayData();

    ^

    Pump:153: error: ‘displayData’ was not declared in this scope

    if (!turnOffOLED) displayData();

    ^

    Pump:162: error: ‘displayData’ was not declared in this scope

    if (!turnOffOLED) displayData();

    ^

    Pump:169: error: ‘displayData’ was not declared in this scope

    if (!turnOffOLED) displayData();

    ^

    exit status 1
    ‘oledStart’ was not declared in this scope


    Can you give me suggestions?
    I am using Arduino IDE 1.8.1, Blynk 0.4.7, NodeMCU v1

    Curtir

    • 

      Hi. No, it is not a bug. You are not compiling the code correctly. The Arduino IDE must have all 6 files in the same folder. Also, note that the folder must have the same name as the main .ino file (ArduFarmBot2_Ext_Auto_Ctrl__V4_0)
      If you do it correctly, you will have the 6 tabs at your IDE one for each file.
      You can find several tutorials on the internet (like this one bellow) explaining how to work with multiple files at Arduino IDE: https://www.youtube.com/watch?v=gxLpob4fiWQ)
      Thanks

      Curtir

  17. 

    Estou tentando conectar o sensor de Corrente SCT013 no ESP nodemcu e mostrar os dados no blynk. Este código do sensor analógico só serve para o Higrômetro ?

    Curtir

    • 

      Oi Cindy. O NodeMCU tem uma entrada analógica. Variand-se o sinal analógico D.C. nesta entrada de 0 a 3.3V, internamente o ADC gerará um dado digital proporcional variando de 0 a 1023. Eu nunca usei esse sensor de corrente, mas desde que ele gere um sinal analógico equivalente ao comentado acima, não vejo problema. Cuidado com os valores máximos de tensão e corrente gerados pelo sensor que devem ser compatíveis as entradas do NodeMCU.
      De uma olhada em meu último post, ele é mais simples e talvez te explique melhor:

      IoT feito simples: Controlando servos com o NodeMCU e o Blynk


      Um abraço

      Curtir

  18. 

    Boa tarde, tenho dois vasos com dois sensores de humidade do solo, como só existe uma entrada ananlógica A0, será que existe alguma possibilidade de ler os dois valores??

    Curtir

    • 

      Sim. O NodeMCU possuir somente um Analog Digital Converter (ADC) de 10 bits integrado. Quando comparado com um Arduino UNO que tem 6 ADCs “portas” ou o Nano que tem 8, parece que o NodeMCU sai perdendo aqui. Mas isto não é necessariamente verdade. Primeiro, os Arduinos UNO ou Nano em realidade, possuem apenas um ADC integrado internamente o qual deve ser multiplexado para se poder ler suas múltiplas entradas analógicas. Então, podemos fazer exatamente o mesmo com o NodeMCU.

      Você necessite ler 2 sensores analógicos:
      Higrômetro 1 (Sensor 1)
      Higrômetro 2 (Sensor 2)

      O que devemos fazer é criar um “multiplexador” via diodos, “alimentando-se individualmente cada um desses sensores a cada vez que precisemos ler um deles. Para isso você deve definir para cada sensor, uma das GPIOs digitais como saída, colocando-as em nível ALTO em cada leitura.

      Por exemplo, o código abaixo daria conta do recado:

      #include

      int sensorPin = A0; // analog input for both sensors
      int enable1 = D1; // enable reading Sensor 1
      int enable2 = D2; // enable reading Sensor 2

      int sensorValue1 = 0; // variable to store the value coming from sensor 1
      int sensorValue2 = 0; // variable to store the value coming from sensor 2

      void setup()
      {
      Serial.begin(115200);
      delay(10);
      pinMode(enable1, OUTPUT);
      pinMode(enable2, OUTPUT);
      }

      void loop()
      {
      // Sensor 1
      digitalWrite(enable1, HIGH);
      sensorValue1 = analogRead(sensorPin);
      sensorValue1 = constrain(sensorValue1, xxx, yyy);
      sensorValue1 = map(sensorValue1, xxx, yyy, 0, 1023);
      Serial.print(“Sensor 1 value: “);
      Serial.println(sensorValue1);
      digitalWrite(enable1, LOW);
      delay(100);

      // Sensor 2

      digitalWrite(enable2, HIGH);
      delay(500);
      sensorValue2 = analogRead(sensorPin);
      sensorValue2 = constrain(sensorValue2, xxx, yyy);
      sensorValue2 = map(sensorValue2, xxx, yyy, 1023, 0);

      Serial.print(“Sensor 1 value: “);
      Serial.println(sensorValue2);
      Serial.println();
      delay(100);

      digitalWrite(enable2, LOW);
      }

      Como aqui não consigo responder com fotos, de uma olhadinha em meu post:

      Do “blink” ao BLYNK, uma viagem pela “Internet das coisas” nas asas do NodeMCU ESP-12E

      Curtir

  19. 

    Show de bola o projeto, o legal que esta bem fácil de derivar outras ideias, o controle de temperatura vai ser muito útil no meu secador de frutas hehe.

    meus parabéns

    Uma duvida é possivel usar o blynk sem internet? preciso montar um sisteminha off-line e o blynk seria muito util para exibir informações.

    Curtido por 1 pessoa

Deixe um comentário