// ============================================================================= // web_server.cpp – HTTP-Webinterface für Statusanzeige und Konfiguration // Projekt: MQTT-Display LaserCutter // ============================================================================= #include "web_server.h" #include "settings.h" #include "laser_tracker.h" #include "mqtt_client.h" #include #include // Globale Instanz WebServerManager webServer; // ----------------------------------------------------------------------------- // Hilfsmakro: HTML-Template-Platzhalter ersetzen // ----------------------------------------------------------------------------- static String htmlReplace(String html, const String& key, const String& value) { html.replace(key, value); return html; } // ----------------------------------------------------------------------------- // Konstruktor // ----------------------------------------------------------------------------- WebServerManager::WebServerManager() : _server(80) {} // ----------------------------------------------------------------------------- // begin() – Routen registrieren und Server starten // ----------------------------------------------------------------------------- void WebServerManager::begin() { registerRoutes(); ElegantOTA.begin(&_server); _server.begin(); Serial.println(F("[WebServer] gestartet auf Port 80")); Serial.print(F("[WebServer] URL: http://")); Serial.println(WiFi.localIP()); } // ----------------------------------------------------------------------------- // registerRoutes() // ----------------------------------------------------------------------------- void WebServerManager::registerRoutes() { // --- GET / – Statusseite ------------------------------------------------- _server.on("/", HTTP_GET, [this](AsyncWebServerRequest* request) { request->send(200, "text/html; charset=utf-8", buildStatusPage()); }); // --- GET /config – Konfigurationsformular -------------------------------- _server.on("/config", HTTP_GET, [this](AsyncWebServerRequest* request) { request->send(200, "text/html; charset=utf-8", buildConfigPage()); }); // --- POST /config – Konfiguration speichern ------------------------------ _server.on("/config", HTTP_POST, [](AsyncWebServerRequest* request) { const Settings& s = settings.get(); // MQTT const char* broker = s.mqttBroker; uint16_t port = s.mqttPort; const char* user = s.mqttUser; const char* pass = s.mqttPassword; if (request->hasParam("broker", true)) broker = request->getParam("broker", true)->value().c_str(); if (request->hasParam("port", true)) port = (uint16_t)request->getParam("port", true)->value().toInt(); if (request->hasParam("user", true)) user = request->getParam("user", true)->value().c_str(); if (request->hasParam("password", true)) pass = request->getParam("password", true)->value().c_str(); settings.saveMqttConfig(broker, port, user, pass); // Gratiszeit if (request->hasParam("gratis", true)) { uint8_t g = (uint8_t)request->getParam("gratis", true)->value().toInt(); settings.saveGratisSeconds(g); } // Signal-Polarität if (request->hasParam("polarity", true)) { uint8_t pol = (uint8_t)request->getParam("polarity", true)->value().toInt(); settings.saveSignalPolarity(pol); } Serial.println(F("[WebServer] Konfiguration gespeichert – Neustart empfohlen")); // Weiterleitung mit Hinweis request->send(200, "text/html; charset=utf-8", "" "" "" "

✓ Gespeichert

" "

Einstellungen wurden in NVS geschrieben. " "MQTT-Änderungen werden nach einem Neustart aktiv.

" "

Weiterleitung in 3 s …

" ""); }); // --- POST /reset – Session zurücksetzen --------------------------------- _server.on("/reset", HTTP_POST, [](AsyncWebServerRequest* request) { laserTracker.resetSession(); Serial.println(F("[WebServer] Session zurueckgesetzt")); request->send(200, "text/html; charset=utf-8", "" "" "" "

✓ Session gelöscht

" "

Weiterleitung …

" ""); }); // 404 _server.onNotFound([](AsyncWebServerRequest* request) { request->send(404, "text/plain", "Not found"); }); } // ----------------------------------------------------------------------------- // buildStatusPage() // ----------------------------------------------------------------------------- String WebServerManager::buildStatusPage() { const Settings& s = settings.get(); String mqttStatus = mqttClient.isConnected() ? "✓ verbunden" : "✗ getrennt"; String laserStatus = laserTracker.isActive() ? "aktiv" : "inaktiv"; String ip = WiFi.isConnected() ? WiFi.localIP().toString() : "nicht verbunden"; // Gesamtzeit formatieren char totalBuf[16]; snprintf(totalBuf, sizeof(totalBuf), "%.2f", laserTracker.getTotalMinutes()); String html = F( "" "" "" "LaserCutter Display" "" "" "

LaserCutter Display

" "" "" "" "" "" "" "" "" "" "
Summe Session%ALLSESSIONS% min
Maschinenlaufzeit (gesamt)%TOTAL% min
Letzte Laserzeit%LASTSESSION% s
Laser%LASER%
IP-Adresse%IP%
MQTT%MQTT%
Broker%BROKER%:%PORT%
Gratiszeit%GRATIS% s
" "
" "" "
" "  " "" "  " "" "" "" ); html.replace("%ALLSESSIONS%", String(laserTracker.getAllSessionsSumMinutes())); html.replace("%TOTAL%", String(totalBuf)); html.replace("%LASTSESSION%", String(laserTracker.getLastSessionSeconds())); html.replace("%LASER%", laserStatus); html.replace("%IP%", ip); html.replace("%MQTT%", mqttStatus); html.replace("%BROKER%", String(s.mqttBroker)); html.replace("%PORT%", String(s.mqttPort)); html.replace("%GRATIS%", String(s.gratisSeconds)); return html; } // ----------------------------------------------------------------------------- // buildConfigPage() // ----------------------------------------------------------------------------- String WebServerManager::buildConfigPage() { const Settings& s = settings.get(); String html = F( "" "" "" "Konfiguration – LaserCutter Display" "" "" "

Konfiguration

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "
" "" "

" "" "" ); html.replace("%BROKER%", String(s.mqttBroker)); html.replace("%PORT%", String(s.mqttPort)); html.replace("%USER%", String(s.mqttUser)); html.replace("%PASSWORD%", String(s.mqttPassword)); html.replace("%GRATIS%", String(s.gratisSeconds)); html.replace("%POL_LOW%", s.signalPolarity == 0 ? "checked" : ""); html.replace("%POL_HIGH%", s.signalPolarity == 1 ? "checked" : ""); return html; }