GruppeC/firmware/dht11_lcd/esp_wifi.h

160 lines
5.1 KiB
C

// 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]);
// Leere Zeile zuerst: schliesst Zeichensalat ab, den der ESP beim Uno-Reset oder durch
// einen Versuch mit falscher Baudrate empfangen hat. Sonst wird daraus z. B. "x#~AT" -> ERROR.
espSerial.print(F("\r\n"));
delay(100);
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;
}