// ESP8266 (ESP-01) per AT-Befehle am Arduino Uno: sendet die Messwerte als HTTP-POST // an das Backend (POST /api/messwerte, Datenvertrag siehe backend/README.md). #include #include "wifi_config.h" // --- ESP-01 Verdrahtung --- // ESP TX -> Uno Pin 3 (SoftwareSerial-RX) // ESP RX -> Uno Pin 4 (SoftwareSerial-TX), über Spannungsteiler 5 V -> 3,3 V (z. B. 1 kΩ / 2 kΩ) // ESP VCC und CH_PD -> 3,3 V (Der ESP braucht bis ~300 mA, der 3,3-V-Pin des Uno liefert nur 50 mA!) // ESP GND -> GND const uint8_t ESP_RX_PIN = 3; const uint8_t ESP_TX_PIN = 4; SoftwareSerial espSerial(ESP_RX_PIN, ESP_TX_PIN); bool wifiOk = false; uint8_t sendeFehler = 0; const uint8_t MAX_SENDEFEHLER = 3; // danach wird das WLAN neu verbunden // 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. SoftwareSerial ist bei 115200 unzuverlässig, deshalb // wird ein Modul mit 115200 (Werkseinstellung) dauerhaft auf 9600 umgestellt. bool espBaudrateFinden() { espSerial.begin(9600); if (espBefehl(F("AT"))) { return true; } espSerial.begin(115200); espSerial.println(F("AT+UART_DEF=9600,8,1,0,0")); // neue AT-Firmware delay(500); espSerial.println(F("AT+CIOBAUD=9600")); // alte AT-Firmware delay(500); espSerial.begin(9600); return espBefehl(F("AT")); } bool wifiVerbinden() { wifiOk = false; if (!espBaudrateFinden()) { Serial.println(F("ESP8266 antwortet nicht (Pins, Versorgung, Baudrate pruefen)")); return false; } espBefehl(F("ATE0")); // Echo aus if (!espBefehl(F("AT+CWMODE=1"))) { // Station-Modus Serial.println(F("ESP8266: CWMODE fehlgeschlagen")); return false; } espBefehl(F("AT+CIPMUX=0")); // eine Verbindung gleichzeitig Serial.print(F("Verbinde mit WLAN ")); Serial.println(F(WLAN_SSID)); 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); Serial.println(wifiOk ? F("WLAN verbunden") : F("WLAN-Verbindung fehlgeschlagen (SSID/Passwort?)")); 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 && !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; Serial.println(F("An Server gesendet")); return true; } Serial.println(F("Senden fehlgeschlagen (Server-IP/Port/Firewall pruefen)")); if (++sendeFehler >= MAX_SENDEFEHLER) { sendeFehler = 0; wifiOk = false; // beim nächsten Senden neu verbinden } return false; }