ArduFarmBot Parte 2: Construindo uma Estação de Controle IoT Remota
Componentes e Materiais
| Componente | Descrição | Qtd |
|---|---|---|
| Arduino Nano R3 | – | 1 |
| Espressif ESP8266 ESP-01 | Módulo Wi-Fi serial. | 1 |
| Sensor Temperatura/Umidade DHT22 | – | 1 |
| Módulo LDR KY-018 (luminosidade) | – | 1 |
| Hidrômetro (umidade do solo) | – | 1 |
| Relé Genérico (5V) | Para bomba e lâmpada. | 2 |
| LCD I2C 20x4 | – | 1 |
| Pushbutton 12mm (SparkFun) | Teclado de membrana 4 teclas. | 3 |
| LED Genérico | Indicadores. | 3 |
Aplicativos e Serviços Online
- ThingSpeak API – Armazenamento na nuvem e dashboard.
Sobre o Projeto

Esta é a continuação do ArduFarmBot: Controlando uma Horta de Tomate Caseira com Arduino e IoT.
Na Parte 1, criamos uma estação de controle local capturando temperatura, umidade relativa do ar, luminosidade e umidade do solo. O ArduFarmBot decidia automaticamente quantidade e momento de água e calor. Permitia também intervenção manual local na bomba e lâmpada.
Nesta Parte 2, implementamos abordagem IoT: a intervenção manual também será possível remotamente via Internet. O diagrama de blocos mostra a arquitetura.
Dados capturados são enviados ao serviço de nuvem ThingSpeak.com. Uma página web dedicada (Remote Control Page) monitora e exibe dados em tempo quase real e permite acionamento remoto de bomba e lâmpada.
Passo 1: Lista de Materiais (Bill of Material)
- Arduino Nano – (US$ 7,50)
- Sensor Temperatura/Umidade DHT22 ou DHT11 – (US$ 3,66)
- Sensor Luminosidade AD-018 (fotoresistor) ou equivalente – (US$ 0,71)
- 2x Sensor Umidade Solo – (US$ 1,99) (opcional, pode ser DIY)
- LCD I2C 20x4 – (US$ 13,99)
- LEDs (1x) – (US$ 0,20)
- ESP8266 ESP-01 Wi-Fi – (US$ 5,96)
- Buzzer Ativo KY-012 ou equivalente – (US$ 0,60)
- 2x Módulo Relé 5V – (US$ 11,60)
- Jumpers – (US$ 1,00)
- Resistores: 10kΩ, 2.2kΩ, 1kΩ, 220Ω
- Shield Arduino Nano "Funduino" – (US$ 7,28)
- Teclado de membrana 4 teclas – (US$ 6,65)
- Caixa plástica
Passo 2: Completando o Hardware

Partindo da Estação Local da Parte 1, o único hardware extra é o ESP8266. O diagrama de blocos mostra todas as conexões de pinos. Atenção ao nível de tensão: ESP8266 opera a 3.3V; o pino Rx não deve ligar direto no Tx do Nano (D3, 5V). Use divisor de tensão (resistores 2.2kΩ + 1kΩ) como conversor de nível.
Usamos ESP8266 nos pinos Nano 2 (Tx) e 3 (Rx) com biblioteca SoftwareSerial. Para liberar esses pinos, pode usar pinos seriais 0 e 1 do Nano (desconecte ao fazer upload).
Nota: Buzzer no pino D17 (A3). Útil para sinalizar erro de comunicação. Usei na fase de teste, retirei no final (código preparado).
Código para testar/configurar ESP8266: FC9DBPKIT682FY7.ino
Passo 3: Conexão do ESP8266

Para conectar à Internet, usamos ESP8266. Primeiro, reset no pino CH_PD:
void reset8266(void) {
pinMode(CH_PD, OUTPUT);
digitalWrite(CH_PD, LOW); delay(300);
digitalWrite(CH_PD, HIGH);
Serial.print("8266 reset OK");
lcd.clear(); lcd.println("8266 reset OK ");
}
Depois, conecte à rede Wi-Fi (altere USERNAME e PASSWORD no código) e inicie como Station Mode (CWMODE=1):
void connectWiFi(void) {
sendData("AT+RST\r\n", 2000, DEBUG);
sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG);
delay(3000);
sendData("AT+CWMODE=1\r\n", 1000, DEBUG);
sendData("AT+CIFSR\r\n", 1000, DEBUG); // mostra IP
lcd.clear(); lcd.print("8266 Connected");
Serial.println("8266 Connected");
}
Função genérica para enviar comandos AT:
String sendData(String command, const int timeout, boolean debug) {
String response = "";
esp8266.print(command);
long int time = millis();
while ((time + timeout) > millis()) {
while (esp8266.available()) {
char c = esp8266.read(); response += c;
}
}
if (debug) Serial.print(response);
return response;
}
Essas funções são chamadas no setup(). Se tudo certo, verá mensagens similares no Monitor Serial.
Passo 4: Armazenamento na Nuvem: ThingSpeak.com

Todos os dados vão para o ThingSpeak (gratuito). No loop(), após readSensors(), chamamos updateDataThingSpeak():
void updateDataThingSpeak(void) {
startThingSpeakCmd();
cmd = msg;
cmd += "&field1="; cmd += tempDHT; // campo 1: temp DHT
cmd += "&field2="; cmd += humDHT; // campo 2: umidade DHT
cmd += "&field3="; cmd += lumen; // campo 3: luminosidade
cmd += "&field4="; cmd += soilMoist; // campo 4: umidade solo
cmd += "&field5="; cmd += pumpStatus; // campo 5: status bomba
cmd += "&field6="; cmd += lampStatus; // campo 6: status lâmpada
cmd += "\r\n";
sendThingSpeakCmd();
}
Inicia comunicação com ThingSpeak:
void startThingSpeakCmd(void) {
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += IP; cmd += "\",80";
esp8266.println(cmd); delay(2000);
if (esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); return; }
Serial.println("Thinkspeak Comm Started"); cmd = "";
}
Envia dados montados:
String sendThingSpeakCmd(void) {
esp8266.print("AT+CIPSEND="); esp8266.println(cmd.length());
if (esp8266.find(">")) {
esp8266.print(cmd);
Serial.println(""); Serial.println(""); Serial.println(cmd);
delay(500);
String messageBody = "";
while (esp8266.available()) {
String line = esp8266.readStringUntil('\n');
if (line.length() == 1) {
messageBody = esp8266.readStringUntil('\n');
Serial.print("Message received: "); Serial.println(messageBody);
}
}
return messageBody;
} else {
esp8266.println("AT+CIPCLOSE");
Serial.println("ESP8266 CIPSEND ERROR: RESENDING");
error = 1; return "error";
}
}
Baseado no tutorial de Michalis Vasilakis: Arduino IOT: Temperature and Humidity (with ESP8266 WiFi).
Passo 5: Comando dos Atuadores via Web

Agora temos dados na nuvem. Para acionar bomba/lâmpada remotamente, criamos campos específicos no canal ThingSpeak:
- Campo 7: 1 = Liga Bomba, 0 = Desliga Bomba
- Campo 8: 1 = Liga Lâmpada, 0 = Desliga Lâmpada
Para escrever nesses campos via API:
api.thingspeak.com/update?key=YOUR_WRITE_KEY&field7=1
Teste no navegador: o campo 7 mudará para 1. Retorno: página branca com número sequencial.
Para ler o último comando (último dado do campo):
api.thingspeak.com/channels/CHANNEL_ID/fields/7/last
Função para ler campo 7:
int readLastDataField7() {
startThingSpeakCmd();
cmd = msgReadLastDataField7; cmd += "\r\n";
String messageDown = sendThingSpeakCmd();
Serial.print("Command received: "); Serial.println(messageDown[7]);
int command = messageDown[7] - 48; // ASCII para int
return command;
}
Função similar para campo 8. Depois, usamos os comandos recebidos:
void receiveCommands() {
field7Data = readLastDataField7();
if (field7Data == 1) { digitalWrite(PUMP_PIN, HIGH); pumpStatus = 1; showDataLCD(); }
if (field7Data == 0) { digitalWrite(PUMP_PIN, LOW); pumpStatus = 0; showDataLCD(); }
delay(500);
field8Data = readLastDataField8();
if (field8Data == 1) { digitalWrite(LAMP_PIN, HIGH); lampStatus = 1; showDataLCD(); }
if (field8Data == 0) { digitalWrite(LAMP_PIN, LOW); lampStatus = 0; showDataLCD(); }
delay(500);
}
Agora você pode ligar/desligar bomba e lâmpada via navegador. O Monitor Serial mostra comandos recebidos.
Coordenação entre Comando Local e Remoto
Atualize readLocalCmd() para sincronizar campos 7 e 8 com status local:
field7Data = pumpStatus;
field8Data = lampStatus;
Atualize aplyCmd() que efetivamente aciona atuadores:
void aplyCmd() {
if (field7Data == 1) digitalWrite(PUMP_PIN, HIGH);
if (field7Data == 0) digitalWrite(PUMP_PIN, LOW);
if (field8Data == 1) digitalWrite(LAMP_PIN, HIGH);
if (field8Data == 0) digitalWrite(LAMP_PIN, LOW);
}
Definição de prioridade (quem manda por último):
- Cada ciclo do loop: verifica botões locais.
- ~cada minuto: pooling no ThingSpeak para comandos remotos.
- ~cada 10 min: lê sensores, atualiza ThingSpeak e executa controle automático (este prevalece).
Dois timers:
long sampleTimingSeconds = 75; // leitura sensores
long poolingRemoteCmdSeconds = 20; // pooling comandos remotos
long startTiming = 0, elapsedTime = 0;
long startRemoteCmdTiming = 0, elapsedRemoteCmdTime = 0;
int reverseElapsedTimeSeconds = 0;
loop() reescrito:
void loop() {
elapsedRemoteCmdTime = millis() - startRemoteCmdTiming;
elapsedTime = millis() - startTiming;
reverseElapsedTimeSeconds = round(sampleTimingSeconds - elapsedTime/1000);
readLocalCmd(); // botões locais
showDataLCD();
if (elapsedRemoteCmdTime > (poolingRemoteCmdSeconds * 1000)) {
receiveCommands(); updateDataThingSpeak();
startRemoteCmdTiming = millis();
}
if (elapsedTime > (sampleTimingSeconds * 1000)) {
readSensors(); autoControlPlantation(); updateDataThingSpeak();
startTiming = millis();
}
}
Passo 6: Implementando Página Web Dedicada

O ArduFarmBot já é controlável via web, mas a solução via navegador/ThingSpeak não é "elegante". O ideal é uma página web completa exibindo dados e botões para atuadores.
Usei Byethost (hospedagem gratuita, simples). Apliquei conhecimentos da especialização Coursera/Univ. Michigan: Learn to Design and Create Websites (HTML5, CSS3, JavaScript).
Não entrarei em detalhes de desenvolvimento web (não é foco), mas incluo códigos-fonte HTML, CSS, JS. Dúvidas no quadro de comentários.
A página NÃO fala diretamente com o ArduFarmBot local. Ela interage com o canal ThingSpeak:
- Lê dados sensores nos campos 1, 2, 3, 4
- Lê status atuadores nos campos 5, 6
- Escreve comandos nos campos 7, 8
- Lê clima local via Yahoo Weather (extra, opcional)
O item 4 permite ações remotas independentes do local. Sugestão: armazenar dados climáticos em outro canal ThingSpeak e baixar para Arduino mostrar no LCD local (já fiz em outro projeto).
Passo 7: Volta ao Cérebro – Abordagem Matriz Sensor-Atuador

Na Parte 1, definimos regras simples. Para situações complexas, usamos Matriz Sensor-Atuador. No Excel (anexo) há duas abas: tabela com filtro e versão para selecionar múltiplas condições e ver resultado nos atuadores.
Traduzimos para array 18x10 no código:
// +---SOIL----+-LIGHT-+---TEMP---+---ACTUAT----+
// SL SM SH LL LH TL TM TH Pump Lamp
boolean SDf[18][10] = {
{1,0,0, 0,1, 0,0,1, 1,0},
{1,0,0, 0,1, 0,1,0, 1,0},
{1,0,0, 0,1, 1,0,0, 1,1},
{1,0,0, 1,0, 0,0,1, 1,0},
{1,0,0, 1,0, 0,1,0, 1,0},
{1,0,0, 1,0, 1,0,0, 0,1},
{0,1,0, 0,1, 0,0,1, 0,0},
{0,1,0, 0,1, 0,1,0, 0,0},
{0,1,0, 0,1, 1,0,0, 0,1},
{0,1,0, 1,0, 0,0,1, 0,0},
{0,1,0, 1,0, 0,1,0, 0,1},
{0,1,0, 1,0, 1,0,0, 0,1},
{0,0,1, 0,1, 0,0,1, 0,0},
{0,0,1, 0,1, 0,1,0, 0,0},
{0,0,1, 0,1, 1,0,0, 0,1},
{0,0,1, 1,0, 0,0,1, 0,0},
{0,0,1, 1,0, 0,1,0, 0,1},
{0,0,1, 1,0, 1,0,0, 0,1}
};
Função defSensorStatus() testa cada linha: se as 8 primeiras colunas forem TRUE, executa as 2 últimas (bomba, lâmpada). Exemplo:
if (1 && 0 && 0 && 0 && 1 && 0 && 0 && 1) { pumpStatus=1; lampStatus=0; }
else if (1 && 0 && 0 && 0 && 1 && 0 && 1 && 0) { pumpStatus=1; lampStatus=0; }
// ...
Array auxiliar boolean snsSts[8]={0,0,0,0,0,0,0,0}; (SL, SM, SH, LL, LH, TL, TM, TH) também usado para LOG.
Baixe planilha Excel da matriz.
Passo 8: Otimização de Código

Durante desenvolvimento, ajustes na especificação original:
- Display: LCD OFF por default. Botão "Sensors Read" atua como toggle ON/OFF. Liga/desliga atualiza leituras para display, mas não afeta funções regulares.
- Setup Inicial: Ao ligar/resetar, LCD mostra "Initial Set-up". Pressione "Sensors" para iniciar. Mostra: Temp Fria (ex 12°C), Solo Seco (30%), Solo Úmido (60%), Escuro (40%), Tempo Bomba ON (10s), Tempo Scan (600s), Versão SW (4.1).
- Log de Auditoria: A cada ciclo de leitura, executa
storeDataLogEEPROM()gravando bits desnsSts[]+ status bomba/lâmpada na EEPROM.
void storeDataLogEEPROM(void) {
for (int i=0; i<8; i++) { logData = logData + (snsSts[i]) << 1; }
EEPROM.write(memoAddr, logData); memoAddr++; logData = 0;
logData = logData + pumpStatus; logData = logData << 1;
logData = logData + lampStatus;
EEPROM.write(memoAddr, logData);
EEPROM.write(0, memoAddr+1); logData = 0;
if ((memoAddr+1) == 1023) memoAddr=1; else memoAddr++;
}
Código dividido em arquivos para clareza. Novos arquivos nesta parte:
- communication.ino (funções ThingSpeak e ESP8266)
- stationCredentials.h (Channel ID e Write Keys do ThingSpeak)
Dados constantes movidos para flash (memória de programa) com PROGMEM para economizar SRAM. Ex: const PROGMEM byte DHTPIN = 5; (inclua avr/pgmspace.h). Comente/remova Serial.print() de debug para economizar SRAM.
Arquivos completos do ArduFarmBot (troque dados dummy em credentials.h e credenciais Wi-Fi em communication.ino):
- FTUT5VIIT67U8ME.ino
- FWMIPSSIT67U8MG.ino
- FJPGZNKIT67U8MK.ino
- FQH3X9VIT67U8NA.ino
- F15MY4YIT67U8NB.ino
- FVU64X1IT67U8NC.h
- FZ057E3IT67U8P5.h
Passo 9: A Fazenda Caseira MJRovai
Fotos sequenciais do ArduFarmBot controlando minha primeira plantação de tomate.











Sequência da 2ª plantação: da semente até seleção das 6 melhores mudas (~45 dias) e transplante.


Passo 10: Conclusão

É isso por enquanto! Espero que ajude outros a explorar eletrônica, IoT e robótica.
Em breve publicaremos a terceira e última parte: uma ótima receita de molho de tomate orgânico para massa.
Na foto acima, primeiros sinais de vida na plantação do Mauricio! Antes de ir, confira o ArduFarmBot, the Book! onde todo o projeto está em formato mais amigável:
ArduFarmBot, the Book!

Disponível na Amazon.com. O livro usa o controlador eletrônico ArduFarmBot como base para ensinar HW e SW com:
- Displays LCD e OLED
- LEDs e botões
- Ativação de bombas e lâmpadas via relés
- Sensores: DHT22 (temp/umidade ar), DS18B20 (temp solo), YL69 (umidade solo), LDR (luminosidade)

Todas as etapas documentadas: textos explicativos, diagramas de blocos, fotos alta resolução, esquemáticos Fritzing, códigos completos no GitHub e vídeos YouTube.

Duas versões do ArduFarmBot desenvolvidas em detalhe. Da captura de dados do jardim (temp ar/solo, umidade, luminosidade), o ArduFarmBot controla quando a cultura recebe calor e água – automaticamente, local e remotamente via internet. Livro em 3 partes:
- Parte 1: Arduino Nano como base para versão local (manual + automático).
- Parte 2: Automação e operação remota com webpage. ESP8266-01 para Wi-Fi, dados no ThingSpeak.com.
- Parte 3: Nova versão com NodeMCU ESP8266-12E (substitui Nano + ESP-01). Explora plataforma Blynk.




Baixe o livro, avalie e use o quadro de mensagens para comentários, sugestões ou críticas!
Mais projetos no blog: MJRoBot.org
Saudações do sul do mundo!
Até o próximo projeto!
Obrigado, Marcelo
Código (Snippets)
Os snippets principais já estão incorporados nos passos acima. Arquivos completos disponíveis nos links do Passo 8.
Repositório GitHub: https://github.com/Mjrovai/ArduFarmBot
Esquemático

Processo de manufatura
- Tendências Emergentes em Implementação de IoT: Insights e Estratégias
- Estação de Mistura de Bebidas 6-Shooter Controlada por Arduino – Construa seu Próprio Automatizador de Coquetéis
- Sistema Multi-Posição de Sensores de Temperatura para Integração em Casa Inteligente
- MotionSense: Detecção Inteligente de Intrusão com Arduino e ESP8266
- Prevenção de Incêndio em Impressoras 3D: Sistema de Segurança com Sensor Inteligente
- Crie um Medidor IoT Web com Arduino, Yaler e IFTTT
- Levitação Magnética Repulsiva com Arduino: Circuito Simples e Guia DIY
- Robô Garra Controlado Remotamente para Manipulação de Precisão
- Registrador de Dados de Balão Meteorológico Arduino de Alto Desempenho
- CoroFence Detector Térmico: Sensor PIR Avançado & Integração IoT