Refactor to use ESPAsyncWebServer instead of ESP8266WebServer/WebServer

- Replace ESP8266WebServer/WebServer with ESPAsyncWebServer
- Update all route handlers to async pattern with AsyncWebServerRequest*
- Replace synchronous HTTPSend() with request->send()
- Add configurable delay constants (REBOOT_DELAY_MS, EXIT_DELAY_MS, ERASE_REBOOT_DELAY_MS)
- Implement scheduled reboot/abort flags instead of blocking delays
- Update WiFiManagerRequestArgs to use AsyncWebServerRequest
- Remove server->handleClient() and server->stop() calls (not needed for AsyncWebServer)
- Update parameter access to use request->getParam() instead of server->arg()
- Add ESPAsyncWebServer to platformio.ini dependencies
This commit is contained in:
2025-11-04 22:51:22 +10:00
parent c2e1e7f95c
commit d62f680132
3 changed files with 354 additions and 332 deletions
+40 -48
View File
@@ -61,7 +61,7 @@
// #define esp32autoreconnect // implement esp32 autoreconnect event listener kludge, @DEPRECATED // #define esp32autoreconnect // implement esp32 autoreconnect event listener kludge, @DEPRECATED
// autoreconnect is WORKING https://github.com/espressif/arduino-esp32/issues/653#issuecomment-405604766 // autoreconnect is WORKING https://github.com/espressif/arduino-esp32/issues/653#issuecomment-405604766
#define WM_WEBSERVERSHIM // use webserver shim lib // WM_WEBSERVERSHIM no longer needed - using ESPAsyncWebServer
#define WM_G(string_literal) (String(FPSTR(string_literal)).c_str()) #define WM_G(string_literal) (String(FPSTR(string_literal)).c_str())
@@ -71,7 +71,7 @@
#include "user_interface.h" #include "user_interface.h"
} }
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266WebServer.h> #include <ESPAsyncTCP.h>
#ifdef WM_MDNS #ifdef WM_MDNS
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
@@ -85,20 +85,11 @@
#include <WiFi.h> #include <WiFi.h>
#include <esp_wifi.h> #include <esp_wifi.h>
#include <Update.h> #include <Update.h>
#include <AsyncTCP.h>
#define WIFI_getChipId() (uint32_t)ESP.getEfuseMac() #define WIFI_getChipId() (uint32_t)ESP.getEfuseMac()
#define WM_WIFIOPEN WIFI_AUTH_OPEN #define WM_WIFIOPEN WIFI_AUTH_OPEN
#ifndef WEBSERVER_H
#ifdef WM_WEBSERVERSHIM
#include <WebServer.h>
#else
#include <ESP8266WebServer.h>
// Forthcoming official ? probably never happening
// https://github.com/esp8266/ESPWebServer
#endif
#endif
#ifdef WM_ERASE_NVS #ifdef WM_ERASE_NVS
#include <nvs.h> #include <nvs.h>
#include <nvs_flash.h> #include <nvs_flash.h>
@@ -130,6 +121,7 @@
#endif #endif
#include <DNSServer.h> #include <DNSServer.h>
#include <ESPAsyncWebServer.h>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@@ -512,32 +504,26 @@ class WiFiManager
std::unique_ptr<DNSServer> dnsServer; std::unique_ptr<DNSServer> dnsServer;
std::unique_ptr<AsyncWebServer> server;
#if defined(ESP32) && defined(WM_WEBSERVERSHIM)
using WM_WebServer = WebServer;
#else
using WM_WebServer = ESP8266WebServer;
#endif
std::unique_ptr<WM_WebServer> server;
public: public:
// Define WiFiManagerRequestArgs here after WM_WebServer is available // Define WiFiManagerRequestArgs here after AsyncWebServer is available
class WiFiManagerRequestArgs { class WiFiManagerRequestArgs {
public: public:
std::unordered_map<std::string, std::string> args; std::unordered_map<std::string, std::string> args;
// Constructor - builds from WM_WebServer (ESP8266WebServer or WebServer) // Constructor - builds from AsyncWebServerRequest
WiFiManagerRequestArgs(WM_WebServer* server) { WiFiManagerRequestArgs(AsyncWebServerRequest* request) {
if (server) { if (request) {
for (uint8_t i = 0; i < server->args(); i++) { size_t paramCount = request->params();
String argName = server->argName(i); for (size_t i = 0; i < paramCount; i++) {
String argValue = server->arg(i); const AsyncWebParameter* p = request->getParam(i);
args[std::string(argName.c_str())] = std::string(argValue.c_str()); args[std::string(p->name().c_str())] = std::string(p->value().c_str());
} }
} }
} }
// Legacy constructor for backward compatibility (if needed during transition)
WiFiManagerRequestArgs() {} WiFiManagerRequestArgs() {}
// Check if argument exists // Check if argument exists
@@ -609,8 +595,17 @@ class WiFiManager
unsigned long _startscan = 0; // ms for timing wifi scans unsigned long _startscan = 0; // ms for timing wifi scans
unsigned long _startconn = 0; // ms for timing wifi connects unsigned long _startconn = 0; // ms for timing wifi connects
// async reboot/abort scheduling
bool _rebootScheduled = false; // flag for scheduled reboot
unsigned long _rebootTime = 0; // ms when reboot should occur
bool _abortScheduled = false; // flag for scheduled abort
unsigned long _abortTime = 0; // ms when abort should occur
// defaults // defaults
const uint8_t DNS_PORT = 53; const uint8_t DNS_PORT = 53;
const unsigned long REBOOT_DELAY_MS = 1000; // delay before reboot after response sent
const unsigned long EXIT_DELAY_MS = 2000; // delay before abort after response sent
const unsigned long ERASE_REBOOT_DELAY_MS = 2000; // delay before reboot after erase response sent
String _apName = "no-net"; String _apName = "no-net";
String _apPassword = ""; String _apPassword = "";
String _ssid = ""; // var temp ssid String _ssid = ""; // var temp ssid
@@ -742,33 +737,30 @@ protected:
// webserver handlers // webserver handlers
public: public:
void handleNotFound(); void handleNotFound(AsyncWebServerRequest *request);
protected: protected:
void HTTPSend(const String &content); void handleRoot(AsyncWebServerRequest *request);
void handleRoot(); void handleWifi(AsyncWebServerRequest *request, boolean scan);
void handleWifi(boolean scan); void handleWifiSave(AsyncWebServerRequest *request);
void handleWifiSave(); void handleInfo(AsyncWebServerRequest *request);
void handleInfo(); void handleReset(AsyncWebServerRequest *request);
void handleReset(); void handleExit(AsyncWebServerRequest *request);
void handleClose(AsyncWebServerRequest *request);
void handleExit(); void handleErase(AsyncWebServerRequest *request, boolean opt);
void handleClose(); void handleParam(AsyncWebServerRequest *request);
// void handleErase(); void handleWiFiStatus(AsyncWebServerRequest *request);
void handleErase(boolean opt); void handleRequest(AsyncWebServerRequest *request);
void handleParam(); void handleParamSave(AsyncWebServerRequest *request);
void handleWiFiStatus();
void handleRequest();
void handleParamSave();
void doParamSave(WiFiManagerRequestArgs requestArgs); void doParamSave(WiFiManagerRequestArgs requestArgs);
boolean captivePortal(); boolean captivePortal(AsyncWebServerRequest *request);
boolean configPortalHasTimeout(); boolean configPortalHasTimeout();
uint8_t processConfigPortal(); uint8_t processConfigPortal();
void stopCaptivePortal(); void stopCaptivePortal();
// OTA Update handler // OTA Update handler
void handleUpdate(); void handleUpdate(AsyncWebServerRequest *request);
void handleUpdating(); void handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
void handleUpdateDone(); void handleUpdateDone(AsyncWebServerRequest *request);
// wifi platform abstractions // wifi platform abstractions
+253 -227
View File
@@ -627,8 +627,7 @@ void WiFiManager::setupHTTPServer(){
#endif #endif
} }
server.reset(new WM_WebServer(_httpPort)); server.reset(new AsyncWebServer(_httpPort));
// This is not the safest way to reset the webserver, it can cause crashes on callbacks initilized before this and since its a shared pointer...
if ( _webservercallback != NULL) { if ( _webservercallback != NULL) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
@@ -636,27 +635,76 @@ void WiFiManager::setupHTTPServer(){
#endif #endif
_webservercallback(); // @CALLBACK _webservercallback(); // @CALLBACK
} }
// @todo add a new callback maybe, after webserver started, callback cannot override handlers, but can grab them first
/* Setup httpd callbacks, web pages: root, wifi config pages, SO captive portal detectors and not found. */ /* Setup httpd callbacks, web pages: root, wifi config pages, SO captive portal detectors and not found. */
// G macro workaround for Uri() bug https://github.com/esp8266/Arduino/issues/7102 // Register routes with lambdas
server->on(WM_G(R_root), std::bind(&WiFiManager::handleRoot, this)); server->on(WM_G(R_root), HTTP_GET, [this](AsyncWebServerRequest *request) {
server->on(WM_G(R_wifi), std::bind(&WiFiManager::handleWifi, this, true)); this->handleRoot(request);
server->on(WM_G(R_wifinoscan), std::bind(&WiFiManager::handleWifi, this, false)); });
server->on(WM_G(R_wifisave), std::bind(&WiFiManager::handleWifiSave, this));
server->on(WM_G(R_info), std::bind(&WiFiManager::handleInfo, this));
server->on(WM_G(R_param), std::bind(&WiFiManager::handleParam, this));
server->on(WM_G(R_paramsave), std::bind(&WiFiManager::handleParamSave, this));
server->on(WM_G(R_restart), std::bind(&WiFiManager::handleReset, this));
server->on(WM_G(R_exit), std::bind(&WiFiManager::handleExit, this));
server->on(WM_G(R_close), std::bind(&WiFiManager::handleClose, this));
server->on(WM_G(R_erase), std::bind(&WiFiManager::handleErase, this, false));
server->on(WM_G(R_status), std::bind(&WiFiManager::handleWiFiStatus, this));
server->onNotFound (std::bind(&WiFiManager::handleNotFound, this));
server->on(WM_G(R_update), std::bind(&WiFiManager::handleUpdate, this)); server->on(WM_G(R_wifi), HTTP_GET, [this](AsyncWebServerRequest *request) {
server->on(WM_G(R_updatedone), HTTP_POST, std::bind(&WiFiManager::handleUpdateDone, this), std::bind(&WiFiManager::handleUpdating, this)); this->handleWifi(request, true);
});
server->on(WM_G(R_wifinoscan), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleWifi(request, false);
});
server->on(WM_G(R_wifisave), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->handleWifiSave(request);
});
server->on(WM_G(R_info), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleInfo(request);
});
server->on(WM_G(R_param), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleParam(request);
});
server->on(WM_G(R_paramsave), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->handleParamSave(request);
});
server->on(WM_G(R_restart), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleReset(request);
});
server->on(WM_G(R_exit), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleExit(request);
});
server->on(WM_G(R_close), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleClose(request);
});
server->on(WM_G(R_erase), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleErase(request, false);
});
server->on(WM_G(R_status), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleWiFiStatus(request);
});
// OTA Update routes
server->on(WM_G(R_update), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->handleUpdate(request);
});
server->on(WM_G(R_updatedone), HTTP_POST,
[this](AsyncWebServerRequest *request) {
this->handleUpdateDone(request);
},
[this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
this->handleUpdating(request, filename, index, data, len, final);
}
);
// 404 handler
server->onNotFound([this](AsyncWebServerRequest *request) {
this->handleNotFound(request);
});
server->begin(); // Web server start server->begin(); // Web server start
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
@@ -827,6 +875,19 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo
* @return bool connected * @return bool connected
*/ */
boolean WiFiManager::process(){ boolean WiFiManager::process(){
// Check for scheduled reboots
if (_rebootScheduled && millis() >= _rebootTime) {
_rebootScheduled = false;
reboot();
return false;
}
// Check for scheduled aborts
if (_abortScheduled && millis() >= _abortTime) {
_abortScheduled = false;
abort = true;
}
// process mdns, esp32 not required // process mdns, esp32 not required
#if defined(WM_MDNS) && defined(ESP8266) #if defined(WM_MDNS) && defined(ESP8266)
MDNS.update(); MDNS.update();
@@ -868,8 +929,7 @@ uint8_t WiFiManager::processConfigPortal(){
dnsServer->processNextRequest(); dnsServer->processNextRequest();
} }
//HTTP handler //HTTP handler - AsyncWebServer handles clients automatically, no need to call handleClient()
server->handleClient();
// Waiting for save... // Waiting for save...
if(connect) { if(connect) {
@@ -966,12 +1026,11 @@ bool WiFiManager::shutdownConfigPortal(){
dnsServer->processNextRequest(); dnsServer->processNextRequest();
} }
//HTTP handler //HTTP handler - AsyncWebServer handles clients automatically, no need to call handleClient()
server->handleClient();
// @todo what is the proper way to shutdown and free the server up // @todo what is the proper way to shutdown and free the server up
// debug - many open issues aobut port not clearing for use with other servers // debug - many open issues aobut port not clearing for use with other servers
server->stop(); // AsyncWebServer doesn't have stop(), just reset the unique_ptr
server.reset(); server.reset();
WiFi.scanDelete(); // free wifi scan results WiFi.scanDelete(); // free wifi scan results
@@ -1307,46 +1366,29 @@ String WiFiManager::getHTTPEnd() {
return end; return end;
} }
void WiFiManager::HTTPSend(const String &content){
server->send(200, FPSTR(HTTP_HEAD_CT), content);
}
/** /**
* HTTPD handler for page requests * HTTPD handler for page requests
*/ */
void WiFiManager::handleRequest() { void WiFiManager::handleRequest(AsyncWebServerRequest *request) {
_webPortalAccessed = millis(); _webPortalAccessed = millis();
// TESTING HTTPD AUTH RFC 2617 // TESTING HTTPD AUTH RFC 2617
// BASIC_AUTH will hold onto creds, hard to "logout", but convienent // Note: ESPAsyncWebServer has different auth mechanisms
// DIGEST_AUTH will require new auth often, and nonce is random // May need to implement custom middleware for auth
// bool authenticate(const char * username, const char * password); // For now, auth is commented out as in original
// bool authenticateDigest(const String& username, const String& H1);
// void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );
// 2.3 NO AUTH available // Auth handling would go here if needed
bool testauth = false;
if(!testauth) return;
DEBUG_WM(WM_DEBUG_DEV,F("DOING AUTH"));
bool res = server->authenticate("admin","12345");
if(!res){
#ifndef WM_NOAUTH
server->requestAuthentication(HTTPAuthMethod::BASIC_AUTH); // DIGEST_AUTH
#endif
DEBUG_WM(WM_DEBUG_DEV,F("AUTH FAIL"));
}
} }
/** /**
* HTTPD CALLBACK root or redirect to captive portal * HTTPD CALLBACK root or redirect to captive portal
*/ */
void WiFiManager::handleRoot() { void WiFiManager::handleRoot(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Root")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Root"));
#endif #endif
if (captivePortal()) return; // If captive portal redirect instead of displaying the page if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page
handleRequest(); handleRequest(request);
String page = getHTTPHead(_title, FPSTR(C_root)); // @token options @todo replace options with title String page = getHTTPHead(_title, FPSTR(C_root)); // @token options @todo replace options with title
String str = FPSTR(HTTP_ROOT_MAIN); // @todo custom title String str = FPSTR(HTTP_ROOT_MAIN); // @todo custom title
str.replace(FPSTR(T_t), _title); str.replace(FPSTR(T_t), _title);
@@ -1357,7 +1399,7 @@ void WiFiManager::handleRoot() {
reportStatus(page); reportStatus(page);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
if(_preloadwifiscan) WiFi_scanNetworks(_scancachetime, true); // preload wifiscan throttled, async if(_preloadwifiscan) WiFi_scanNetworks(_scancachetime, true); // preload wifiscan throttled, async
// @todo buggy, captive portals make a query on every page load, causing this to run every time in addition to the real page load // @todo buggy, captive portals make a query on every page load, causing this to run every time in addition to the real page load
// I dont understand why, when you are already in the captive portal, I guess they want to know that its still up and not done or gone // I dont understand why, when you are already in the captive portal, I guess they want to know that its still up and not done or gone
@@ -1367,17 +1409,19 @@ void WiFiManager::handleRoot() {
/** /**
* HTTPD CALLBACK Wifi config page handler * HTTPD CALLBACK Wifi config page handler
*/ */
void WiFiManager::handleWifi(boolean scan) { void WiFiManager::handleWifi(AsyncWebServerRequest *request, boolean scan) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Wifi")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Wifi"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titlewifi), FPSTR(C_wifi)); // @token titlewifi String page = getHTTPHead(FPSTR(S_titlewifi), FPSTR(C_wifi)); // @token titlewifi
if (scan) { if (scan) {
#ifdef WM_DEBUG_LEVEL // Check if refresh is requested
// DEBUG_WM(WM_DEBUG_DEV,"refresh flag:",server->hasArg(F("refresh"))); bool forceRefresh = false;
#endif if (request->hasParam("refresh")) {
WiFi_scanNetworks(server->hasArg(F("refresh")),false); //wifiscan, force if arg refresh forceRefresh = true;
}
WiFi_scanNetworks(forceRefresh, false); //wifiscan, force if arg refresh
page += getScanItemOut(); page += getScanItemOut();
} }
String pitem = ""; String pitem = "";
@@ -1413,7 +1457,7 @@ void WiFiManager::handleWifi(boolean scan) {
reportStatus(page); reportStatus(page);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("Sent config page")); DEBUG_WM(WM_DEBUG_DEV, F("Sent config page"));
@@ -1423,11 +1467,11 @@ void WiFiManager::handleWifi(boolean scan) {
/** /**
* HTTPD CALLBACK Wifi param page handler * HTTPD CALLBACK Wifi param page handler
*/ */
void WiFiManager::handleParam(){ void WiFiManager::handleParam(AsyncWebServerRequest *request){
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titleparam), FPSTR(C_param)); // @token titlewifi String page = getHTTPHead(FPSTR(S_titleparam), FPSTR(C_param)); // @token titlewifi
String pitem = ""; String pitem = "";
@@ -1442,7 +1486,7 @@ void WiFiManager::handleParam(){
reportStatus(page); reportStatus(page);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("Sent param page")); DEBUG_WM(WM_DEBUG_DEV, F("Sent param page"));
@@ -1803,35 +1847,39 @@ String WiFiManager::getParamOut(){
return page; return page;
} }
void WiFiManager::handleWiFiStatus(){ void WiFiManager::handleWiFiStatus(AsyncWebServerRequest *request){
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi status ")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi status "));
#endif #endif
handleRequest(); handleRequest(request);
String page; String page;
// String page = "{\"result\":true,\"count\":1}"; // String page = "{\"result\":true,\"count\":1}";
#ifdef WM_JSTEST #ifdef WM_JSTEST
page = FPSTR(HTTP_JS); page = FPSTR(HTTP_JS);
#endif #endif
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
} }
/** /**
* HTTPD CALLBACK save form and redirect to WLAN config page again * HTTPD CALLBACK save form and redirect to WLAN config page again
*/ */
void WiFiManager::handleWifiSave() { void WiFiManager::handleWifiSave(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi save ")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi save "));
DEBUG_WM(WM_DEBUG_DEV,F("Method:"),server->method() == HTTP_GET ? (String)FPSTR(S_GET) : (String)FPSTR(S_POST)); DEBUG_WM(WM_DEBUG_DEV, F("Method:"), request->method() == HTTP_GET ? FPSTR(S_GET) : FPSTR(S_POST));
#endif #endif
handleRequest(); handleRequest(request);
// BUILD REQUEST ARGS STRUCT EARLY - captures all arguments while request is active // BUILD REQUEST ARGS STRUCT EARLY - captures all arguments while request is active
WiFiManagerRequestArgs requestArgs(server.get()); WiFiManagerRequestArgs requestArgs(request);
//SAVE/connect here //SAVE/connect here
_ssid = server->arg(F("s")).c_str(); if (request->hasParam("s", true)) {
_pass = server->arg(F("p")).c_str(); _ssid = request->getParam("s", true)->value().c_str();
}
if (request->hasParam("p", true)) {
_pass = request->getParam("p", true)->value().c_str();
}
if(_ssid == "" && _pass != ""){ if(_ssid == "" && _pass != ""){
_ssid = WiFi_SSID(true); // password change, placeholder ssid, @todo compare pass to old?, confirm ssid is clean _ssid = WiFi_SSID(true); // password change, placeholder ssid, @todo compare pass to old?, confirm ssid is clean
@@ -1843,44 +1891,44 @@ void WiFiManager::handleWifiSave() {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
String requestinfo = "SERVER_REQUEST\n----------------\n"; String requestinfo = "SERVER_REQUEST\n----------------\n";
requestinfo += "URI: "; requestinfo += "URI: ";
requestinfo += server->uri(); requestinfo += request->url();
requestinfo += "\nMethod: "; requestinfo += "\nMethod: ";
requestinfo += (server->method() == HTTP_GET) ? "GET" : "POST"; requestinfo += (request->method() == HTTP_GET) ? "GET" : "POST";
requestinfo += "\nArguments: "; requestinfo += "\nArguments: ";
requestinfo += server->args(); requestinfo += request->params();
requestinfo += "\n"; requestinfo += "\n";
for (uint8_t i = 0; i < server->args(); i++) { for (size_t i = 0; i < request->params(); i++) {
requestinfo += " " + server->argName(i) + ": " + server->arg(i) + "\n"; const AsyncWebParameter* p = request->getParam(i);
requestinfo += " " + p->name() + ": " + p->value() + "\n";
} }
DEBUG_WM(WM_DEBUG_MAX, requestinfo); DEBUG_WM(WM_DEBUG_MAX, requestinfo);
#endif #endif
// set static ips from server args // set static ips from request args
if (server->arg(FPSTR(S_ip)) != "") { if (request->hasParam(FPSTR(S_ip), true)) {
//_sta_static_ip.fromString(server->arg(FPSTR(S_ip)); String ip = request->getParam(FPSTR(S_ip), true)->value();
String ip = server->arg(FPSTR(S_ip));
optionalIPFromString(&_sta_static_ip, ip.c_str()); optionalIPFromString(&_sta_static_ip, ip.c_str());
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("static ip:"), ip); DEBUG_WM(WM_DEBUG_DEV, F("static ip:"), ip);
#endif #endif
} }
if (server->arg(FPSTR(S_gw)) != "") { if (request->hasParam(FPSTR(S_gw), true)) {
String gw = server->arg(FPSTR(S_gw)); String gw = request->getParam(FPSTR(S_gw), true)->value();
optionalIPFromString(&_sta_static_gw, gw.c_str()); optionalIPFromString(&_sta_static_gw, gw.c_str());
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("static gateway:"), gw); DEBUG_WM(WM_DEBUG_DEV, F("static gateway:"), gw);
#endif #endif
} }
if (server->arg(FPSTR(S_sn)) != "") { if (request->hasParam(FPSTR(S_sn), true)) {
String sn = server->arg(FPSTR(S_sn)); String sn = request->getParam(FPSTR(S_sn), true)->value();
optionalIPFromString(&_sta_static_sn, sn.c_str()); optionalIPFromString(&_sta_static_sn, sn.c_str());
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("static netmask:"), sn); DEBUG_WM(WM_DEBUG_DEV, F("static netmask:"), sn);
#endif #endif
} }
if (server->arg(FPSTR(S_dns)) != "") { if (request->hasParam(FPSTR(S_dns), true)) {
String dns = server->arg(FPSTR(S_dns)); String dns = request->getParam(FPSTR(S_dns), true)->value();
optionalIPFromString(&_sta_static_dns, dns.c_str()); optionalIPFromString(&_sta_static_dns, dns.c_str());
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("static DNS:"), dns); DEBUG_WM(WM_DEBUG_DEV, F("static DNS:"), dns);
@@ -1907,8 +1955,9 @@ void WiFiManager::handleWifiSave() {
if(_showBack) page += FPSTR(HTTP_BACKBTN); if(_showBack) page += FPSTR(HTTP_BACKBTN);
page += getHTTPEnd(); page += getHTTPEnd();
server->sendHeader(FPSTR(HTTP_HEAD_CORS), FPSTR(HTTP_HEAD_CORS_ALLOW_ALL)); // @HTTPHEAD send cors AsyncWebServerResponse *response = request->beginResponse(200, FPSTR(HTTP_HEAD_CT), page);
HTTPSend(page); response->addHeader(FPSTR(HTTP_HEAD_CORS), FPSTR(HTTP_HEAD_CORS_ALLOW_ALL)); // @HTTPHEAD send cors
request->send(response);
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("Sent wifi save page")); DEBUG_WM(WM_DEBUG_DEV, F("Sent wifi save page"));
@@ -1917,18 +1966,18 @@ void WiFiManager::handleWifiSave() {
connect = true; //signal ready to connect/reset process in processConfigPortal connect = true; //signal ready to connect/reset process in processConfigPortal
} }
void WiFiManager::handleParamSave() { void WiFiManager::handleParamSave(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param save ")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param save "));
#endif #endif
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV,F("Method:"),server->method() == HTTP_GET ? (String)FPSTR(S_GET) : (String)FPSTR(S_POST)); DEBUG_WM(WM_DEBUG_DEV, F("Method:"), request->method() == HTTP_GET ? FPSTR(S_GET) : FPSTR(S_POST));
#endif #endif
handleRequest(); handleRequest(request);
// BUILD REQUEST ARGS STRUCT // BUILD REQUEST ARGS STRUCT
WiFiManagerRequestArgs requestArgs(server.get()); WiFiManagerRequestArgs requestArgs(request);
doParamSave(requestArgs); doParamSave(requestArgs);
@@ -1937,7 +1986,7 @@ void WiFiManager::handleParamSave() {
if(_showBack) page += FPSTR(HTTP_BACKBTN); if(_showBack) page += FPSTR(HTTP_BACKBTN);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("Sent param save page")); DEBUG_WM(WM_DEBUG_DEV, F("Sent param save page"));
@@ -1972,28 +2021,17 @@ void WiFiManager::doParamSave(WiFiManagerRequestArgs requestArgs){
// For custom HTML parameters, try to get from RequestArgs // For custom HTML parameters, try to get from RequestArgs
String name = (String)FPSTR(S_parampre)+(String)i; String name = (String)FPSTR(S_parampre)+(String)i;
// Try RequestArgs first
if (requestArgs.hasArg(name)) { if (requestArgs.hasArg(name)) {
value = requestArgs.getArg(name); value = requestArgs.getArg(name);
} else {
// Fallback to server for now (will be removed when DeviceFramework uses RequestArgs)
if(server->hasArg(name)) {
value = server->arg(name);
} else { } else {
continue; // Skip if not found continue; // Skip if not found
} }
}
} else { } else {
// Regular parameter - use existing logic // Regular parameter - use RequestArgs
String name = (String)FPSTR(S_parampre)+(String)i; String name = (String)FPSTR(S_parampre)+(String)i;
if(server->hasArg(name)) { if(requestArgs.hasArg(name)) {
value = server->arg(name); value = requestArgs.getArg(name);
} else { } else {
value = server->arg(_params[i]->getID());
}
// Also check RequestArgs as fallback for custom params that might share ID
if (value.length() == 0 && requestArgs.hasArg(_params[i]->getID())) {
value = requestArgs.getArg(_params[i]->getID()); value = requestArgs.getArg(_params[i]->getID());
} }
} }
@@ -2018,11 +2056,11 @@ void WiFiManager::doParamSave(WiFiManagerRequestArgs requestArgs){
/** /**
* HTTPD CALLBACK info page * HTTPD CALLBACK info page
*/ */
void WiFiManager::handleInfo() { void WiFiManager::handleInfo(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Info")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Info"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titleinfo), FPSTR(C_info)); // @token titleinfo String page = getHTTPHead(FPSTR(S_titleinfo), FPSTR(C_info)); // @token titleinfo
reportStatus(page); reportStatus(page);
@@ -2119,7 +2157,7 @@ void WiFiManager::handleInfo() {
page += FPSTR(HTTP_HELP); page += FPSTR(HTTP_HELP);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV, F("Sent info page")); DEBUG_WM(WM_DEBUG_DEV, F("Sent info page"));
@@ -2363,54 +2401,55 @@ String WiFiManager::getInfoData(String id){
/** /**
* HTTPD CALLBACK exit, closes configportal if blocking, if non blocking undefined * HTTPD CALLBACK exit, closes configportal if blocking, if non blocking undefined
*/ */
void WiFiManager::handleExit() { void WiFiManager::handleExit(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Exit")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Exit"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titleexit), FPSTR(C_exit)); // @token titleexit String page = getHTTPHead(FPSTR(S_titleexit), FPSTR(C_exit)); // @token titleexit
page += FPSTR(S_exiting); // @token exiting page += FPSTR(S_exiting); // @token exiting
page += getHTTPEnd(); page += getHTTPEnd();
// ('Logout', 401, {'WWW-Authenticate': 'Basic realm="Login required"'}) // ('Logout', 401, {'WWW-Authenticate': 'Basic realm="Login required"'})
server->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache AsyncWebServerResponse *response = request->beginResponse(200, FPSTR(HTTP_HEAD_CT), page);
HTTPSend(page); response->addHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache
delay(2000); request->send(response);
abort = true;
// Schedule abort after response is sent
_abortScheduled = true;
_abortTime = millis() + EXIT_DELAY_MS;
} }
/** /**
* HTTPD CALLBACK reset page * HTTPD CALLBACK reset page
*/ */
void WiFiManager::handleReset() { void WiFiManager::handleReset(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Reset")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Reset"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titlereset), FPSTR(C_restart)); //@token titlereset String page = getHTTPHead(FPSTR(S_titlereset), FPSTR(C_restart)); //@token titlereset
page += FPSTR(S_resetting); //@token resetting page += FPSTR(S_resetting); //@token resetting
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
// Schedule reboot after response is sent
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(F("RESETTING ESP")); DEBUG_WM(F("RESETTING ESP"));
#endif #endif
delay(1000); _rebootScheduled = true;
reboot(); _rebootTime = millis() + REBOOT_DELAY_MS;
} }
/** /**
* HTTPD CALLBACK erase page * HTTPD CALLBACK erase page
*/ */
// void WiFiManager::handleErase() { void WiFiManager::handleErase(AsyncWebServerRequest *request, boolean opt) {
// handleErase(false);
// }
void WiFiManager::handleErase(boolean opt) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_NOTIFY, F("<- HTTP Erase")); DEBUG_WM(WM_DEBUG_NOTIFY, F("<- HTTP Erase"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titleerase), FPSTR(C_erase)); // @token titleerase String page = getHTTPHead(FPSTR(S_titleerase), FPSTR(C_erase)); // @token titleerase
bool ret = erase(opt); bool ret = erase(opt);
@@ -2424,43 +2463,46 @@ void WiFiManager::handleErase(boolean opt) {
} }
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
if(ret){ if(ret){
delay(2000); // Schedule reboot after response is sent
_rebootScheduled = true;
_rebootTime = millis() + ERASE_REBOOT_DELAY_MS;
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(F("RESETTING ESP")); DEBUG_WM(F("RESETTING ESP"));
#endif #endif
reboot();
} }
} }
/** /**
* HTTPD CALLBACK 404 * HTTPD CALLBACK 404
*/ */
void WiFiManager::handleNotFound() { void WiFiManager::handleNotFound(AsyncWebServerRequest *request) {
if (captivePortal()) return; // If captive portal redirect instead of displaying the page if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page
handleRequest(); handleRequest(request);
String message = FPSTR(S_notfound); // @token notfound String message = FPSTR(S_notfound); // @token notfound
bool verbose404 = false; // show info in 404 body, uri,method, args bool verbose404 = false; // show info in 404 body, uri,method, args
if(verbose404){ if(verbose404){
message += FPSTR(S_uri); // @token uri message += FPSTR(S_uri); // @token uri
message += server->uri(); message += request->url();
message += FPSTR(S_method); // @token method message += FPSTR(S_method); // @token method
message += ( server->method() == HTTP_GET ) ? FPSTR(S_GET) : FPSTR(S_POST); message += (request->method() == HTTP_GET) ? FPSTR(S_GET) : FPSTR(S_POST);
message += FPSTR(S_args); // @token args message += FPSTR(S_args); // @token args
message += server->args(); message += request->params();
message += F("\n"); message += F("\n");
for ( uint8_t i = 0; i < server->args(); i++ ) { for (size_t i = 0; i < request->params(); i++) {
message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n"; const AsyncWebParameter* p = request->getParam(i);
message += " " + p->name() + ": " + p->value() + "\n";
} }
} }
server->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache AsyncWebServerResponse *response = request->beginResponse(404, FPSTR(HTTP_HEAD_CT2), message);
server->sendHeader(F("Pragma"), F("no-cache")); response->addHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); // @HTTPHEAD send cache
server->sendHeader(F("Expires"), F("-1")); response->addHeader(F("Pragma"), F("no-cache"));
server->send ( 404, FPSTR(HTTP_HEAD_CT2), message ); response->addHeader(F("Expires"), F("-1"));
request->send(response);
} }
/** /**
@@ -2468,14 +2510,14 @@ void WiFiManager::handleNotFound() {
* Redirect to captive portal if we got a request for another domain. * Redirect to captive portal if we got a request for another domain.
* Return true in that case so the page handler do not try to handle the request again. * Return true in that case so the page handler do not try to handle the request again.
*/ */
boolean WiFiManager::captivePortal() { boolean WiFiManager::captivePortal(AsyncWebServerRequest *request) {
if(!_enableCaptivePortal || !configPortalActive) return false; // skip redirections if cp not enabled or not in ap mode if(!_enableCaptivePortal || !configPortalActive) return false; // skip redirections if cp not enabled or not in ap mode
String serverLoc = toStringIp(server->client().localIP()); String serverLoc = toStringIp(request->client()->localIP());
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_DEV,"-> " + server->hostHeader()); DEBUG_WM(WM_DEBUG_DEV, "-> " + request->host());
DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc); DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc);
#endif #endif
@@ -2488,16 +2530,14 @@ boolean WiFiManager::captivePortal() {
} }
if(_httpPort != 80) serverLoc += ":" + (String)_httpPort; // add port if not default if(_httpPort != 80) serverLoc += ":" + (String)_httpPort; // add port if not default
bool doredirect = serverLoc != server->hostHeader(); // redirect if hostheader not server ip, prevent redirect loops bool doredirect = serverLoc != request->host(); // redirect if hostheader not server ip, prevent redirect loops
if (doredirect) { if (doredirect) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Request redirected to captive portal")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Request redirected to captive portal"));
DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc); DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc);
#endif #endif
server->sendHeader(F("Location"), (String)F("http://") + serverLoc, true); // @HTTPHEAD send redirect request->redirect((String)F("http://") + serverLoc);
server->send ( 302, FPSTR(HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server->client().stop(); // Stop is needed because we sent no content length
return true; return true;
} }
return false; return false;
@@ -2509,17 +2549,17 @@ void WiFiManager::stopCaptivePortal(){
} }
// HTTPD CALLBACK, handle close, stop captive portal, if not enabled undefined // HTTPD CALLBACK, handle close, stop captive portal, if not enabled undefined
void WiFiManager::handleClose(){ void WiFiManager::handleClose(AsyncWebServerRequest *request){
DEBUG_WM(WM_DEBUG_VERBOSE, F("Disabling Captive Portal")); DEBUG_WM(WM_DEBUG_VERBOSE, F("Disabling Captive Portal"));
stopCaptivePortal(); stopCaptivePortal();
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP close")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP close"));
#endif #endif
handleRequest(); handleRequest(request);
String page = getHTTPHead(FPSTR(S_titleclose), FPSTR(C_close)); // @token titleclose String page = getHTTPHead(FPSTR(S_titleclose), FPSTR(C_close)); // @token titleclose
page += FPSTR(S_closing); // @token closing page += FPSTR(S_closing); // @token closing
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
} }
void WiFiManager::reportStatus(String &page){ void WiFiManager::reportStatus(String &page){
@@ -3937,11 +3977,11 @@ void WiFiManager::WiFi_autoReconnect(){
} }
// Called when /update is requested // Called when /update is requested
void WiFiManager::handleUpdate() { void WiFiManager::handleUpdate(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update"));
#endif #endif
if (captivePortal()) return; // If captive portal redirect instead of displaying the page if (captivePortal(request)) return; // If captive portal redirect instead of displaying the page
String page = getHTTPHead(_title, FPSTR(C_update)); // @token options String page = getHTTPHead(_title, FPSTR(C_update)); // @token options
String str = FPSTR(HTTP_ROOT_MAIN); String str = FPSTR(HTTP_ROOT_MAIN);
str.replace(FPSTR(T_t), _title); str.replace(FPSTR(T_t), _title);
@@ -3951,106 +3991,87 @@ void WiFiManager::handleUpdate() {
page += FPSTR(HTTP_UPDATE); page += FPSTR(HTTP_UPDATE);
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
} }
// upload via /u POST // upload via /u POST - AsyncWebServer upload handler
void WiFiManager::handleUpdating(){ void WiFiManager::handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
// @todo static unsigned long _configPortalTimeoutSAV = 0;
// cannot upload files in captive portal, file select is not allowed, show message with link or hide static bool timeoutSaved = false;
// cannot upload if softreset after upload, maybe check for hard reset at least for dev, ERROR[11]: Invalid bootstrapping state, reset ESP8266 before updating
// add upload status to webpage somehow
// abort upload if error detected ?
// [x] supress cp timeout on upload, so it doesnt keep uploading?
// add progress handler for debugging
// combine route handlers into one callback and use argument or post checking instead of mutiple functions maybe, if POST process else server upload page?
// [x] add upload checking, do we need too check file?
// convert output to debugger if not moving to example
// if (captivePortal()) return; // If captive portal redirect instead of displaying the page if (!index) {
bool error = false; // Upload start
unsigned long _configPortalTimeoutSAV = _configPortalTimeout; // store cp timeout if (!timeoutSaved) {
_configPortalTimeout = 0; // disable timeout _configPortalTimeoutSAV = _configPortalTimeout;
timeoutSaved = true;
// handler for the file upload, get's the sketch bytes, and writes
// them through the Update object
HTTPUpload& upload = server->upload();
// UPLOAD START
if (upload.status == UPLOAD_FILE_START) {
// if(_debug) Serial.setDebugOutput(true);
uint32_t maxSketchSpace;
// Use new callback for before OTA update
if (_preotaupdatecallback != NULL) {
_preotaupdatecallback(); // @CALLBACK
} }
#ifdef ESP8266 _configPortalTimeout = 0; // Disable timeout during upload
WiFiUDP::stopAll();
maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
#elif defined(ESP32)
// Think we do not need to stop WiFIUDP because we haven't started a listener
// maxSketchSpace = (ESP.getFlashChipSize() - 0x1000) & 0xFFFFF000;
// #define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF // include update.h
maxSketchSpace = UPDATE_SIZE_UNKNOWN;
#endif
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE,"[OTA] Update file: ", upload.filename.c_str()); DEBUG_WM(WM_DEBUG_VERBOSE, F("[OTA] Update file: "), filename.c_str());
#endif #endif
// Update.onProgress(THandlerFunction_Progress fn); // Call pre-OTA callback
// Update.onProgress([](unsigned int progress, unsigned int total) { if (_preotaupdatecallback != NULL) {
// Serial.printf("Progress: %u%%\r", (progress / (total / 100))); _preotaupdatecallback();
// }); }
if (!Update.begin(maxSketchSpace)) { // start with max available size #ifdef ESP8266
WiFiUDP::stopAll();
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
#elif defined(ESP32)
uint32_t maxSketchSpace = UPDATE_SIZE_UNKNOWN;
#endif
if (!Update.begin(maxSketchSpace)) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update ERROR"), Update.getError()); DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update ERROR"), Update.getError());
#endif #endif
error = true; request->send(500, "text/plain", "Update.begin failed");
Update.end(); // Not sure the best way to abort, I think client will keep sending.. _configPortalTimeout = _configPortalTimeoutSAV;
timeoutSaved = false;
return;
} }
} }
// UPLOAD WRITE
else if (upload.status == UPLOAD_FILE_WRITE) { // Write chunk
// Serial.print("."); if (len) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { if (Update.write(data, len) != len) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update WRITE ERROR"), Update.getError()); DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update WRITE ERROR"), Update.getError());
//Update.printError(Serial); // write failure
#endif #endif
error = true; request->send(500, "text/plain", "Update.write failed");
_configPortalTimeout = _configPortalTimeoutSAV;
timeoutSaved = false;
return;
} }
} }
// UPLOAD FILE END
else if (upload.status == UPLOAD_FILE_END) { // Upload complete
if (Update.end(true)) { // true to set the size to the current progress if (final) {
if (Update.end(true)) {
#ifdef WM_DEBUG_LEVEL #ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE,F("\n\n[OTA] OTA FILE END bytes: "), upload.totalSize); DEBUG_WM(WM_DEBUG_VERBOSE, F("\n\n[OTA] OTA FILE END bytes: "), (String)index);
// Serial.printf("Updated: %u bytes\r\nRebooting...\r\n", upload.totalSize);
#endif #endif
// Response will be sent by handleUpdateDone
} else {
#ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update END ERROR"), Update.getError());
#endif
request->send(500, "text/plain", "Update.end failed");
} }
else {
// Update.printError(Serial); // Restore timeout
error = true; _configPortalTimeout = _configPortalTimeoutSAV;
timeoutSaved = false;
} }
} }
// UPLOAD ABORT
else if (upload.status == UPLOAD_FILE_ABORTED) {
Update.end();
DEBUG_WM(F("[OTA] Update was aborted"));
error = true;
}
if(error) _configPortalTimeout = _configPortalTimeoutSAV;
delay(0);
}
// upload and ota done, show status // upload and ota done, show status
void WiFiManager::handleUpdateDone() { void WiFiManager::handleUpdateDone(AsyncWebServerRequest *request) {
#ifdef WM_DEBUG_LEVEL
DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update done")); DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update done"));
// if (captivePortal()) return; // If captive portal redirect instead of displaying the page #endif
String page = getHTTPHead(FPSTR(S_options), FPSTR(C_update)); // @token options String page = getHTTPHead(FPSTR(S_options), FPSTR(C_update)); // @token options
String str = FPSTR(HTTP_ROOT_MAIN); String str = FPSTR(HTTP_ROOT_MAIN);
@@ -4065,19 +4086,24 @@ void WiFiManager::handleUpdateDone() {
#else #else
page += "OTA Error: " + (String)Update.getError(); page += "OTA Error: " + (String)Update.getError();
#endif #endif
#ifdef WM_DEBUG_LEVEL
DEBUG_WM(F("[OTA] update failed")); DEBUG_WM(F("[OTA] update failed"));
#endif
} }
else { else {
page += FPSTR(HTTP_UPDATE_SUCCESS); page += FPSTR(HTTP_UPDATE_SUCCESS);
#ifdef WM_DEBUG_LEVEL
DEBUG_WM(F("[OTA] update ok")); DEBUG_WM(F("[OTA] update ok"));
#endif
} }
page += getHTTPEnd(); page += getHTTPEnd();
HTTPSend(page); request->send(200, FPSTR(HTTP_HEAD_CT), page);
delay(1000); // send page // Schedule reboot if successful
if (!Update.hasError()) { if (!Update.hasError()) {
ESP.restart(); _rebootScheduled = true;
_rebootTime = millis() + REBOOT_DELAY_MS;
} }
} }
+4
View File
@@ -8,6 +8,8 @@ framework = arduino
monitor_speed = 115200 monitor_speed = 115200
test_framework = unity test_framework = unity
test_build_src = no test_build_src = no
lib_deps =
ESP32Async/ESPAsyncWebServer
[env:esp32] [env:esp32]
platform = espressif32 platform = espressif32
@@ -16,4 +18,6 @@ framework = arduino
monitor_speed = 115200 monitor_speed = 115200
test_framework = unity test_framework = unity
test_build_src = no test_build_src = no
lib_deps =
ESP32Async/ESPAsyncWebServer