Intelligentes Kräuterbox-Ökosystem: Alexa-gesteuertes Indoor-Garten-Set
Komponenten und Materialien
| Komponente | Menge |
|---|---|
| Amazon Alexa Echo Dot | 1 |
| Arduino UNO | 1 |
| Espressif ESP8266 ESP-01 (WiFi-Modul) | 1 |
| Arduino Proto Shield | 1 |
| Arduino 4-Kanal-Relais-Shield | 1 |
| Aqua-Pumpe (12V) | 2 |
| Pflanzenwachstumslampe (230V) | 1 |
| 220V DC Netzteil | 1 |
| 12V DC Netzteil | 1 |
| USB-Netzteil + Kabel | 1 |
| Luftschlauch | 1 |
| Jumper-Wires (Sortiment) | 1 |
Apps & Online-Dienste
- Arduino IDE
- Amazon Alexa Skills Kit
- Amazon Web Services AWS Lambda
- PHP Webserver (für API/Website)
Über dieses Projekt
Da meine Pflanzen immer unter Über- oder Unterversorgung litten und ich gerne viele Kräuter beim Kochen verwende, baute ich ein individuelles Bewässerungssystem. Die Kräuterbox soll konfigurierbar sein, automatisch oder manuell arbeiten. Eine Web-Schnittstelle ermöglicht Einrichtung und Feuchtigkeitsanzeige im Diagramm. Der letzte Schritt war die Sprachsteuerung via Amazon Alexa: Feuchtigkeit abfragen, Wachstumslampe ein/ausschalten, Bewässerung starten (wenn Automatik deaktiviert).
Ich begann mit der Technik, kaufte einen Arduino, lernte durch Tutorials Software und Steuerung. Dann bestellte ich WiFi-Controller (ESP-01), Feuchtesensoren, Pumpen, Pflanzenlampe und Zusatzhardware (Relais-Shield zur Trennung der Stromkreise für Lampe/Pumpen vom Arduino, Kabel, Buchenholz für den Rahmen). Der Arduino-Code wird hier bereitgestellt; Website/API-Code nicht (außer bei hoher Nachfrage).
Schritt 1: Feuchtesensor
Erster Meilenstein: Luftfeuchtigkeit mit Arduino auslesen. Der Sensor YL-69 lässt sich einfach anschließen: VCC an GPIO-Pin (z. B. Pin 6), GND an GND, A0 an analogen Pin (z. B. A1).
byte vccPin = 6;
byte dataPin = A1;
void setup() {
pinMode(vccPin, OUTPUT);
digitalWrite(vccPin, LOW);
Serial.begin(9600);
while (!Serial);
}
int readHumidity() {
digitalWrite(vccPin, HIGH);
delay(500); // Vorlaufzeit testen
int value = analogRead(dataPin);
digitalWrite(vccPin, LOW);
return 1023 - value; // Umkehren: höher = feuchter
}
void loop() {
Serial.print("Feuchtigkeitslevel (0-1023): ");
Serial.println(readHumidity());
delay(10000);
}
Schritt 2: Relais für Pumpen & Lampe
Relais-Shield (4 Relais) trennt Stromkreise: Arduino (5V), Pumpen (12V), Lampe (230V). Shield an 5V & GND des Arduino anschließen. Jedes Relais braucht einen GPIO-Pin zum Schalten. Jumper VCC JC zu VCC auf Shield oder separate Batterie (besser, aber hier nicht verbaut).
Wichtig: Mein Shield schaltet ein bei LOW am Pin. Sobald Pin als OUTPUT definiert, wird es aktiv. Im Code immer auf INPUT + LOW setzen, um Relais auszuschalten. Arduino-Pins sind standardmäßig INPUT/LOW.
byte pump1 = 11;
byte pump2 = 10;
void setup() {
Serial.begin(9600);
while (!Serial);
pinMode(pump1, OUTPUT);
digitalWrite(pump2, LOW);
}
void loop() {
digitalWrite(pump1, HIGH); // Pumpe 1 aus
pinMode(pump2, INPUT); // Pumpe 2 aus
delay(1000);
digitalWrite(pump1, LOW); // Pumpe 1 an
pinMode(pump2, OUTPUT); // Pumpe 2 an
delay(1000);
}
Schritt 3: WiFi mit ESP-01
ESP8266 ESP-01 an Arduino für WLAN war der schwierigste Teil. Anschluss: VCC=3,3V, GND=GND, CH_PD=3,3V, TX=Pin 2, RX=Pin 3. Für Produktivbetrieb: Pegelwandler 5V→3,3V für Pins 2/3 nutzen (hier funktionierte es auch ohne).
Beide Mikrocontroller kommunizieren seriell. Arduino UNO nutzt Standard-Pins 0/1 für RX/TX – diese dienen aber auch USB-Debugging. Daher SoftwareSerial.h nutzen und eigene Pins definieren.
#include <SoftwareSerial.h>
SoftwareSerial espSerial(3, 2); // RX, TX
void setup() {
Serial.begin(9600);
espSerial.begin(115200); // Nach AT+UART_DEF=9600,8,1,0,0 auf 9600 umstellen
while (!Serial);
}
void loop() {
if (espSerial.available()) Serial.write(espSerial.read());
if (Serial.available()) espSerial.write(Serial.read());
}
Damit AT-Befehle in Serial Monitor eingeben und Antworten sehen. Baudrate von 115200 auf 9600 reduziert für Stabilität.
Nützliche Libraries: WiFiEsp (speicherintensiv), MemoryFree (Speicherprüfung).
HTTP-Kommunikation mit ESP-01
Skript nutzt HTTP 1.0 (bei 1.1 sind Bytes Teil der Response). Wichtig: Korrekte Zeilenumbrüche nach AT+CIPSEND, sonst Byte-Send-Fehler.
#include <SoftwareSerial.h>
SoftwareSerial espSerial(3, 2);
const char* ssid = "<DEIN-WIFI-SSID>";
const char* pass = "<DEIN-WIFI-PASSWORT>";
void setup() {
Serial.begin(9600);
espSerial.begin(9600);
while(!Serial);
while(!connectToWiFi());
if (httpRequest("my.server.com", "/site/subsite/index.php")) {
while (espSerial.available()) Serial.write(espSerial.read());
}
}
void loop() {
if (espSerial.available()) Serial.write(espSerial.read());
if (Serial.available()) espSerial.write(Serial.read());
}
bool connectToWiFi() {
delay(2000);
espSerial.setTimeout(3000);
while (espSerial.available()) Serial.write(espSerial.read());
Serial.println(F("[ESP] Verbinde mit WiFi"));
espSerial.println(F("AT+CIPSTATUS=2"));
if (!espSerial.find("OK")) {
espSerial.setTimeout(10000);
Serial.println(F("[ESP] Modul Reset"));
espSerial.println(F("AT+RST"));
if (!espSerial.find("ready")) { Serial.println(F("[ESP] Reset fehlgeschlagen")); return false; }
Serial.println(F("[ESP] Setze CWMode"));
espSerial.println(F("AT+CWMODE=1"));
if (!espSerial.find("OK")) { Serial.println(F("[ESP] Modus fehlgeschlagen")); return false; }
Serial.println(F("[ESP] Verbinde mit Router"));
espSerial.print(F("AT+CWJAP=\""));
espSerial.print(ssid);
espSerial.print(F("\",\""));
espSerial.print(pass);
espSerial.println("\"");
if (!espSerial.find("OK")) { Serial.println(F("[ESP] WiFi-Verbindung fehlgeschlagen")); return false; }
}
espSerial.setTimeout(3000);
Serial.println(F("[ESP] WiFi verbunden"));
return true;
}
bool httpRequest(String server, String site) {
String cmd = "";
cmd += "GET " + site + " HTTP/1.0\r\n";
cmd += "Host: " + server + "\r\n";
cmd += "Connection: close";
int cmdLength = cmd.length() + 4;
espSerial.print(F("AT+CIPSTART=\"TCP\",\""));
espSerial.print(server);
espSerial.println(F("\",80"));
if (!espSerial.find("OK")) { Serial.println(F("[ESP] TCP-Verbindungsfehler")); return false; }
espSerial.print(F("AT+CIPSEND="));
espSerial.println(cmdLength);
if (!espSerial.find(">")) { Serial.println(F("[ESP] Sendezustand-Fehler")); return false; }
espSerial.print(F("GET "));
espSerial.print(site);
espSerial.print(F(" HTTP/1.0\r\n"));
espSerial.print(F("Host: "));
espSerial.print(server);
espSerial.print(F("\r\n"));
espSerial.print(F("Connection: close\r\n"));
espSerial.println();
if (!espSerial.find(":")) { Serial.println(F("Bytes nicht gesendet")); espSerial.print(F("AT+CIPCLOSE")); return false; }
char status[32] = {0};
espSerial.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) { Serial.print(F("[ESP] Unerwartete Antwort: ")); Serial.println(status); return false; }
if (!espSerial.find("\r\n\r\n")) { Serial.println(F("[ESP] Ungültige Antwort")); return false; }
return true;
}
Schritt 4: Der Holzrahmen
Rahmen aus Buche (wasserfest verleimt) für 3 Supermarktkräutertöpfe + Elektronik (4 Feuchtesensoren, 2 Pumpen, Arduino+Shields, USB-Buchse, Kabel). Kreise per Stichsäge (selbstgebauter Tisch) ausgeschnitten, Töpfe mit Heißkleber in Kreisen fixiert. Seiten mit D3-Holzleim (wasserfest) verleimt. Keine Schrauben/Nägel außer Bodenplatte.
Alle Kabel, Schläuche, Sensoren innen verlegt, Sensoren und Wassertank-Schläuche nach außen geführt. Untersetzer als Spritzschutz für Elektronik eingebaut.
Schritt 5: Website & API
Basiert auf jQuery, Bootstrap, X-editable (Inline-AJAX-Formulare), Chart.js (Feuchtigkeitsdiagramm), in PHP. Einstellungen für Arduino definierbar (Sensor-Pins, Prüfintervall, Pumpen pro Pflanze, Pumpen-VCC-Pins, Licht-VCC-Pin). Aktuelle Feuchtigkeit + Diagramm anzeigbar.
Konfiguration per JSON für Arduino. Box prüft regelmäßig auf neue Settings. JSON-Parsing mit ArduinoJson, Polling-Intervall mit StensTimer.
Schritt 6: Alexa-Integration
Website stellt API für Alexa bereit: Empfängt Alexa-Request-JSON, übersetzt in Arduino-JSON (z. B. Lampe an, Pflanze 1 bewässern). Arduino pollt Aktionen und führt aus.
Da Sprachbefehle komplexer als An/Aus sind, wurde ein Alexa Skill (kein Smart Home) implementiert. AWS Lambda leitet Request-JSON an eigene API weiter, die Intents parst.
var https = require('https');
exports.handler = (event, context, callback) => {
var postData = JSON.stringify(event);
var options = {
host: '<MEIN-SERVER>',
path: '<MEINE-API-URL>',
port: 443,
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length }
};
var postRequest = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('Response: ' + chunk);
callback(null, JSON.parse(chunk));
});
});
postRequest.write(postData);
postRequest.end();
};
Genutzte Intents (Auszug):
- ReadHumidityIntent: „Wie geht es meinen Pflanzen?“ / „Wie geht es meinem {pflanzenName}?“
- IrrigatePlantIntent: „Bewässere meine Pflanzen“ / „Bewässere mein {pflanzenName} für {dauerSekunden} Sekunden“
- SwitchIntent: „Schalte die Lampe {zustand}“
- ReadIrrigateIntent: „Welche Pflanzen brauchen Wasser?“
- ReadLastIrrigationIntent: „Wann wurde mein {pflanzenName} zuletzt bewässert?“
Lokale Unterstützung für Deutsch & Englisch.
Das Ergebnis
Holzbox für Supermarktkräuter, Wasserschläuche & Feuchtesensoren in Erde, Schläuche in externem Wassertank. Mit Alexa:
- „Alexa, frage Kräuterbox wie meine Pflanzen sind“ → „Pflanze 1 ok, Pflanze 2 trocken…“
- „Alexa, sag Kräuterbox, bewässere mein Basilikum für 5 Sekunden“ → „Bewässere Basilikum für 5 Sekunden“
- „Alexa, frage Kräuterbox welche Pflanzen Bewässerung brauchen“ → „Pflanze 1 trocken, Pflanze 3 trocken…“
- „Alexa, frage Kräuterbox wann letzte Bewässerung meines Basilikums war“ → „Letzte Bewässerung vor 36h“
- „Alexa, sag Kräuterbox schalte Lampe an“ → „Pflanzenlampe eingeschaltet“
Videos & GIFs im Original zeigen die Funktion (Deutsch).
Geplante Features
- Energiesparmodus für Arduino-Code
- Externe Arduino Nanos mit 2,4 GHz Funk für weitere Pflanzen (Box als WiFi-Hub), batteriebetrieben
- API-Erweiterung für mehrere Kräuterbox-Instanzen (Freunde, Interessierte)
- Physischer Taster an Box für Bewässerung/Lampe ohne Web/Alexa
- Alexa-Bilder (Karte in Skill-Antwort)
Update 23.03.2018
Zwei neue Intents für geplante externe Arduino Nanos (nur Feuchtelogging):
- „Welche Pflanzen sind trocken“
- „Wann war die letzte Bewässerung“
Arduino-Code (Modulare Struktur)
Der Code ist in mehrere Dateien aufgeteilt:
- EcoActionBuffer.h/.cpp – Aktionspuffer mit Timer-Callbacks
- Plant.h/.cpp – Pflanzenobjekt mit Feuchtemessung & API-Update
- WhiteWalnut.ino – Hauptsketch: Initialisierung, Timer, Hauptloop
- WhiteWalnutApi.h/.cpp – WiFi-Verbindung, HTTP-Requests, JSON-Parsing (ArduinoJson), API-Kommunikation
Hinweis: Vollständiger Code ist im Original enthalten. Hier exemplarisch die Header-Dateien:
EcoActionBuffer.h
#ifndef ECOACTIONBUFFER_H
#define ECOACTIONBUFFER_H
#include "Arduino.h"
#include "StensTimer.h"
struct EcoActionBuffer : public IStensTimerListener {
long entryNo;
int action;
int pin;
long duration;
void timerCallback(Timer* timer);
void switchPin(int pin, bool value);
void readStack();
void process();
void toSerial();
void reset();
};
#endif
Plant.h
#ifndef PLANT_H
#define PLANT_H
#include "Arduino.h"
#include "StensTimer.h"
struct Plant : public IStensTimerListener {
const char* code;
int humidityDataPin;
long humidityCheckInterval;
void checkHumidity();
void timerCallback(Timer* timer);
void toSerial();
void updateApi();
};
#endif
WhiteWalnutApi.h
#ifndef WHITEWALNUTAPI_H
#define WHITEWALNUTAPI_H
#include "Arduino.h"
#include "ArduinoJson.h"
#include "EcoActionBuffer.h"
#include "Plant.h"
class WhiteWalnutApi {
public:
static bool connectToWiFi();
static void updatePlant(Plant& plant);
static void sendHumidity(Plant& plant, int humidity);
static void sendHeartbeat(Plant& plant);
static void receiveActionFromStack(EcoActionBuffer& actionBuffer);
static void updateActionOnStack(EcoActionBuffer& actionBuffer);
static void switchPin(int pin, bool value);
private:
static bool httpRequest(String site);
static JsonObject& parseJson();
};
#endif
Schaltpläne & Diagramme
- Kommunikations- & Schnittstellen-Chart
- Alle implementierten Alexa-Intents mit Responses (mehrsprachig)
- Einstieg in Alexa-JSON-Parsing
Herstellungsprozess
- Web-gesteuertes DMX-Lichtsystem – Arduino Master Controller
- Bluetooth-gesteuerter Arduino-Spybot bauen – Überwachungsroboter mit IP-Kamera
- SERENA: Eigenes Arduino Mega 2560 Alarmsystem mit TFT-LCD-Touchscreen
- Kompakte Wetterstation: Arduino Nano & ESP8266 mit BMP280 Barometrischem Sensor & OLED/Nokia LCD Display
- Intelligente Kellerbelüftung: Arduino-gesteuerte Feuchteregelung
- Echtzeit-RFID-Anwesenheitssystem mit Arduino & Google Tabellen
- Drahtloses Arduino-Programmier-Shield mit HC-05 Bluetooth – Kein USB-Kabel nötig
- Fortschrittliches Arduino Kollisionswarnsystem – Visuelle & Akustische Alerts für Fahrzeugsicherheit
- 2,8″ TFT-Shield für Arduino Nano – 320×240 SPI-Display mit Touch
- Nixie-Röhren-Uhr-Shield NCS314 für Arduino UNO/MEGA – Kompatibilität mit IN‑14/IN‑12