Select your language

© Borgmann Aquaponik & Hydroponik
Alle Rechte Vorbehalten
https://borgmann-aquaponik-hydroponik.ch

Viel Erfolg wünschen wir Ihnen!

Email Alerts

Automatic notifications for aquaponics and hydroponics systems

Introduction

An automated plant growing system offers numerous advantages, but its true strength lies in the ability for remote monitoring and timely alerts during critical conditions. This article provides detailed explanations on how to equip an ESP32-based system for monitoring aquaponics and hydroponics systems with alarm functions and remote access.

The implementation comprises three essential components: A notification system for critical events, a web-based interface for remote control, and integration into existing smart home infrastructures. All presented solutions are based on low-cost components and open-source software.

Hardware Selection and Technical Specifications

Microcontroller

For implementation, the ESP32-DevKitC V4 (Espressif Systems) with the ESP32-WROOM-32 module is recommended. This exact specification is crucial for correct compilation and function of the code.

ESP32-DevKitC V4 (ESP32-WROOM-32)

Processor: Xtensa Dual-Core 32-bit LX6, up to 240 MHz

Flash Memory: 4 MB

SRAM: 520 KB

WiFi: 802.11 b/g/n (2.4 GHz)

GPIO Pins: 34 programmable

Operating Voltage: 3.3V (via USB 5V)

Estimated Cost: 8-12 EUR

Sensors

For a complete monitoring system, the following sensors are specified:

pH Sensor

Model: DFRobot SEN0161-V2

Interface: Analog (0-5V via BNC connector)

Measurement Range: 0-14 pH

Accuracy: ±0.1 pH at 25°C

Operating Voltage: 5V DC

Output Signal: 0-3.0V (corresponds to pH 0-14)

Cost: approx. 35-45 EUR

Water Temperature

Model: DS18B20 (waterproof version)

Interface: OneWire (Digital, 1-Wire protocol)

Measurement Range: -55 to +125°C

Accuracy: ±0.5°C (-10°C to +85°C)

Resolution: 9-12 bit (configurable)

Operating Voltage: 3.0-5.5V

Cost: approx. 3-5 EUR

Water Level

Model: JSN-SR04T (waterproof ultrasonic version)

Interface: Digital (Trigger/Echo pins)

Measurement Range: 25-450 cm

Accuracy: ±1 cm

Operating Voltage: 5V DC

Current Consumption: 8 mA

Cost: approx. 8-12 EUR

Air Temperature/Humidity

Model: DHT22 (AM2302)

Interface: Digital (Single-Wire, proprietary protocol)

Temperature Range: -40 to +80°C

Humidity Range: 0-100% RH

Accuracy: ±0.5°C / ±2% RH

Operating Voltage: 3.3-5.5V

Cost: approx. 5-8 EUR

Additional Components

Relay Module

Specification: 4-channel 5V relay module with optocoupler

Switching Capacity: 10A at 250V AC / 30V DC per channel

Control: Low-level trigger (relay switches at LOW signal)

LED Indicator: Per channel

Purpose: Switching pumps, lighting

Cost: approx. 6-10 EUR

Power Supply

Specification: Switching power supply 5V DC, 3A

Input Voltage: 100-240V AC

Output: 5V DC, max. 3A (15W)

Connection: USB-A or terminal block

Purpose: Power supply for ESP32 and peripherals

Cost: approx. 8-12 EUR

Software Environment and Configuration

Setting Up the Development Environment

The Arduino IDE is used for programming the ESP32-DevKitC V4. The following configuration is required:

Step 1: Arduino IDE Installation
  1. Download and install Arduino IDE version 2.3.0 or higher from arduino.cc
  2. Start Arduino IDE
  3. Open menu File → Preferences
  4. In the field Additional Board Manager URLs enter the following URL:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  5. Confirm with OK and restart IDE
Step 2: Install ESP32 Board Support
  1. Open menu Tools → Board → Board Manager
  2. Enter "esp32" in the search field
  3. Find entry "esp32 by Espressif Systems"
  4. Select version 2.0.14 or higher and click Install
  5. Close Board Manager after installation completes
  6. Open menu Tools → Board → esp32 and select "ESP32 Dev Module"
Step 3: Board Configuration

Set the following options under the Tools menu:

  • Board: "ESP32 Dev Module"
  • Upload Speed: 921600
  • CPU Frequency: 240MHz (WiFi/BT)
  • Flash Frequency: 80MHz
  • Flash Mode: QIO
  • Flash Size: 4MB (32Mb)
  • Partition Scheme: "Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)"
  • Core Debug Level: "None"
  • Port: Select appropriate COM port (e.g., COM3 on Windows or /dev/ttyUSB0 on Linux)

Note: If connection problems occur, reduce Upload Speed to 115200.

Step 4: Install Required Libraries

Open menu Sketch → Include Library → Manage Libraries and install the following libraries:

  • OneWire by Paul Stoffregen (version 2.3.7 or higher)
  • DallasTemperature by Miles Burton (version 3.9.0 or higher)
  • DHT sensor library by Adafruit (version 1.4.4 or higher)
  • Adafruit Unified Sensor by Adafruit (version 1.1.9 or higher)
  • ESP Mail Client by Mobizt (version 3.4.0 or higher)

Manual Installation of ESPAsyncWebServer and AsyncTCP:

  1. Download AsyncTCP from https://github.com/me-no-dev/AsyncTCP as ZIP (green "Code" button → "Download ZIP")
  2. Download ESPAsyncWebServer from https://github.com/me-no-dev/ESPAsyncWebServer as ZIP
  3. In Arduino IDE: Sketch → Include Library → Add .ZIP Library
  4. First select and install the AsyncTCP-master.zip file
  5. Then select and install the ESPAsyncWebServer-master.zip file
  6. Restart Arduino IDE

Hardware Setup and Wiring

Pin Assignment ESP32-DevKitC V4

The following pin assignment is intended for the complete system. The choice of GPIO pins takes into account the hardware-specific limitations of the ESP32.

Sensors - Connection Diagram
DS18B20 (Water Temperature)
  • Data (yellow): GPIO 4
  • VCC (red): 3.3V
  • GND (black): GND
  • Important: 4.7kΩ pull-up resistor required between Data and VCC
DHT22 (Air Temperature/Humidity)
  • Data (Signal): GPIO 15
  • VCC: 3.3V
  • GND: GND
JSN-SR04T (Water Level)
  • Trigger: GPIO 5
  • Echo: GPIO 18
  • VCC: 5V
  • GND: GND
pH Sensor SEN0161-V2
  • Signal (analog): GPIO 34 (ADC1_CH6)
  • VCC: 5V
  • GND: GND
  • Note: Voltage divider required, as ESP32 only tolerates 3.3V
Actuators - Relay Module
4-Channel Relay Module
  • IN1 (Pump 1): GPIO 12
  • IN2 (Pump 2): GPIO 13
  • IN3 (Lighting): GPIO 14
  • IN4 (Reserve): GPIO 27
  • VCC: 5V
  • GND: GND

Voltage Divider for pH Sensor

The pH sensor SEN0161-V2 delivers an analog signal of 0-3.0V. The ESP32 tolerates a maximum of 3.3V at the ADC inputs, but a voltage divider is recommended for safety:

Required Resistors:

  • R1: 10kΩ (between pH sensor signal and GPIO 34)
  • R2: 10kΩ (between GPIO 34 and GND)

Result: The input signal is halved, the measurement range remains usable through software calibration.

Email Notification System

The notification system automatically sends emails during critical events. The implementation uses an SMTP server for email transmission. In this example, Gmail is used as the SMTP server.

SMTP Server Options

Various SMTP servers are available for email notification. Independent or self-hosted solutions are recommended:

Own SMTP Server (recommended)

Advantages:

  • Full control over data
  • No dependence on third parties
  • No quota limitations

Example Configuration:

  • SMTP Host: mail.your-domain.com
  • Port: 587 (STARTTLS) or 465 (SSL)
  • Authentication: Username and password
Mailbox.org

German provider with privacy focus:

  • Server location Germany
  • GDPR compliant
  • Cost: from 1 EUR/month

SMTP Configuration:

  • Host: smtp.mailbox.org
  • Port: 465 (SSL) or 587 (STARTTLS)
  • Authentication: Email and password
Posteo

German provider, focus on privacy:

  • Anonymous registration possible
  • Server location Germany
  • Cost: 1 EUR/month

SMTP Configuration:

  • Host: posteo.de
  • Port: 465 (SSL) or 587 (STARTTLS)
  • Authentication: Email and password
Internet Provider SMTP

SMTP server of your own provider:

  • Usually free in tariff plan
  • Direct availability
  • Provider-dependent configuration

Examples:

  • 1&1: smtp.1und1.de (Port 587)
  • Strato: smtp.strato.de (Port 465)
  • Configuration: Inquire with provider

Implementation of Email Notification System

The following code implements a complete monitoring system with email notification. The system continuously monitors all sensors and automatically sends an email when defined thresholds are exceeded.


/* * ESP32 Aquaponik Überwachungssystem mit E-Mail-Benachrichtigung * * Hardware: ESP32-DevKitC V4 (ESP32-WROOM-32) * Compiler: Arduino IDE 2.3.0 oder höher mit esp32 Board Support 2.0.14+ * * Sensoren: * - DS18B20: Wassertemperatur (OneWire, GPIO 4) * - DHT22: Lufttemperatur/Feuchtigkeit (GPIO 15) * - JSN-SR04T: Wasserstand Ultraschall (Trigger GPIO 5, Echo GPIO 18) * - DFRobot SEN0161-V2: pH-Wert (Analog GPIO 34) * * Aktoren: * - 4-Kanal Relais-Modul (GPIO 12, 13, 14, 27) * * Erforderliche Bibliotheken (über Bibliotheksverwalter): * - OneWire 2.3.7+ * - DallasTemperature 3.9.0+ * - DHT sensor library 1.4.4+ (Adafruit) * - Adafruit Unified Sensor 1.1.9+ * - ESP Mail Client 3.4.0+ (Mobizt) * * Erforderliche Bibliotheken (manuelle Installation): * - AsyncTCP (https://github.com/me-no-dev/AsyncTCP) * - ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) */ #include #include #include #include #include // ==================== KONFIGURATION START ==================== // Bitte alle Werte entsprechend anpassen! // WiFi-Zugangsdaten #define WIFI_SSID "IhrWLANName" // WLAN-SSID #define WIFI_PASSWORD "IhrWLANPasswort" // WLAN-Passwort // SMTP-Server Konfiguration (Beispiel: Mailbox.org) // Für andere Anbieter entsprechend anpassen #define SMTP_HOST "smtp.mailbox.org" // SMTP-Server Adresse #define SMTP_PORT 465 // Port (465 für SSL, 587 für STARTTLS) #define AUTHOR_EMAIL "This email address is being protected from spambots. You need JavaScript enabled to view it." // Absender E-Mail-Adresse #define AUTHOR_PASSWORD "IhrPasswort" // E-Mail Passwort #define RECIPIENT_EMAIL "This email address is being protected from spambots. You need JavaScript enabled to view it." // Empfänger E-Mail-Adresse #define RECIPIENT_NAME "Aquaponik Admin" // Empfängername // Sensor Pin-Definitionen #define ONE_WIRE_BUS 4 // DS18B20 Datenleitung (OneWire) #define DHTPIN 15 // DHT22 Datenleitung #define DHTTYPE DHT22 // DHT-Sensor Typ #define TRIGGER_PIN 5 // Ultraschall Sensor Trigger #define ECHO_PIN 18 // Ultraschall Sensor Echo #define PH_PIN 34 // pH-Sensor Analogeingang (ADC1_CH6) // Relais Pin-Definitionen (LOW-Level-Trigger) #define RELAY_PUMP1 12 // Pumpe 1 (Hauptpumpe) #define RELAY_PUMP2 13 // Pumpe 2 (Nährlösung) #define RELAY_LIGHT 14 // Beleuchtung #define RELAY_RESERVE 27 // Reserve (z.B. Heizung/Lüfter) // Grenzwerte für Alarme - an eigene Anforderungen anpassen #define PH_MIN 5.5 // Minimaler pH-Wert #define PH_MAX 7.5 // Maximaler pH-Wert #define WATER_TEMP_MIN 18.0 // Minimale Wassertemperatur (°C) #define WATER_TEMP_MAX 26.0 // Maximale Wassertemperatur (°C) #define WATER_LEVEL_MIN 10.0 // Minimaler Wasserstand (cm vom Sensor) #define WATER_LEVEL_MAX 100.0 // Maximaler Wasserstand (cm vom Sensor) #define AIR_TEMP_MAX 35.0 // Maximale Lufttemperatur (°C) #define HUMIDITY_MIN 40.0 // Minimale Luftfeuchtigkeit (%) // pH-Sensor Kalibrierung (muss für jeden Sensor individuell erfolgen) // Diese Werte sind Beispiele und müssen angepasst werden! #define PH_CALIBRATION_VOLTAGE_4 1.032 // Spannung bei pH 4 (Volt) #define PH_CALIBRATION_VOLTAGE_7 1.500 // Spannung bei pH 7 (Volt) // Zeitintervalle #define SENSOR_READ_INTERVAL 30000 // Sensor-Abfrage alle 30 Sekunden #define EMAIL_COOLDOWN 300000 // Min. 5 Minuten zwischen E-Mails // ==================== KONFIGURATION ENDE ==================== // Globale Objekte initialisieren OneWire oneWire(ONE_WIRE_BUS); // OneWire-Bus für DS18B20 DallasTemperature sensors(&oneWire); // Dallas Temperature Bibliothek DHT dht(DHTPIN, DHTTYPE); // DHT22 Sensor SMTPSession smtp; // SMTP Session für E-Mail // Globale Variablen unsigned long lastSensorRead = 0; // Zeitstempel letzte Sensor-Abfrage unsigned long lastEmailSent = 0; // Zeitstempel letzte E-Mail bool wifiConnected = false; // WiFi Verbindungsstatus // Struktur für Sensordaten struct SensorData { float waterTemp; // Wassertemperatur in °C float airTemp; // Lufttemperatur in °C float humidity; // Luftfeuchtigkeit in % float waterLevel; // Wasserstand in cm float pH; // pH-Wert bool valid; // Daten gültig? }; SensorData currentData = {0, 0, 0, 0, 0, false}; // Struktur für Alarmzustände struct AlarmState { bool phLow; // pH zu niedrig bool phHigh; // pH zu hoch bool waterTempLow; // Wassertemperatur zu niedrig bool waterTempHigh; // Wassertemperatur zu hoch bool waterLevelLow; // Wasserstand zu niedrig bool waterLevelHigh; // Wasserstand zu hoch bool airTempHigh; // Lufttemperatur zu hoch bool humidityLow; // Luftfeuchtigkeit zu niedrig bool anyAlarm; // Irgendein Alarm aktiv }; AlarmState alarmState = {false, false, false, false, false, false, false, false, false}; // ==================== SETUP ==================== void setup() { // Serielle Kommunikation starten (für Debugging) Serial.begin(115200); delay(1000); Serial.println("\n\n=== ESP32 Aquaponik Überwachungssystem ==="); Serial.println("Hardware: ESP32-DevKitC V4 (ESP32-WROOM-32)"); Serial.println("========================================\n"); // GPIO-Pins konfigurieren pinMode(TRIGGER_PIN, OUTPUT); // Ultraschall Trigger als Ausgang pinMode(ECHO_PIN, INPUT); // Ultraschall Echo als Eingang pinMode(RELAY_PUMP1, OUTPUT); // Relais als Ausgang pinMode(RELAY_PUMP2, OUTPUT); pinMode(RELAY_LIGHT, OUTPUT); pinMode(RELAY_RESERVE, OUTPUT); // Relais initial ausschalten (HIGH bei Low-Level-Trigger Modulen) digitalWrite(RELAY_PUMP1, HIGH); digitalWrite(RELAY_PUMP2, HIGH); digitalWrite(RELAY_LIGHT, HIGH); digitalWrite(RELAY_RESERVE, HIGH); Serial.println("GPIO-Pins initialisiert"); // Sensoren initialisieren sensors.begin(); // DS18B20 starten dht.begin(); // DHT22 starten // Anzahl der DS18B20 Sensoren prüfen int deviceCount = sensors.getDeviceCount(); Serial.print("DS18B20 Sensoren gefunden: "); Serial.println(deviceCount); if (deviceCount == 0) { Serial.println("WARNUNG: Kein DS18B20 gefunden! Verkabelung prüfen."); } // WiFi verbinden connectToWiFi(); Serial.println("\nSystem bereit. Starte Überwachung...\n"); } // ==================== MAIN LOOP ==================== void loop() { // WiFi-Verbindung prüfen und ggf. wiederherstellen if (WiFi.status() != WL_CONNECTED && wifiConnected) { Serial.println("WiFi-Verbindung verloren. Versuche Wiederverbindung..."); wifiConnected = false; connectToWiFi(); } // Sensoren in definierten Intervallen auslesen if (millis() - lastSensorRead >= SENSOR_READ_INTERVAL) { lastSensorRead = millis(); // Alle Sensoren auslesen readAllSensors(); // Daten ausgeben printSensorData(); // Alarmzustände prüfen checkAlarms(); // Bei Alarm E-Mail senden (wenn Cooldown abgelaufen) if (alarmState.anyAlarm && wifiConnected) { if (millis() - lastEmailSent >= EMAIL_COOLDOWN) { sendAlarmEmail(); lastEmailSent = millis(); } else { Serial.println("Alarm aktiv, aber E-Mail Cooldown noch nicht abgelaufen"); } } } // Kleine Pause um Watchdog zu bedienen delay(100); } // ==================== FUNKTIONEN ==================== /** * Verbindung zum WiFi herstellen */ void connectToWiFi() { Serial.print("Verbinde mit WiFi: "); Serial.println(WIFI_SSID); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); int attempts = 0; while (WiFi.status() != WL_CONNECTED && attempts < 20) { delay(500); Serial.print("."); attempts++; } if (WiFi.status() == WL_CONNECTED) { wifiConnected = true; Serial.println("\nWiFi verbunden!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); Serial.print("Signalstärke: "); Serial.print(WiFi.RSSI()); Serial.println(" dBm"); } else { wifiConnected = false; Serial.println("\nWiFi-Verbindung fehlgeschlagen!"); Serial.println("System arbeitet im Offline-Modus (keine E-Mails möglich)"); } } /** * Alle Sensoren auslesen und Daten in currentData speichern */ void readAllSensors() { // DS18B20 Wassertemperatur auslesen sensors.requestTemperatures(); currentData.waterTemp = sensors.getTempCByIndex(0); // DHT22 Lufttemperatur und Feuchtigkeit auslesen currentData.airTemp = dht.readTemperature(); currentData.humidity = dht.readHumidity(); // JSN-SR04T Wasserstand auslesen currentData.waterLevel = readUltrasonic(); // pH-Wert auslesen currentData.pH = readPH(); // Validität prüfen (NaN-Werte von DHT22 abfangen) currentData.valid = !isnan(currentData.airTemp) && !isnan(currentData.humidity) && currentData.waterTemp != -127.0; } /** * Wasserstand mit JSN-SR04T Ultraschallsensor messen * @return Distanz in cm */ float readUltrasonic() { // Trigger-Impuls senden (10µs HIGH) digitalWrite(TRIGGER_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIGGER_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIGGER_PIN, LOW); // Echo-Zeit messen (Timeout nach 30ms = ca. 5m) long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Distanz berechnen: Schallgeschwindigkeit ca. 343 m/s // Distanz = (Zeit * Geschwindigkeit) / 2 (Hin- und Rückweg) // In cm: duration (µs) * 0.0343 / 2 float distance = duration * 0.01715; // Plausibilität prüfen if (distance < 2.0 || distance > 450.0) { Serial.println("Ultraschall: Messung außerhalb des gültigen Bereichs"); return -1.0; } return distance; } /** * pH-Wert mit DFRobot SEN0161-V2 messen * @return pH-Wert (0-14) */ float readPH() { // ADC-Wert auslesen (12-bit: 0-4095) // Mit Spannungsteiler (R1=R2=10k): Eingangsspannung wird halbiert int adcValue = analogRead(PH_PIN); // ADC-Wert in Spannung umrechnen // ESP32 ADC: 0-4095 entspricht 0-3.3V // Mit Spannungsteiler: tatsächliche Sensorspannung = gemessene Spannung * 2 float voltage = (adcValue / 4095.0) * 3.3 * 2.0; // pH-Wert berechnen mittels 2-Punkt-Kalibrierung // Lineare Interpolation zwischen zwei Kalibrierpunkten float phSlope = (7.0 - 4.0) / (PH_CALIBRATION_VOLTAGE_7 - PH_CALIBRATION_VOLTAGE_4); float phValue = 7.0 + phSlope * (voltage - PH_CALIBRATION_VOLTAGE_7); // Plausibilität prüfen if (phValue < 0.0 || phValue > 14.0) { Serial.println("pH-Sensor: Messung außerhalb des gültigen Bereichs"); Serial.print("Gemessene Spannung: "); Serial.print(voltage, 3); Serial.println(" V"); return -1.0; } return phValue; } /** * Sensordaten auf Serial Monitor ausgeben */ void printSensorData() { Serial.println("=== Aktuelle Messwerte ==="); if (currentData.valid) { Serial.print("Wassertemperatur: "); Serial.print(currentData.waterTemp, 1); Serial.println(" °C"); Serial.print("Lufttemperatur: "); Serial.print(currentData.airTemp, 1); Serial.println(" °C"); Serial.print("Luftfeuchtigkeit: "); Serial.print(currentData.humidity, 1); Serial.println(" %"); if (currentData.waterLevel > 0) { Serial.print("Wasserstand: "); Serial.print(currentData.waterLevel, 1); Serial.println(" cm"); } else { Serial.println("Wasserstand: Messfehler"); } if (currentData.pH > 0) { Serial.print("pH-Wert: "); Serial.println(currentData.pH, 2); } else { Serial.println("pH-Wert: Messfehler"); } } else { Serial.println("FEHLER: Sensordaten ungültig!"); } Serial.println("==========================\n"); } /** * Grenzwerte prüfen und Alarmzustände setzen */ void checkAlarms() { // Alle Alarmzustände zurücksetzen alarmState.phLow = false; alarmState.phHigh = false; alarmState.waterTempLow = false; alarmState.waterTempHigh = false; alarmState.waterLevelLow = false; alarmState.waterLevelHigh = false; alarmState.airTempHigh = false; alarmState.humidityLow = false; // Nur prüfen wenn Daten gültig if (!currentData.valid) { Serial.println("ALARM: Sensordaten ungültig - System-Check erforderlich!"); alarmState.anyAlarm = true; return; } // pH-Wert prüfen if (currentData.pH > 0) { if (currentData.pH < PH_MIN) { alarmState.phLow = true; Serial.println("ALARM: pH-Wert zu niedrig!"); } if (currentData.pH > PH_MAX) { alarmState.phHigh = true; Serial.println("ALARM: pH-Wert zu hoch!"); } } // Wassertemperatur prüfen if (currentData.waterTemp < WATER_TEMP_MIN) { alarmState.waterTempLow = true; Serial.println("ALARM: Wassertemperatur zu niedrig!"); } if (currentData.waterTemp > WATER_TEMP_MAX) { alarmState.waterTempHigh = true; Serial.println("ALARM: Wassertemperatur zu hoch!"); } // Wasserstand prüfen if (currentData.waterLevel > 0) { if (currentData.waterLevel < WATER_LEVEL_MIN) { alarmState.waterLevelLow = true; Serial.println("ALARM: Wasserstand zu niedrig!"); } if (currentData.waterLevel > WATER_LEVEL_MAX) { alarmState.waterLevelHigh = true; Serial.println("ALARM: Wasserstand zu hoch!"); } } // Lufttemperatur prüfen if (currentData.airTemp > AIR_TEMP_MAX) { alarmState.airTempHigh = true; Serial.println("ALARM: Lufttemperatur zu hoch!"); } // Luftfeuchtigkeit prüfen if (currentData.humidity < HUMIDITY_MIN) { alarmState.humidityLow = true; Serial.println("ALARM: Luftfeuchtigkeit zu niedrig!"); } // Gesamtalarmstatus setzen alarmState.anyAlarm = alarmState.phLow || alarmState.phHigh || alarmState.waterTempLow || alarmState.waterTempHigh || alarmState.waterLevelLow || alarmState.waterLevelHigh || alarmState.airTempHigh || alarmState.humidityLow; } /** * Alarm-E-Mail versenden */ void sendAlarmEmail() { Serial.println("\n=== Sende Alarm-E-Mail ==="); // SMTP-Session konfigurieren Session_Config config; config.server.host_name = SMTP_HOST; config.server.port = SMTP_PORT; config.login.email = AUTHOR_EMAIL; config.login.password = AUTHOR_PASSWORD; config.login.user_domain = ""; // Zeit-Synchronisation (für E-Mail-Header) config.time.ntp_server = "pool.ntp.org,time.nist.gov"; config.time.gmt_offset = 1; // MEZ: UTC+1 config.time.day_light_offset = 0; // SMTP-Session initialisieren if (!smtp.connect(&config)) { Serial.println("FEHLER: SMTP-Verbindung fehlgeschlagen"); Serial.println(smtp.errorReason()); return; } // E-Mail-Nachricht erstellen SMTP_Message message; message.sender.name = "ESP32 Aquaponik System"; message.sender.email = AUTHOR_EMAIL; message.subject = "ALARM: Aquaponik System - Kritischer Zustand"; message.addRecipient(RECIPIENT_NAME, RECIPIENT_EMAIL); // E-Mail-Body erstellen String emailBody = "ALARM - Kritischer Zustand im Aquaponik-System!\n\n"; emailBody += "Zeitpunkt: " + String(millis() / 1000) + " Sekunden seit System-Start\n\n"; emailBody += "=== AKTUELLE MESSWERTE ===\n"; emailBody += "Wassertemperatur: " + String(currentData.waterTemp, 1) + " °C\n"; emailBody += "Lufttemperatur: " + String(currentData.airTemp, 1) + " °C\n"; emailBody += "Luftfeuchtigkeit: " + String(currentData.humidity, 1) + " %\n"; emailBody += "Wasserstand: " + String(currentData.waterLevel, 1) + " cm\n"; emailBody += "pH-Wert: " + String(currentData.pH, 2) + "\n\n"; emailBody += "=== AKTIVE ALARME ===\n"; if (alarmState.phLow) emailBody += "- pH-Wert zu niedrig (< " + String(PH_MIN, 1) + ")\n"; if (alarmState.phHigh) emailBody += "- pH-Wert zu hoch (> " + String(PH_MAX, 1) + ")\n"; if (alarmState.waterTempLow) emailBody += "- Wassertemperatur zu niedrig (< " + String(WATER_TEMP_MIN, 1) + " °C)\n"; if (alarmState.waterTempHigh) emailBody += "- Wassertemperatur zu hoch (> " + String(WATER_TEMP_MAX, 1) + " °C)\n"; if (alarmState.waterLevelLow) emailBody += "- Wasserstand zu niedrig (< " + String(WATER_LEVEL_MIN, 1) + " cm)\n"; if (alarmState.waterLevelHigh) emailBody += "- Wasserstand zu hoch (> " + String(WATER_LEVEL_MAX, 1) + " cm)\n"; if (alarmState.airTempHigh) emailBody += "- Lufttemperatur zu hoch (> " + String(AIR_TEMP_MAX, 1) + " °C)\n"; if (alarmState.humidityLow) emailBody += "- Luftfeuchtigkeit zu niedrig (< " + String(HUMIDITY_MIN, 1) + " %)\n"; emailBody += "\nBitte System überprüfen!\n\n"; emailBody += "Diese Nachricht wurde automatisch vom ESP32 Aquaponik-Überwachungssystem generiert."; message.text.content = emailBody.c_str(); message.text.charSet = "utf-8"; message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_high; // E-Mail senden if (!MailClient.sendMail(&smtp, &message)) { Serial.println("FEHLER beim E-Mail-Versand"); Serial.println(smtp.errorReason()); } else { Serial.println("E-Mail erfolgreich versendet!"); } // SMTP-Session schließen smtp.closeSession(); Serial.println("==========================\n"); }

Kontext: