From 4b1226bd0521182d46248a4dcbd3998c30b1c7e3 Mon Sep 17 00:00:00 2001 From: Alex Hope-O'Connor Date: Tue, 4 Nov 2025 20:06:24 +1000 Subject: [PATCH] Add WiFiManagerRequestArgs class and update saveParamsCallback to pass request arguments - Created WiFiManagerRequestArgs nested class to encapsulate HTTP request arguments - Updated setSaveParamsCallback to accept WiFiManagerRequestArgs by value - Updated handleWifiSave() and handleParamSave() to build RequestArgs early - Updated doParamSave() to accept and use RequestArgs for custom HTML params - Updated test callbacks to match new signature - All tests passing (43/43) --- lib/WiFiManager/include/WiFiManager.h | 77 ++++++++++++++++++- lib/WiFiManager/src/WiFiManager.cpp | 53 ++++++++++--- .../test_wifimanager/tests/test_callbacks.cpp | 4 +- 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/lib/WiFiManager/include/WiFiManager.h b/lib/WiFiManager/include/WiFiManager.h index 746ed89..e74c564 100644 --- a/lib/WiFiManager/include/WiFiManager.h +++ b/lib/WiFiManager/include/WiFiManager.h @@ -131,6 +131,8 @@ #include #include +#include +#include // Include wm strings vars @@ -195,6 +197,8 @@ #define WFM_NO_LABEL 0 #define WFM_LABEL_DEFAULT 1 +// WiFiManagerRequestArgs is defined as a nested class inside WiFiManager (after WM_WebServer is defined) + class WiFiManagerParameter { public: /** @@ -247,6 +251,9 @@ class WiFiManagerParameter { class WiFiManager { public: + // Forward declare nested class - defined later after WM_WebServer is available + class WiFiManagerRequestArgs; + WiFiManager(Print& consolePort); WiFiManager(); ~WiFiManager(); @@ -319,7 +326,7 @@ class WiFiManager void setPreSaveParamsCallback( std::function func ); //called when saving either params-in-wifi or params page - void setSaveParamsCallback( std::function func ); + void setSaveParamsCallback( std::function func ); //called just before doing OTA update void setPreOtaUpdateCallback( std::function func ); @@ -514,6 +521,70 @@ class WiFiManager std::unique_ptr server; + public: + // Define WiFiManagerRequestArgs here after WM_WebServer is available + class WiFiManagerRequestArgs { + public: + std::unordered_map args; + + // Constructor - builds from WM_WebServer (ESP8266WebServer or WebServer) + WiFiManagerRequestArgs(WM_WebServer* server) { + if (server) { + for (uint8_t i = 0; i < server->args(); i++) { + String argName = server->argName(i); + String argValue = server->arg(i); + args[std::string(argName.c_str())] = std::string(argValue.c_str()); + } + } + } + + WiFiManagerRequestArgs() {} + + // Check if argument exists + bool hasArg(const char* name) const { + return args.find(std::string(name)) != args.end(); + } + + bool hasArg(const String& name) const { + return hasArg(name.c_str()); + } + + // Get argument value as String + String getArg(const char* name, const String& defaultValue = "") const { + auto it = args.find(std::string(name)); + if (it != args.end()) { + return String(it->second.c_str()); + } + return defaultValue; + } + + String getArg(const String& name, const String& defaultValue = "") const { + return getArg(name.c_str(), defaultValue); + } + + // Type conversion helpers + int getArgAsInt(const char* name, int defaultValue = 0) const { + String value = getArg(name); + return value.length() > 0 ? value.toInt() : defaultValue; + } + + float getArgAsFloat(const char* name, float defaultValue = 0.0f) const { + String value = getArg(name); + return value.length() > 0 ? value.toFloat() : defaultValue; + } + + bool getArgAsBool(const char* name, bool defaultValue = false) const { + String value = getArg(name); + if (value.length() == 0) return defaultValue; + return value == "1" || value.equalsIgnoreCase("true") || + value.equalsIgnoreCase("on") || value.equalsIgnoreCase("yes"); + } + + size_t count() const { + return args.size(); + } + }; + protected: // vars std::vector _menuIds; @@ -688,7 +759,7 @@ protected: void handleWiFiStatus(); void handleRequest(); void handleParamSave(); - void doParamSave(); + void doParamSave(WiFiManagerRequestArgs requestArgs); boolean captivePortal(); boolean configPortalHasTimeout(); @@ -841,7 +912,7 @@ protected: std::function _savewificallback; std::function _presavewificallback; std::function _presaveparamscallback; - std::function _saveparamscallback; + std::function _saveparamscallback; std::function _resetcallback; std::function _preotaupdatecallback; std::function _configportaltimeoutcallback; diff --git a/lib/WiFiManager/src/WiFiManager.cpp b/lib/WiFiManager/src/WiFiManager.cpp index 21c9e38..b22d51d 100644 --- a/lib/WiFiManager/src/WiFiManager.cpp +++ b/lib/WiFiManager/src/WiFiManager.cpp @@ -1826,6 +1826,9 @@ void WiFiManager::handleWifiSave() { #endif handleRequest(); + // BUILD REQUEST ARGS STRUCT EARLY - captures all arguments while request is active + WiFiManagerRequestArgs requestArgs(server.get()); + //SAVE/connect here _ssid = server->arg(F("s")).c_str(); _pass = server->arg(F("p")).c_str(); @@ -1888,7 +1891,7 @@ void WiFiManager::handleWifiSave() { _presavewificallback(); // @CALLBACK } - if(_paramsInWifi) doParamSave(); + if(_paramsInWifi) doParamSave(requestArgs); String page; @@ -1924,7 +1927,10 @@ void WiFiManager::handleParamSave() { #endif handleRequest(); - doParamSave(); + // BUILD REQUEST ARGS STRUCT + WiFiManagerRequestArgs requestArgs(server.get()); + + doParamSave(requestArgs); String page = getHTTPHead(FPSTR(S_titleparamsaved), FPSTR(C_param)); // @token titleparamsaved page += FPSTR(HTTP_PARAMSAVED); @@ -1938,7 +1944,7 @@ void WiFiManager::handleParamSave() { #endif } -void WiFiManager::doParamSave(){ +void WiFiManager::doParamSave(WiFiManagerRequestArgs requestArgs){ // @todo use new callback for before paramsaves, is this really needed? if ( _presaveparamscallback != NULL) { _presaveparamscallback(); // @CALLBACK @@ -1958,13 +1964,38 @@ void WiFiManager::doParamSave(){ #endif break; // @todo might not be needed anymore } - //read parameter from server - String name = (String)FPSTR(S_parampre)+(String)i; + String value; - if(server->hasArg(name)) { - value = server->arg(name); + + // Check if this is a custom HTML parameter (ID is null) + if (_params[i]->getID() == nullptr) { + // For custom HTML parameters, try to get from RequestArgs + String name = (String)FPSTR(S_parampre)+(String)i; + + // Try RequestArgs first + if (requestArgs.hasArg(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 { + continue; // Skip if not found + } + } } else { - value = server->arg(_params[i]->getID()); + // Regular parameter - use existing logic + String name = (String)FPSTR(S_parampre)+(String)i; + if(server->hasArg(name)) { + value = server->arg(name); + } 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()); + } } //store it in params array @@ -1979,7 +2010,7 @@ void WiFiManager::doParamSave(){ } if ( _saveparamscallback != NULL) { - _saveparamscallback(); // @CALLBACK + _saveparamscallback(requestArgs); // @CALLBACK - PASS RequestArgs } } @@ -2869,9 +2900,9 @@ void WiFiManager::setConfigResetCallback( std::function func ) { /** * setSaveParamsCallback, set a save params callback on params save in wifi or params pages * @access public - * @param {[type]} void (*func)(void) + * @param {[type]} void (*func)(WiFiManagerRequestArgs) */ -void WiFiManager::setSaveParamsCallback( std::function func ) { +void WiFiManager::setSaveParamsCallback( std::function func ) { _saveparamscallback = func; } diff --git a/test/test_wifimanager/tests/test_callbacks.cpp b/test/test_wifimanager/tests/test_callbacks.cpp index 47027cf..ead8449 100644 --- a/test/test_wifimanager/tests/test_callbacks.cpp +++ b/test/test_wifimanager/tests/test_callbacks.cpp @@ -29,8 +29,10 @@ void pre_save_config_callback() { pre_save_config_callback_fired = true; } -void save_params_callback() { +void save_params_callback(WiFiManager::WiFiManagerRequestArgs requestArgs) { save_params_callback_fired = true; + // Test that we can access request args + (void)requestArgs; // Suppress unused variable warning } void pre_save_params_callback() {