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.
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:
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
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
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
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
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
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:
- Download and install Arduino IDE version 2.3.0 or higher from
arduino.cc
- Start Arduino IDE
- Open menu File → Preferences
- In the field Additional Board Manager URLs enter the following URL:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- Confirm with OK and restart IDE
- Open menu Tools → Board → Board Manager
- Enter "esp32" in the search field
- Find entry "esp32 by Espressif Systems"
- Select version 2.0.14 or higher and click Install
- Close Board Manager after installation completes
- Open menu Tools → Board → esp32 and select "ESP32 Dev Module"
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.
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:
- Download AsyncTCP from
https://github.com/me-no-dev/AsyncTCP
as ZIP (green "Code" button → "Download ZIP") - Download ESPAsyncWebServer from
https://github.com/me-no-dev/ESPAsyncWebServer
as ZIP - In Arduino IDE: Sketch → Include Library → Add .ZIP Library
- First select and install the AsyncTCP-master.zip file
- Then select and install the ESPAsyncWebServer-master.zip file
- 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.
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
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:
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
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
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
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: