148 lines
4.5 KiB
C
148 lines
4.5 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 "wifi_config.h"
|
|
|
|
// --- ESP-01 Verdrahtung (wie Instructables "Add WiFi to Arduino UNO") ---
|
|
// 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 VIN und ENABLE -> 3,3 V, ESP GND -> GND
|
|
// 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
|
|
|
|
// 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;
|
|
|
|
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 && !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;
|
|
}
|