// ESP8266 (ESP-01) per AT-Befehle am Arduino Uno: sendet die Messwerte als HTTP-POST // an das Backend (POST /api/messwerte, Empfaenger: backend/server.py). #include "wifi_config.h" // --- ESP-01 Verdrahtung (GEKREUZT, anders als Instructables "Add WiFi to Arduino UNO", siehe README) --- // ESP TX -> Uno RX (Pin 0) \ Hardware-Serial! Das Modul teilt sich die Leitung mit dem USB-Anschluss: // ESP RX -> Uno TX (Pin 1) / Beim Hochladen des Sketches ESP TX/RX kurz abziehen. // ESP VCC und EN -> 3,3 V, ESP GND -> GND (gemeinsame Masse mit dem Uno, auch bei fremder 3,3-V-Quelle) // Serial.print() darf im Sketch NICHT fuer Debugging genutzt werden, die Ausgabe ginge an das ESP. #define espSerial Serial bool wifiOk = false; uint8_t sendeFehler = 0; const uint8_t MAX_SENDEFEHLER = 3; // danach wird das WLAN neu verbunden // Ein Verbindungsversuch blockiert 10-30 s. Ohne WLAN deshalb hoechstens einmal pro Minute // neu verbinden, damit das LCD in der Zwischenzeit normal weiterlaeuft. const unsigned long WIFI_NEUVERSUCH_MS = 60000UL; unsigned long letzterWifiVersuch = 0; // Verwirft alles, was der ESP noch geschickt hat void espLeeren() { while (espSerial.available()) { espSerial.read(); } } // Liest vom ESP, bis `ziel` (max. 11 Zeichen) vorkommt. false bei Timeout. bool espWarteAuf(const char* ziel, unsigned long timeoutMs) { char fenster[12]; const uint8_t n = strlen(ziel); memset(fenster, 0, sizeof(fenster)); unsigned long start = millis(); while (millis() - start < timeoutMs) { while (espSerial.available()) { memmove(fenster, fenster + 1, n - 1); fenster[n - 1] = espSerial.read(); if (memcmp(fenster, ziel, n) == 0) { return true; } } } return false; } bool espBefehl(const __FlashStringHelper* befehl, const char* ziel = "OK", unsigned long timeoutMs = 2000) { espLeeren(); espSerial.println(befehl); return espWarteAuf(ziel, timeoutMs); } // Findet die Baudrate des Moduls (Werkseinstellung meist 115200, manchmal 9600) bool espBaudrateFinden() { const long raten[] = {115200, 9600, 57600, 38400}; delay(3000); // das ESP braucht nach dem Einschalten ca. 2-3 s zum Booten for (uint8_t runde = 0; runde < 2; runde++) { for (uint8_t i = 0; i < 4; i++) { espSerial.begin(raten[i]); if (espBefehl(F("AT"), "OK", 1000)) { return true; } } } return false; } // Fehlercode der letzten Verbindung fuer das LCD: 0 = OK, 1 = ESP antwortet nicht, // 2 = CWMODE fehlgeschlagen, 3 = WLAN-Verbindung fehlgeschlagen (SSID/Passwort/2,4 GHz) uint8_t wifiFehler = 0; bool wifiVerbinden() { wifiOk = false; letzterWifiVersuch = millis(); if (!espBaudrateFinden()) { wifiFehler = 1; return false; } espBefehl(F("ATE0")); // Echo aus if (!espBefehl(F("AT+CWMODE=1"))) { // Station-Modus wifiFehler = 2; return false; } espBefehl(F("AT+CIPMUX=0")); // eine Verbindung gleichzeitig espLeeren(); espSerial.print(F("AT+CWJAP=\"")); espSerial.print(F(WLAN_SSID)); espSerial.print(F("\",\"")); espSerial.print(F(WLAN_PASSWORT)); espSerial.println(F("\"")); wifiOk = espWarteAuf("OK", 20000); wifiFehler = wifiOk ? 0 : 3; return wifiOk; } // Schickt einen Messwertsatz per HTTP-POST an das Backend. true, wenn der Server mit 200 antwortet. bool sendeMesswerte(float temperatur, float luftfeuchte, uint16_t eco2, uint16_t tvoc) { if (!wifiOk) { if (millis() - letzterWifiVersuch < WIFI_NEUVERSUCH_MS || !wifiVerbinden()) { return false; } } char temp[8], feuchte[8]; dtostrf(temperatur, 1, 1, temp); dtostrf(luftfeuchte, 1, 1, feuchte); char body[72]; snprintf_P(body, sizeof(body), PSTR("{\"temperatur\":%s,\"luftfeuchte\":%s,\"eco2\":%u,\"tvoc\":%u}"), temp, feuchte, eco2, tvoc); char anfrage[200]; int laenge = snprintf_P(anfrage, sizeof(anfrage), PSTR("POST /api/messwerte HTTP/1.1\r\nHost: %s:%u\r\n" "Content-Type: application/json\r\nContent-Length: %u\r\n" "Connection: close\r\n\r\n%s"), SERVER_IP, (unsigned int)SERVER_PORT, (unsigned int)strlen(body), body); espLeeren(); espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(F(SERVER_IP)); espSerial.print(F("\",")); espSerial.println(SERVER_PORT); bool ok = espWarteAuf("OK", 5000); if (ok) { espLeeren(); espSerial.print(F("AT+CIPSEND=")); espSerial.println(laenge); ok = espWarteAuf(">", 2000); } if (ok) { espSerial.print(anfrage); ok = espWarteAuf("200 OK", 4000); } // Verbindung schließen (der Server hat sie meist schon beendet, dann kommt ERROR) espSerial.println(F("AT+CIPCLOSE")); espWarteAuf("OK", 300); if (ok) { sendeFehler = 0; return true; } if (++sendeFehler >= MAX_SENDEFEHLER) { sendeFehler = 0; wifiOk = false; // beim nächsten Senden neu verbinden } return false; }