GruppeC/firmware/dht11_lcd/esp_wifi.h

154 lines
4.7 KiB
C

// 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 <SoftwareSerial.h>
#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;
}