ArduFarmBot Deel 2: Een Extern IoT-besturingsstation Bouwen
Onderdelen en benodigdheden
| Arduino Nano R3 | Aantal: 1 |
| Espressif ESP8266 ESP-01 | Aantal: 1 |
| DHT22 Temperatuur/vochtigheidssensor | Aantal: 1 |
| KY-018 Fotoweerstand module | Aantal: 1 |
| Bodemvochtigheidssensor (hydrometer) | Aantal: 1 |
| Relais (algemeen) | Aantal: 2 |
| LCD 4×20 (I2C) | Aantal: 1 |
| SparkFun Drukknop 12mm | Aantal: 3 |
| LED (algemeen) | Aantal: 3 |
Apps en online diensten
| ThingSpeak API |
Over dit project



Deze tutorial is een vervolg op ArduFarmBot: Een Tomaten-Hometuin Besturen met Arduino en IoT (Deel 1).
In Deel 1 maakten we een lokaal besturingsstation dat gegevens verzamelde van een tomatenteelt: temperatuur, relatieve luchtvochtigheid, lichtintensiteit en bodemvochtigheid. Op basis hiervan besloot de ArduFarmBot automatisch hoeveel en wanneer water en warmte nodig was. Handmatige bediening van de waterpomp en de lamp was ook mogelijk.
In Deel 2 implementeren we een IoT-aanpak: de "handmatige interventie" wordt ook op afstand via internet mogelijk. Het blokdiagram toont de architectuur.
Gemeten data wordt naar een cloud-opslagdienst gestuurd (in ons geval ThingSpeak.com). Een speciale website, de Remote Control Page, monitoren en toont deze data in near real-time en stelt remote activering van pomp en lamp in.
Stap 1: Stuklijst (Bill of Materials)
- Arduino Nano – ($7,50)
- DHT22 of DHT11 Temperatuur/vochtigheidssensor – ($3,66)
- Lichtsensor – AD-018 Fotoweerstand module of equivalent – ($0,71)
- 2× Bodemvochtigheidssensor – ($1,99) (Optioneel, zelfbouw mogelijk)
- LCD I2C 20×4 – ($13,99)
- LED (1×) – ($0,20)
- ESP8266 ESP-01 WiFi-module – ($5,96)
- Actieve buzzer – KY-012 of equivalent – ($0,60)
- 2× 5V Relaismodule – ($11,60)
- Jumperdrade – ($1,00)
- Weerstanden: 10kΩ, 2,2kΩ, 1kΩ, 220Ω
- Arduino Nano Shield ("Funduino") – ($7,28)
- Membraantoetsenbord (4 toetsen) – ($6,65)
- Plastic behuizing
Stap 2: Hardware completeren







Vanaf het lokale station uit Deel 1 is de enige extra hardware de ESP8266. Het blokdiagram toont alle Arduino- en component-pinverbindingen.
Let op spanningsniveaus! De ESP8266 werkt op 3,3V. De Rx-pin mag niet direct aan de Nano Tx-pin (D3) worden aangesloten. Een spanningsdeler (level shifter) is vereist. In de schema's wordt gedetailleerd getoond hoe de ESP8266 te verbinden.
Meer over ESP8266 in mijn tutorials:
- The ESP8266 Part 3 - Triggering Arduino LEDs Remotely
- The ESP8266 Part 1 - Serial WIFI Module for Arduino
- The ESP8266 Part 2 - Arduino Web Server
We gebruiken ESP8266 op Nano pin 2 (Tx) en pin 3 (Rx) met de SoftwareSerial-bibliotheek. Alternatief: hardware seriële pinnen 0 en 1 (moeten los bij uploaden).
Opmerking: De buzzer kan op pin D17 (A3) aangesloten worden voor foutgeluid. Ik gebruikte hem tijdens testen, niet in het finale project (hardware, maar code is ervoor klaar).
Testcode voor ESP8266 setup: FC9DBPKIT682FY7.ino
Stap 3: De ESP8266-verbinding

Om de ArduFarmBot met internet te verbinden gebruiken we de ESP8266: goedkoop, eenvoudig te programmeren IoT-module.
Eerst een reset op de CH-PD-pin:
/***************************************************
* Reset functie voor communicatie
***************************************************/
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 ");
}
Vervolgens verbinden met je lokale netwerk (vervang USERNAME/PASSWORD in code) en instellen als STA (Station Mode, CWMODE=1):
/***************************************************
* WiFi verbinden
***************************************************/
void connectWiFi(void) {
sendData("AT+RST\r\n", 2000, DEBUG); // Reset
sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG); // Netwerk
delay(3000);
sendData("AT+CWMODE=1\r\n", 1000, DEBUG); // Station mode
sendData("AT+CIFSR\r\n", 1000, DEBUG); // IP-adres tonen
lcd.clear(); lcd.print("8266 Connected");
Serial.println("8266 Connected");
}
Functie sendData() voor AT-commando's:
/***************************************************
* AT-commando's sturen naar module
***************************************************/
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;
}
Deze functies worden in setup() aangeroepen. Bij succes zie je vergelijkbare berichten in de Seriële Monitor.
Stap 4: Cloud-opslag: ThingSpeak.com

Alle data wordt geüpload naar de gratis service van ThingSpeak.com.
In loop() (na readSensors()) roepen we updateDataThingSpeak() aan:
/***************************************************
* Data naar ThingSpeak sturen
***************************************************/
void updateDataThingSpeak(void) {
startThingSpeakCmd();
cmd = msg;
cmd += "&field1="; cmd += tempDHT; // Veld 1: DHT temperatuur
cmd += "&field2="; cmd += humDHT; // Veld 2: DHT vochtigheid
cmd += "&field3="; cmd += lumen; // Veld 3: LDR licht
cmd += "&field4="; cmd += soilMoist; // Veld 4: Bodemvochtigheid
cmd += "&field5="; cmd += pumpStatus; // Veld 5: POMP status
cmd += "&field6="; cmd += lampStatus; // Veld 6: LAMP status
cmd += "\r\n";
sendThingSpeakCmd();
}
Communicatie starten met startThingSpeakCmd():
/***************************************************
* Communicatie met ThingSpeak starten
***************************************************/
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 = "";
}
Data uploaden met sendThingSpeakCmd():
/***************************************************
* ThingSpeak kanaal updaten
***************************************************/
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";
}
}
Bovenstaande functies gebaseerd op tutorial van Michalis Vasilakis: Arduino IOT: Temperature and Humidity (with ESP8266 WiFi).
Stap 5: Actuatoren besturen vanaf het web


Data uploaden is goed voor monitoring, maar we willen ook op afstand pomp/lamp aansturen. We maken specifieke velden op ThingSpeak voor commando's:
- Veld 7: 1 = POMP AAN, 0 = POMP UIT
- Veld 8: 1 = LAMP AAN, 0 = LAMP UIT
Om een veld in te stellen via browser (met jouw Write Key):
api.thingspeak.com/update?key=JOUW_WRITE_KEY&field7=1
Om de laatste waarde van een veld op te halen:
api.thingspeak.com/channels/CHANNEL_ID/fields/7/last
Functie om veld 7 te lezen:
/***************************************************
* Laatste data uit veld 7 lezen (ThingSpeak)
***************************************************/
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 naar int
return command;
}
Vergelijkbare functie voor veld 8. Vervolgens commando's uitvoeren op actuatoren:
/***************************************************
* Commando's van ThingSpeak ontvangen en uitvoeren
***************************************************/
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);
}
Nu kun je via browser-regel pomp en lamp remote aan/uit zetten. De ontvangen commando's verschijnen in de Seriële Monitor.
Coördinatie lokaal vs remote: We passen readLocalCmd() aan om ook ThingSpeak velden 7/8 te updaten met pomp/lamp-status (in de respectievelijke IF-statements). Zie complete code aan het eind.
field7Data = pumpStatus;
field8Data = lampStatus;
Nu zijn velden 7/8 gesynchroniseerd met zowel web-commando's als lokale knopacties. Update aplyCmd() die de actuatoren aanstuurt:
/***************************************************
* Commando's ontvangen en op actuatoren toepassen
***************************************************/
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);
}
Prioriteitsregels: Elke luscyclus checken we lokale knoppen. Elke ~20 seconden polen we ThingSpeak voor remote commando's. Elke ~75 seconden lezen we sensoren, updaten ThingSpeak en voeren automatische acties uit (deze hebben "het laatste woord"). Je kunt dit aanpassen naar wens.
Twee timers:
long sampleTimingSeconds = 75; // Sensor leesinterval (seconden)
long poolingRemoteCmdSeconds = 20; // Remote command polling interval (seconden)
Herschreven loop():
void loop() {
elapsedRemoteCmdTime = millis() - startRemoteCmdTiming;
elapsedTime = millis() - startTiming;
reverseElapsedTimeSeconds = round(sampleTimingSeconds - elapsedTime/1000);
readLocalCmd(); // Lokale knoppen
showDataLCD(); // Display updaten
if (elapsedRemoteCmdTime > (poolingRemoteCmdSeconds * 1000)) {
receiveCommands(); // Remote commando's ophalen
updateDataThingSpeak(); // Status terugsturen
startRemoteCmdTiming = millis();
}
if (elapsedTime > (sampleTimingSeconds * 1000)) {
readSensors(); // Sensoren lezen
autoControlPlantation(); // Automatische besturing
updateDataThingSpeak(); // Data uploaden
startTiming = millis();
}
}
Stap 6: Toegewezen Webpagina Implementeren

De browser-oplossing is functioneel maar niet elegant. Een speciale webpage is beter: data tonen + knoppen voor actuatoren.
Ik gebruikte Byethost (gratis webhosting) en kennis uit de Coursera/University of Michigan specialisatie Learn to Design and Create Websites (HTML5, CSS3, JavaScript).
De pagina communiceert niet direct met de ArduFarmBot, maar met ThingSpeak:
- Sensordata lezen uit velden 1, 2, 3, 4
- Actuatorstatus lezen uit velden 5, 6
- Commando's schrijven naar velden 7, 8
- Lokaal weerdata ophalen via Yahoo-services (optioneel)
Broncode (HTML, CSS, JS) is bijgevoegd: FQOK9ENIT653YX5.zip
Stap 7: Terug naar de "hersenen" – Sensor-Actuator Matrix



In Deel 1 definieerden we simpele regels. Voor complexere situaties gebruiken we een Sensor-Actuator Matrix. In Excel (bijgevoegd) zijn alle sensorcondities en actuatoruitgangen in een matrix vastgelegd.
Vertaald naar code: een array van 18 regels × 10 kolommen:
// +---BODEM---+--LICHT--+--TEMP---+--ACTUAT--+
// SL SM SH LL LH TL TM TH Pomp 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}
};
Functie defSensorStatus() test per regel of de eerste 8 kolommen (sensorcondities) TRUE zijn. Zo ja, voer de actuatoracties uit (laatste 2 kolommen).
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; }
// enzovoort...
Interne array snsSts[8] houdt sensorstatussen bij (ook voor logging).
Excel-bestand: F2HWXBYITA8WIN1.xlsx
Stap 8: Code-optimalisatie


Display: LCD standaard UIT. Knop "Sensors Read" werkt als toggle om display aan/uit te zetten (update sensoren voor display, niet voor reguliere functies).
Initiële setup: Bij opstart/reset toont LCD "Initial Set-up". Druk "Sensors" om te starten. Instellingen: Koude temp (12°C), Droge bodem (30%), Natte bodem (60%), Donker licht (40%), Pomp AAN-tijd (10s), Scan-tijd (600s), SW-versie (4.1).
Log registratie: Elke meetcyclus voert storeDataLogEEPROM() uit. Er wordt bit-gepakt opgeslagen: sensorstatussen (8 bits) + pomp-status + lamp-status in EEPROM.
/***************************************************
* Logdata opslaan in Arduino 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++;
}
Code opgesplitst in meerdere bestanden voor overzichtelijkheid. Nieuwe bestanden in Deel 2:
- communication.ino (ThingSpeak & ESP8266 functies)
- stationCredentials.h (ThingSpeak Channel ID & Write Keys)
Geheugenoptimalisatie: Constante data in flash (programma) geheugen via PROGMEM ipv SRAM. Bijv. const PROGMEM byte DHTPIN = 5; + #include <avr/pgmspace.h>. Debug Serial.print() regels uitcommentariëren bespaart ook SRAM.
Complete codebestanden (vervang dummy-gegevens in credentials.h met jouw Channel ID/Write Key, en in communication.ino jouw WiFi-gegevens):
- FTUT5VIIT67U8ME.ino
- FWMIPSSIT67U8MG.ino
- FJPGZNKIT67U8MK.ino
- FQH3X9VIT67U8NA.ino
- F15MY4YIT67U8NB.ino
- FVU64X1IT67U8NC.h
- FZ057E3IT67U8P5.h
Stap 9: De MJRovai Hometuin
Onderstaande foto's tonen de evolutie van mijn eerste tomatenteelt onder controle van ArduFarmBot.











Tweede teelt: van zaailing tot selectie beste 6 planten (~45 dagen) en verplanting.


Stap 10: Conclusie


Dat is het voor nu! Ik hoop dat dit project anderen helpt in de spannende wereld van electronica, IoT en robotica!
Binnenkort waarschijnlijk Deel 3: een recept voor biologische tomatensaus pasta. Op de foto hierboven zie je de eerste levenstekens van Mauricios teelt!
Bekijk ook het nieuwe ArduFarmBot, het boek! waar het hele project in een vriendelijk formaat is gebundeld:
ArduFarmBot, het Boek!

Ook verkrijgbaar op Amazon.com. Het boek gebruikt de ArduFarmBot-controller als basis om te leren werken met:
- LCD en OLED displays
- LEDs en knoppen
- Activering van pompen en lampen via relais
- Sensoren: DHT22 (lucht temp/vocht), DS18B20 (bodemtemp), YL69 (bodemvocht), LDR (licht)

Alle fas gedocumenteerd met uitleg, blokdiagrammen, kleurenfoto's, Fritzing-schema's, complete code op GitHub en YouTube-video's.

Twee versies van ArduFarmBot uitgewerkt. Deel 1: Arduino Nano als lokaal station (handmatig/automatisch). Deel 2: Remote operatie via webpage, ESP8266-01 voor WiFi, ThingSpeak.com. Deel 3: NodeMCU ESP8266-12E vervangt zowel Nano als ESP-01, plus Blynk-platform.




Download het boek, geef een review en gebruik het berichtenbord voor commentaar, suggesties of kritiek!
Meer projecten op mijn blog: MJRoBot.org
Groetjes uit het zuiden van de wereld!
Tot de volgende keer!
Dank je wel
Marcelo
Code
Alle code-snippets en volledige bestanden zijn in de bovenstaande stappen verwerkt. De complete projectcode is te vinden op GitHub:
https://github.com/Mjrovai/ArduFarmBot
Schema
Productieproces
- Arduino-gestuurde 6-Shooter Drank Mixstation – Bouw je eigen Cocktail Automaat
- Meerpositie-temperatuursensorsysteem voor slimme thuisintegratie
- MotionSense: Slimme inbraakdetectie met Arduino en ESP8266
- 3D-Printer Brandpreventie: Slimme Sensor Veiligheidssysteem
- Web-IoT Meter Bouwen met Arduino, Yaler en IFTTT
- Arduino-gebaseerde Afstotende Magnetische Levitatie: Eenvoudige Schakeling & DIY Handleiding
- Geavanceerde Remote-gecontrolleerde Gripper Robot voor Precisiehantering
- High-Performance Arduino Weerballon Datalogger
- Bouw een $10 Draagbare Arduino Weerstation (AWS) – Eenvoudige DIY met Nano, DHT22, BMP180 & LCD
- CoroFence Thermische Detector: Geavanceerde PIR-sensor & IoT-integratie
- Opkomende Trends in IoT-implementatie: Inzichten & Strategieën