From f6d5cba1fbac9c72d8d9b3bf4e796e14ec6ead60 Mon Sep 17 00:00:00 2001 From: M-Factory Date: Thu, 13 Nov 2025 22:52:43 +0900 Subject: [PATCH] Added /factory_reset endpoint /factory_reset to delete all time and config data, available only thru in AP mode: 192.168.4.1/factory_reset --- ESPTimeCast_ESP32/ESPTimeCast_ESP32.ino | 97 ++++++++++++++++++++- ESPTimeCast_ESP8266/ESPTimeCast_ESP8266.ino | 97 ++++++++++++++++++++- 2 files changed, 190 insertions(+), 4 deletions(-) diff --git a/ESPTimeCast_ESP32/ESPTimeCast_ESP32.ino b/ESPTimeCast_ESP32/ESPTimeCast_ESP32.ino index 43d366e..fac5a49 100644 --- a/ESPTimeCast_ESP32/ESPTimeCast_ESP32.ino +++ b/ESPTimeCast_ESP32/ESPTimeCast_ESP32.ino @@ -1481,6 +1481,93 @@ void setupWebServer() { if (final) f.close(); // finish file }); + server.on("/factory_reset", HTTP_GET, [](AsyncWebServerRequest *request) { + // If not in AP mode, block and return a 403 response + if (!isAPMode) { + request->send(403, "text/plain", "Factory reset only allowed in AP mode."); + Serial.println(F("[RESET] Factory reset attempt blocked (not in AP mode).")); + return; + } + const char *FACTORY_RESET_HTML = R"rawliteral( + + + + + + Resetting Device + + + +

Factory Reset Initiated

+

All saved configuration and Wi-Fi credentials are now being erased.

+
+

⚠️ ACTION REQUIRED

+

+ The device is rebooting and will be temporarily offline for about 45 seconds. +

+ Your browser will disconnect automatically. +

+

+ Next steps: +
1. Wait about 45 seconds for the reboot to finish.
+ 2. Reconnect your PC or phone to the Wi-Fi network: ESPTimeCast.
+ 3. Open your browser and go to 192.168.4.1 to continue setup. +

+ + + )rawliteral"; + request->send(200, "text/html", FACTORY_RESET_HTML); + Serial.println(F("[RESET] Factory reset requested, initiating cleanup...")); + + // Use onDisconnect() to ensure the HTTP response is fully sent before the disruptive actions + request->onDisconnect([]() { + // Small delay to ensure the response buffer is flushed before file ops + delay(500); + + // --- Remove configuration and uptime files --- + const char *filesToRemove[] = { "/config.json", "/uptime.dat" }; + for (auto &file : filesToRemove) { + if (LittleFS.exists(file)) { + if (LittleFS.remove(file)) { + Serial.printf("[RESET] Deleted %s\n", file); + } else { + Serial.printf("[RESET] ERROR deleting %s\n", file); + } + } else { + Serial.printf("[RESET] %s not found, skipping delete.\n", file); + } + } + +// --- Clear Wi-Fi credentials --- +#if defined(ESP8266) + WiFi.disconnect(true); // true = wipe credentials +#elif defined(ESP32) + WiFi.disconnect(true, true); // (erase=true, wifioff=true) +#endif + + Serial.println(F("[RESET] Factory defaults restored. Rebooting...")); + delay(500); + ESP.restart(); + }); + }); + server.on("/generate_204", HTTP_GET, handleCaptivePortal); // Android server.on("/fwlink", HTTP_GET, handleCaptivePortal); // Windows server.on("/hotspot-detect.html", HTTP_GET, handleCaptivePortal); // iOS/macOS @@ -1491,8 +1578,14 @@ void setupWebServer() { void handleCaptivePortal(AsyncWebServerRequest *request) { - Serial.print(F("[WEBSERVER] Captive Portal triggered for URL: ")); - Serial.println(request->url()); + String uri = request->url(); + + // Filter out system-generated probe requests + if (!uri.endsWith("/204") && !uri.endsWith("/ipv6check") && !uri.endsWith("connecttest.txt") && !uri.endsWith("/generate_204") && !uri.endsWith("/fwlink") && !uri.endsWith("/hotspot-detect.html")) { + + Serial.print(F("[WEBSERVER] Captive Portal triggered for URL: ")); + Serial.println(uri); + } if (isAPMode) { IPAddress apIP = WiFi.softAPIP(); diff --git a/ESPTimeCast_ESP8266/ESPTimeCast_ESP8266.ino b/ESPTimeCast_ESP8266/ESPTimeCast_ESP8266.ino index d42b5ff..17abde2 100644 --- a/ESPTimeCast_ESP8266/ESPTimeCast_ESP8266.ino +++ b/ESPTimeCast_ESP8266/ESPTimeCast_ESP8266.ino @@ -1477,6 +1477,93 @@ void setupWebServer() { if (final) f.close(); // finish file }); + server.on("/factory_reset", HTTP_GET, [](AsyncWebServerRequest *request) { + // If not in AP mode, block and return a 403 response + if (!isAPMode) { + request->send(403, "text/plain", "Factory reset only allowed in AP mode."); + Serial.println(F("[RESET] Factory reset attempt blocked (not in AP mode).")); + return; + } + const char *FACTORY_RESET_HTML = R"rawliteral( + + + + + + Resetting Device + + + +

Factory Reset Initiated

+

All saved configuration and Wi-Fi credentials are now being erased.

+
+

⚠️ ACTION REQUIRED

+

+ The device is rebooting and will be temporarily offline for about 45 seconds. +

+ Your browser will disconnect automatically. +

+

+ Next steps: +
1. Wait about 45 seconds for the reboot to finish.
+ 2. Reconnect your PC or phone to the Wi-Fi network: ESPTimeCast.
+ 3. Open your browser and go to 192.168.4.1 to continue setup. +

+ + + )rawliteral"; + request->send(200, "text/html", FACTORY_RESET_HTML); + Serial.println(F("[RESET] Factory reset requested, initiating cleanup...")); + + // Use onDisconnect() to ensure the HTTP response is fully sent before the disruptive actions + request->onDisconnect([]() { + // Small delay to ensure the response buffer is flushed before file ops + delay(500); + + // --- Remove configuration and uptime files --- + const char *filesToRemove[] = { "/config.json", "/uptime.dat" }; + for (auto &file : filesToRemove) { + if (LittleFS.exists(file)) { + if (LittleFS.remove(file)) { + Serial.printf("[RESET] Deleted %s\n", file); + } else { + Serial.printf("[RESET] ERROR deleting %s\n", file); + } + } else { + Serial.printf("[RESET] %s not found, skipping delete.\n", file); + } + } + +// --- Clear Wi-Fi credentials --- +#if defined(ESP8266) + WiFi.disconnect(true); // true = wipe credentials +#elif defined(ESP32) + WiFi.disconnect(true, true); // (erase=true, wifioff=true) +#endif + + Serial.println(F("[RESET] Factory defaults restored. Rebooting...")); + delay(500); + ESP.restart(); + }); + }); + server.on("/generate_204", HTTP_GET, handleCaptivePortal); // Android server.on("/fwlink", HTTP_GET, handleCaptivePortal); // Windows server.on("/hotspot-detect.html", HTTP_GET, handleCaptivePortal); // iOS/macOS @@ -1486,8 +1573,14 @@ void setupWebServer() { } void handleCaptivePortal(AsyncWebServerRequest *request) { - Serial.print(F("[WEBSERVER] Captive Portal triggered for URL: ")); - Serial.println(request->url()); + String uri = request->url(); + + // Filter out system-generated probe requests + if (!uri.endsWith("/204") && !uri.endsWith("/ipv6check") && !uri.endsWith("connecttest.txt") && !uri.endsWith("/generate_204") && !uri.endsWith("/fwlink") && !uri.endsWith("/hotspot-detect.html")) { + + Serial.print(F("[WEBSERVER] Captive Portal triggered for URL: ")); + Serial.println(uri); + } if (isAPMode) { IPAddress apIP = WiFi.softAPIP();