Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Intelligentes Kräuterbox-Ökosystem: Alexa-gesteuertes Indoor-Garten-Set

Komponenten und Materialien

KomponenteMenge
Amazon Alexa Echo Dot1
Arduino UNO1
Espressif ESP8266 ESP-01 (WiFi-Modul)1
Arduino Proto Shield1
Arduino 4-Kanal-Relais-Shield1
Aqua-Pumpe (12V)2
Pflanzenwachstumslampe (230V)1
220V DC Netzteil1
12V DC Netzteil1
USB-Netzteil + Kabel1
Luftschlauch1
Jumper-Wires (Sortiment)1

Apps & Online-Dienste

Ü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

  1. Web-gesteuertes DMX-Lichtsystem – Arduino Master Controller
  2. Bluetooth-gesteuerter Arduino-Spybot bauen – Überwachungsroboter mit IP-Kamera
  3. SERENA: Eigenes Arduino Mega 2560 Alarmsystem mit TFT-LCD-Touchscreen
  4. Kompakte Wetterstation: Arduino Nano & ESP8266 mit BMP280 Barometrischem Sensor & OLED/Nokia LCD Display
  5. Intelligente Kellerbelüftung: Arduino-gesteuerte Feuchteregelung
  6. Echtzeit-RFID-Anwesenheitssystem mit Arduino & Google Tabellen
  7. Drahtloses Arduino-Programmier-Shield mit HC-05 Bluetooth – Kein USB-Kabel nötig
  8. Fortschrittliches Arduino Kollisionswarnsystem – Visuelle & Akustische Alerts für Fahrzeugsicherheit
  9. 2,8″ TFT-Shield für Arduino Nano – 320×240 SPI-Display mit Touch
  10. Nixie-Röhren-Uhr-Shield NCS314 für Arduino UNO/MEGA – Kompatibilität mit IN‑14/IN‑12