#include "Arduino.h" #include #include #include #include #include #include #include "States.h" #include "Commands.h" #include "HtmlPages.h" #include "LEDStripManager.h" AppState state = STATE_BOOT; #define LED_COUNT 12 // Nbr of LEDs on stripe TODO: move to eeprom, configurable over wifi unsigned long connectStart = 0; const byte DNS_PORT = 53; // WLAN Config struct Config { char ssid[32]; char pass[64]; bool valid; }; // AP Daten const char *ap_ssid = "Wemos_Setup"; const char *ap_pass = "admin123"; ESP8266WebServer webServer(80); WebSocketsServer webSocket(81); DNSServer dnsServer; LEDStripManager ledMngr(LED_COUNT, LED_STRIP_DATA_PIN); Config config; // ---------- EEPROM ---------- //TODO: move to onw class void saveConfig() { EEPROM.begin(sizeof(Config)); EEPROM.put(0, config); EEPROM.commit(); } void loadConfig() { EEPROM.begin(sizeof(Config)); EEPROM.get(0, config); if (config.valid != true) { config.valid = false; } } // ---------- CAPTIVE PORTAL PAGE ---------- void handleSetupPage() { String mac = WiFi.macAddress(); String html = getSetupPage(mac); webServer.send(200, "text/html", html); } // ---------- Wemos Control PAGE ---------- void handleSTAControlPage() { String mac = WiFi.macAddress(); String html = getSTAControlPage(mac); webServer.send(200, "text/html", html); } // ---------- SAVE ---------- void handleSave() { String ssid = webServer.arg("ssid"); String pass = webServer.arg("pass"); ssid.toCharArray(config.ssid, 32); pass.toCharArray(config.pass, 64); config.valid = true; saveConfig(); webServer.send(200, "text/html", getConnectionSuccessPage()); delay(1500); ESP.restart(); } // ---------- NOT FOUND (CAPTIVE REDIRECT) ---------- void handleNotFound() { webServer.sendHeader("Location", "http://192.168.4.1/", true); webServer.send(302, "text/plain", ""); } // ---------- START ACCESS POINT ---------- void startAP() { WiFi.mode(WIFI_AP); WiFi.softAP(ap_ssid, ap_pass); delay(500); IPAddress apIP = WiFi.softAPIP(); Serial.print("AP IP: "); Serial.println(apIP); // DNS: ALLE Domains auf ESP IP umleiten dnsServer.start(DNS_PORT, "*", apIP); // Webserver Routes webServer.on("/", handleSetupPage); webServer.on("/save", HTTP_POST, handleSave); webServer.onNotFound(handleNotFound); webServer.begin(); Serial.println("Captive Portal gestartet"); } void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) { switch (type) { case WStype_CONNECTED: { IPAddress ip = webSocket.remoteIP(num); Serial.printf("WS Client %u verbunden von %d.%d.%d.%d\n", num, ip[0], ip[1], ip[2], ip[3]); webSocket.sendTXT(num, "Connected"); if (digitalRead(LED_STRIP_POWER_PIN) == HIGH) { webSocket.sendTXT(num, "LED ON"); } else { webSocket.sendTXT(num, "LED OFF"); } break; } case WStype_DISCONNECTED: Serial.printf("WS Client %u getrennt\n", num); break; case WStype_TEXT: { String msg = String((char*) payload); Serial.print("WS empfangen: "); Serial.println(msg); JsonDocument doc; deserializeJson(doc, msg); const char *cmd = doc["cmd"]; if (strToCommand(cmd) == CMD_SWITCH_LED) { const char *value = doc["val"]; if (strcmp(value, "on") == 0) { Serial.println("LED ON"); ledMngr.on(); delay(20); if (digitalRead(LED_STRIP_POWER_PIN) == HIGH) { webSocket.sendTXT(num, "LED ON"); } } else if (strcmp(value, "off") == 0) { Serial.println("LED OFF"); ledMngr.off(); delay(20); if (digitalRead(LED_STRIP_POWER_PIN) == LOW) { webSocket.sendTXT(num, "LED OFF"); } } } else if (strToCommand(cmd) == CMD_RESET_WIFI_CFG) { resetWifiConfiguration(num); } else { String s = "ACK UNKNOWN: " + msg; webSocket.sendTXT(num, s); } break; } default: break; } } void resetWifiConfiguration(uint8_t num) { EEPROM.begin(sizeof(Config)); config.valid = false; EEPROM.put(0, config); webSocket.sendTXT(num, "Wifi_Reset_Success"); delay(200); EEPROM.commit(); ESP.restart(); } void setState(AppState newState) { Serial.printf("STATE %s -> %s\n", stateToString(state), stateToString(newState)); state = newState; } void handleBoot() { if (config.valid) { WiFi.mode(WIFI_STA); WiFi.begin(config.ssid, config.pass); setState(STATE_CONNECTING); } else { startAP(); setState(STATE_AP_MODE); } } void handleConnecting() { if (WiFi.status() == WL_CONNECTED) { startSTAWebServer(); setState(STATE_STA_MODE); return; } if (millis() - connectStart > 10000) { Serial.println("Connect Timeout"); startAP(); setState(STATE_AP_MODE); } } void handleAPMode() { dnsServer.processNextRequest(); webServer.handleClient(); } void handleSTAMode() { webServer.handleClient(); webSocket.loop(); if (WiFi.status() != WL_CONNECTED) { Serial.println("WLAN verloren"); WiFi.begin(config.ssid, config.pass); connectStart = millis(); setState(STATE_CONNECTING); } } void handleError() { ledMngr.off(); } void startSTAWebServer() { Serial.println("Starte STA Services"); // Webseite webServer.on("/", handleSTAControlPage); // optional webServer.on("/save", HTTP_POST, handleSave); webServer.begin(); // WebSocket webSocket.begin(); webSocket.onEvent(webSocketEvent); Serial.print("HTTP Server: http://"); Serial.println(WiFi.localIP()); Serial.print("WebSocket: ws://"); Serial.print(WiFi.localIP()); Serial.println(":81/"); } // ---------- SETUP ---------- void setup() { Serial.begin(115200); ledMngr.begin(); loadConfig(); setState(STATE_BOOT); connectStart = millis(); } // ---------- LOOP ---------- void loop() { switch (state) { case STATE_BOOT: handleBoot(); break; case STATE_AP_MODE: handleAPMode(); break; case STATE_CONNECTING: handleConnecting(); break; case STATE_STA_MODE: handleSTAMode(); break; case STATE_ERROR: handleError(); break; } }